MuninMunin
Sign inStart free
Home/Journal/Munin in Cursor.
Engineering · 5 min read

Munin in Cursor.

The support thread that reported the bug and the file that contains it have never been in the same window. One `mcp.json` entry and they are — with Cursor's tool approval sitting exactly where Munin's already does.

Looking across a quiet shop counter through an open doorway into the lit workshop behind it — the place customers reach you and the place things get made, in one frame.
The counter and the workshop, in one frame.

Every engineer has done this dance. A bug report arrives in the support tool. You read it there, translate it into your own words, go to the editor, fix it, then go back and translate the fix into something a customer can read. Two systems, two vocabularies, and a human in the middle whose job is retyping. The fix takes ten minutes. The round trip takes an hour.

What does Munin in Cursor actually give you?

Your customer platform as tools inside the editor. Munin serves 204 MCP tools at one endpoint, so Cursor's agent can read the support thread that reported a bug, look up who reported it, search your knowledge base for the existing answer, and write the reply — in the same window where it's reading the stack trace.

The useful part isn't convenience. It's that the agent has the customer's exact words and your source tree in one context at the same time.

How do you add Munin to Cursor?

One entry in mcp.json. Cursor reads .cursor/mcp.json in a project for project-scoped servers, or ~/.cursor/mcp.json in your home directory for servers you want everywhere. Mint an admin key in Settings → API keys first; it's shown once.

json~/.cursor/mcp.json
{
  "mcpServers": {
    "munin": {
      "url": "https://mcp.getmunin.com",
      "headers": {
        "Authorization": "Bearer ${env:MUNIN_API_KEY}"
      }
    }
  }
}

That ${env:MUNIN_API_KEY} is not decoration. Cursor resolves variables in command, args, env, url, and headers, so you can keep the credential in your shell profile instead of committing it. Do that — .cursor/mcp.json is a file in your repository, and a pasted admin key is a pasted admin key.

Self-hosting instead? Point it at http://localhost:3001/mcp. Munin also supports scoped OAuth, and Cursor supports OAuth for servers that require it, which is the better choice for anything a human is driving.

When it doesn't connect, the logs are in the Output panel (Cmd+Shift+U) under MCP Logs — they show initialisation, tool calls, and auth failures. And you can toggle the server off without deleting it under Settings → Features → Model Context Protocol, which is worth knowing when 204 tools is more than you want in a session.

What does the loop look like in practice?

One search, one lookup, one fix, one reply — all inside the editor. The agent finds the support conversation by the words the customer actually used, resolves who reported it and who else hit the same thing, fixes the code with the complaint and the source tree in one context, then answers in the customer's own thread and files the explanation as a knowledge-base draft.

Four steps that used to be four tabs:

  • 01Read the report in the editor. conv_search_messages finds the thread by the phrase the customer used — not the phrase you'd have used. That difference is usually where the bug is hiding.
  • 02Find out who's affected. crm_lookup_contact resolves the reporter, conv_list_conversations finds everyone else who described the same behaviour. Two people is a bug report; eleven is a priority.
  • 03Fix it with the context intact. The agent has the customer's wording, the affected accounts, and your source tree in one context. No translation step.
  • 04Close the loop. conv_send_message replies in the customer's own thread, and kb_propose_curation_candidate files the explanation as a knowledge-base draft so the next person who asks gets an answer instead of a ticket.

Does this actually find bugs, or just move tickets around?

It finds them, because the signal is in the phrasing and the phrasing is in the threads. Munin ships a bug-triage recipe that clusters conversations by broken-behaviour language, separates real defects from confusion, and files internal notes on representative threads — the useful output being the distinction between "this is broken" and "this is confusing," which are different tickets for different teams.

Run it before you plan a sprint rather than during one. The recipes are markdown you can read and edit, and you should read this one before trusting its judgment about what counts as a defect. What makes that reading cheap is that the recipe is a file rather than a vendor's black box: change the clustering rule, tighten the stopping condition, save it, run it again on the same week of threads. Triage logic buried in somebody's dashboard is not something you can open, edit, or argue with.

What stops the agent replying to a customer by accident?

Two layers, and they line up neatly. Cursor asks for approval before using MCP tools by default, and shows you the arguments before it runs — so a conv_send_message call is something you see and confirm, not something you discover afterwards.

Underneath that, Munin's own asymmetry applies regardless of client. Cheap reversible actions like tagging or titling a thread write directly; irreversible ones — publishing a knowledge article, merging two contacts — can only be proposed into a review queue. The destructive verb isn't in the agent's hands to begin with, which is the part that survives someone turning off confirmations.

If you do pre-approve tools for auto-run, put the read-only ones in permissions.json and leave the writes asking. The judgment is the product; the clicking never was.

A support thread is untrusted input

Anything a customer types can end up in the agent's context, which makes a ticket a plausible prompt-injection vector. Treat it that way.

The mitigation is scope, not vigilance: use a credential limited to the modules the task needs, keep write tools behind approval, and remember that Munin's admin key is full access to the org. Don't put one in a repo file.

Who is this setup wrong for?

Teams where support and engineering are different people with different tooling. The value here is specifically for developers who also answer customers — small teams, dev-tool companies, anyone where the person reading the ticket can also fix the code. A dedicated support manager wants a queue with SLA timers and CSAT scores, and Zendesk and Intercom have spent well over a decade building exactly that; if that's the desk you're staffing, buy one of them. The open-source helpdesk comparison covers where the self-hosted options sit on the same question.

It also isn't a substitute for reading things yourself. An agent summarising eleven threads will smooth over the one oddly-worded report that explains the whole bug — which is exactly why the triage recipe files internal notes on representative threads rather than handing you a summary, and why conv_search_messages returns the customer's own sentence instead of a paraphrase of it.

For the team this does fit, the arithmetic is unusual. The support thread, the contact who opened it, the knowledge article that should have answered it, and the source file that caused it are one Postgres schema and one tool catalogue away from each other — so the round trip that used to cost an hour costs about as long as the fix. That is the distance this collapses, and it is the right one to collapse when the person holding both ends is the same person.

Frequently asked questions

How do I add a remote MCP server to Cursor? Add it to .cursor/mcp.json for one project or ~/.cursor/mcp.json globally, with a url and a headers object for authentication. Cursor resolves ${env:NAME} inside both fields, so keep tokens in your environment rather than in the file.

Where are Cursor's MCP logs? Open the Output panel with Cmd+Shift+U and select MCP Logs from the dropdown. It shows server initialisation, tool calls, and authentication errors — which is where most "it won't connect" problems resolve.

Will the agent send messages to real customers? Only with approval. Cursor prompts before MCP tool calls by default and shows the arguments first. Separately, Munin only lets agents propose irreversible actions like publishing knowledge articles or merging contacts — those land in a review queue regardless of which client is connected.

Can I limit which Munin tools Cursor sees? Yes. Scope the API key to the modules you need, since Munin gates tool visibility by audience at the tool layer. You can also disable the whole server temporarily under Settings → Features → Model Context Protocol.

Does this work with Claude Code or ChatGPT too? Yes. Munin serves standard MCP with no client-specific behaviour, so Claude Code, Claude Desktop, ChatGPT, Codex, Gemini, and custom runners all connect to the same endpoint. There's a separate walkthrough for Claude Code, and one for running it from ChatGPT without a terminal.

Do I need Munin Cloud? No. Self-hosting is docker compose up and serves MCP at /mcp on your backend port, free forever under MIT. Cloud is EU-hosted with a free tier and the same tool surface.

The short version

  • One mcp.json entry with url and headers puts 204 Munin tools in Cursor. Use ${env:MUNIN_API_KEY} — that file lives in your repo.
  • .cursor/mcp.json for one project, ~/.cursor/mcp.json for everywhere. Logs under Output panel → MCP Logs.
  • The loop: find the thread by the customer's phrasing, see who else hit it, fix it with both contexts in one window, reply and file the answer as a KB draft.
  • Cursor asks approval before tool calls; Munin only lets agents propose publishes and merges. Two layers that agree with each other.
  • This is built for developers who also answer customers — small teams and dev-tool companies, where the person reading the ticket is the person who can fix it.

Add the server, then ask Cursor which conversations from the last week describe something being broken. The MCP tool reference lists all 204, and Munin Cloud is free to start on.

The bug report and the bug were always the same object. Only your tooling disagreed.