npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@mgsoftwarebv/mcp-server-bridge

v3.5.36

Published

MCP Server bridge for MG Tickets - connects Cursor to HTTP MCP server with image support and GitHub code exploration

Readme

@mgsoftwarebv/mcp-server-bridge

An MCP server that connects Cursor / Claude Desktop / Windsurf directly to your Refront Postgres database, exposing tickets, customers, projects, documents and time tracking as MCP tools and resources.

Since v3.0 the bridge talks straight to Postgres via Drizzle ORM — the previous PostgREST/JWT transport has been removed.

📦 Installation

npm install -g @mgsoftwarebv/mcp-server-bridge

🔧 Cursor Configuration

Add the following to your ~/.cursor/mcp.json. You always need two things:

  1. An API key from your Refront dashboard (/settings/developer, format mid_...).
  2. A Postgres connection string for your Refront database (DATABASE_URL).
{
  "mcpServers": {
    "refront": {
      "command": "npx",
      "args": [
        "-y",
        "@mgsoftwarebv/mcp-server-bridge@latest",
        "--api-key=mid_your_api_key_here",
        "--database-url=postgresql://USER:PASSWORD@HOST:PORT/DBNAME"
      ]
    }
  }
}

Both values can also be supplied via environment variables instead of CLI flags:

{
  "mcpServers": {
    "refront": {
      "command": "npx",
      "args": ["-y", "@mgsoftwarebv/mcp-server-bridge@latest"],
      "env": {
        "MG_TICKETS_API_KEY": "mid_your_api_key_here",
        "DATABASE_PRIMARY_POOLER_URL": "postgresql://USER:PASSWORD@HOST:PORT/DBNAME"
      }
    }
  }
}

🔑 Getting an API Key

  1. Go to your Refront dashboard: /settings/developer
  2. Create a new API key
  3. Copy the key (format: mid_...)
  4. Use it in your MCP configuration

🗄️ Getting the Database URL

  • Refront SaaS customers: ask MG Software for a read-only Postgres user that points at your team's database (we do not hardcode a default connection string here for security reasons).
  • Self-hosted: use the same DATABASE_PRIMARY_POOLER_URL you configured for the API/dashboard.

The bridge uses @refront/db/job-client, which is tuned for a single connection per process and gracefully closes idle connections.

📋 Command-Line Options

# Basic usage
mg-tickets-mcp --api-key=mid_your_key --database-url=postgresql://...

# Via environment variables
export MG_TICKETS_API_KEY=mid_your_key
export DATABASE_PRIMARY_POOLER_URL=postgresql://USER:PASSWORD@HOST:PORT/DBNAME
mg-tickets-mcp

--database-url falls back to DATABASE_PRIMARY_POOLER_URL, then to DATABASE_URL. The bridge exits at startup if no connection string is provided.

For attachment downloads you also need to expose Cloudflare R2 credentials (R2_ENDPOINT, R2_ACCESS_KEY_ID, R2_SECRET_ACCESS_KEY, optional R2_PUBLIC_DOMAIN). Without them the attachment / image inlining tools will return an error, but everything else keeps working.

🏢 Multi-provider support

A single API key now works even if you belong to multiple providers (workspaces). The key is bound to one provider as its default, but every team-scoped tool accepts an optional teamId argument that is validated against your team memberships.

How it resolves which provider a tool acts on:

  • teamId provided → it is validated against your memberships and used.
  • teamId omitted, you belong to one provider → that provider is used automatically (no change for single-provider users).
  • teamId omitted, you belong to several → list/create tools return the list of your providers and ask the AI to re-call with a teamId. By-id tools resolve across all your providers (the record id disambiguates), and accept teamId to narrow.

Use get-teams to list the providers you can act on and copy a teamId.

🛠️ Available Tools

Related mutations are consolidated into a single action-based tool (pick the operation with an action argument), while reads and destructive deletes stay their own explicit tools. Full parameter docs live in each tool's MCP schema (src/tools/definitions/).

Teams

  • get-teams — list the provider teams (workspaces) you can act on; use a returned id as teamId on other tools

Tickets, Customers & Projects

  • get-tickets — list tickets with filters (status, priority, project, customer, text query); each result includes the ticket ID (UUID) and ticket number
  • get-ticket-by-id — fetch one ticket by UUID or ticket number, with all comment text, a full attachment listing (ids), and inline images (base64)
  • create-ticket — create a new ticket (returns UUID and ticket number)
  • update-ticket — update fields (title, description, status, priority, type, project, customer, assignee, estimated hours, deadline, tags); accepts UUID or ticket number; assigneeId: null unassigns
  • add-ticket-comment — add a comment (plain text or TipTap JSON); accepts UUID or ticket number; isInternal for internal-only notes
  • get-ticket-attachment / upload-ticket-attachment / delete-ticket-attachment — signed download URLs, uploads, and removals
  • get-customers — list/search customers
  • customer (action: create|update|archive) — create, edit, or archive a customer; delete-customer hard-deletes an empty one
  • get-customer-agreements + customer-agreement (action: create|update) — per-customer product agreements (draft-only writes)
  • get-projects — list/search projects
  • project (action: create|update|archive) — create, edit, or archive a project; delete-project hard-deletes an empty one
  • project-members (action: list|set|add|remove) and project-tags (action: list|set|add|remove)
  • get-tags + tag (action: create|update|merge) + delete-tag
  • get-calendar-items + calendar-item (action: create|update)

Note: Ticket writes (update-ticket, add-ticket-comment) are recorded in the dashboard's ticket activity feed but do not send notifications (email/Slack/in-app) or trigger @mention routing. Notification delivery is a planned follow-up.

Quote / Proposal Documents

  • list-documents — list documents with filters (type, status, customer, title search)
  • get-document — fetch one document with metadata and the full blocks JSON; pass linkType (dashboard/pdf_signed/public_share) to get only a shareable link
  • document (action: create|update) — create from content blocks (cover, toc, heading, text, callout, table, chart incl. multi-series, pricing, timeline, two_column, divider, signature) or update (replace/append/targeted blockOps); supports a teamId provider override and links to a customerId/invoiceId
  • delete-document — soft-delete a document

Invoicing, Products & Quotes

  • get-invoices — list invoices, or pass invoiceId for full detail (and linkType for a shareable/PDF/payment link)
  • update-invoice — edit a draft invoice: lineItems (replace all), patchLines (targeted), addProduct (add a catalog product), or linkDocumentId (attach a document)
  • send-invoice-to-customer — email an invoice via the dashboard send pipeline
  • get-products — list catalog products, or pass productId for one; product (action: create|update|archive)
  • get-quotes + quote (action: create|update|add-product) — draft-only quote/offerte writes

Trips (kilometer registration)

  • get-trips + trip (action: create|update) + get-trip-context (include: vehicles|templates|frequent)

Document text runs through a built-in humanizer that strips AI-sounding patterns (em-dashes, NL/EN clichés like "naadloos"/"seamless", filler phrases). Control it per call with humanize:

  • "rules" (default) — deterministic cleanup, no API key needed; the tool result includes a change report
  • "full" — rules + an LLM rewrite pass (requires OPENAI_API_KEY in the bridge env)
  • "off" — store the blocks exactly as provided

Optional PDF compilation: pass compilePdf: true to trigger the compile-document-pdf Trigger.dev job after create/update. This requires TRIGGER_SECRET_KEY (and optionally TRIGGER_API_URL) in the bridge env; without it the dashboard compiles the PDF when the document is opened or shared.

Time Tracking

  • log-hours — log work hours as a draft agenda event (see the /hours Cursor command)
  • create-time-entries — create one or more individual dated hour lines (one timesheet event per date), single or bulk via entries[]. Top-level projectId/ticketId/userId/description/billable/status are shared defaults each entry can override. Skips duplicates (same user/team/date/project/description) unless allowDuplicate, and reports created/skipped/errored lines plus totalHours. Use this instead of log-hours when you have separate dated lines (e.g. "8h on 19/6, 8h on 16/6").
  • get-time-entries — read and total tracked time entries (urenregistratie), filterable by period, user, project, customer, ticket, status and type; returns accurate aggregate totals (total/billable/non-billable/invoiced hours) plus an optional grouped breakdown (day/project/customer/user/ticket). Answers questions like "how many hours did I work this month for customer X?"
  • delete-time-entries — soft-delete one or more existing hour lines by id/ids[] (e.g. to drop a wrongly-logged lump entry before re-creating dated lines). Only draft, non-invoiced entries are removed unless allowInvoicedOverride; confirmed/invoiced ones are skipped. Reports deleted/skipped/errored ids plus deletedHours.
  • update-time-entry — correct a single hour line by id: change date/hours (re-times the line), description, projectId, ticketId, status or billable. On confirmed/invoiced entries the financial/time fields are locked unless allowInvoicedOverride; description and project/ticket links stay editable.

GitHub Code Exploration

  • github (action: read-file|list-dir) — read one file, or list a directory, in the GitHub repo linked to a project

Activity, Telemetry & Cycle-time Reports

  • get-activity-report (report: user|mcp|ui|ticket-timeline|ticket-analytics) — daily per-user execution timeline, Refront MCP/UI telemetry, and per-ticket / cross-ticket cycle-time metrics; actor-based and timezone-aware

⏱️ Quick Hour Logging with /hours

The /hours Cursor command makes logging time effortless:

  1. Do your work in Cursor — chat and code normally.
  2. Type /hours when you're done.
  3. The AI analyzes the chat and estimates how long a senior developer (without AI) would have spent.
  4. Workspace ↔ project matching is automatic where possible.
  5. A draft entry is created in the tracker (not billed yet).

How it works

  1. Lists all projects via get-projects.
  2. Matches the workspace folder name to the closest project (or skips matching when ambiguous).
  3. Analyzes the chat — what was built/fixed.
  4. Estimates a realistic time budget (investigation + implementation + testing).
  5. Creates a tracker entry as draft.

📚 Available Resources

  • tickets://recent — most recent tickets across all accessible teams
  • customers://all — all accessible customers
  • projects://active — all accessible projects

🔍 Debugging

The bridge logs to stderr so you can capture debug output without breaking the MCP stdio protocol:

mg-tickets-mcp --api-key=mid_... --database-url=postgresql://... 2>debug.log

Debug output shows:

  • Database connection / startup status
  • API key validation hash
  • Tool dispatch and access decisions
  • Errors with stack traces

🏗️ Development

git clone https://github.com/mgsoftwarebv/tickets-v2.git
cd tickets-v2/packages/mcp-server-bridge

bun install
bun run build

node dist/index.js --api-key=mid_... --database-url=postgresql://...

🔄 Updates

npm update -g @mgsoftwarebv/mcp-server-bridge
# Or via npx (no install required)
npx @mgsoftwarebv/mcp-server-bridge@latest --api-key=mid_...

🆘 Troubleshooting

❌ "API key is required"

  • Pass --api-key= or set MG_TICKETS_API_KEY.
  • Make sure the key has the format mid_... (length 68).

❌ "Database URL is required"

  • Pass --database-url=postgresql://... or set DATABASE_PRIMARY_POOLER_URL / DATABASE_URL.
  • Confirm the user can reach the database from your machine (firewall, VPN, etc).

❌ "API key not found or invalid"

  • Generate a new API key in /settings/developer and check it is enabled.
  • Confirm the key belongs to a team that exists in the database you're connecting to.

❌ "R2 storage is not configured"

  • Image / attachment tools need R2_ENDPOINT, R2_ACCESS_KEY_ID, R2_SECRET_ACCESS_KEY. Set them in the env block of your mcp.json if you need attachment support.

📄 License

MIT © MG Software B.V.