Cursor MCP JSON: Configure mcp.json the Right Way

Cursor MCP JSON is the config file that tells Cursor's Agent which Model Context Protocol servers to load, and it lives at ~/.cursor/mcp.json for global servers or .cursor/mcp.json in a repo for project-scoped ones. You add a server block, restart Cursor, and confirm the tools show up green under Settings, MCP, and the Agent can call them without you pasting anything.
Most guides paste one JSON snippet and move on, which leaves you stranded the first time it prints "0 tools enabled." The config is small, but the failure modes are specific, and knowing them is the difference between a working local server and an afternoon of guessing.
What does the cursor mcp json file actually contain?
Two shapes cover almost everything. A stdio server is a local binary Cursor launches and talks to over standard input and output, and an SSE or HTTP server is a URL Cursor connects to that must already be running.
A stdio block is the common case for anything that touches your machine:
{
"mcpServers": {
"pinvari": {
"command": "pinvari-mcp",
"args": [],
"env": {}
}
}
}
The keys are exactly three: command is the executable, args is the argument array, and env is an optional map of environment variables. Cursor runs command as-is on your PATH, so if the binary is not on PATH you give the absolute path instead.
An SSE or HTTP block swaps the launch keys for connection keys:
{
"mcpServers": {
"remote-tool": {
"url": "http://127.0.0.1:8787/sse",
"headers": { "Authorization": "Bearer ${TOKEN}" }
}
}
}
Here url points at a server you started separately, and headers carries auth. That is the entire cursor mcp json schema for day-to-day use.
One detail that trips people up: the mcpServers object is keyed by a name you choose, and that name is what shows up in Cursor's MCP panel. Keep it short and lowercase, because you will type it when you scope which servers are on for a given chat.
Keep secrets out of the file. Use ${TOKEN} style references that read from your shell environment rather than pasting API keys inline, because mcp.json often ends up committed to a dotfiles repo.
Where does mcp.json live, global vs project?
Cursor reads two locations, and the precedence matters. The global file at ~/.cursor/mcp.json applies everywhere, and the project file at .cursor/mcp.json in your repository root applies only to that project and wins where both define the same server.
Use the split deliberately. Put servers every project needs, like a filesystem or a screen-context tool, in the global file, and keep repo-specific servers, like a database that only one app uses, in the project file.
Global ~/.cursor/mcp.json | Project .cursor/mcp.json | |
|---|---|---|
| Scope | Every workspace | One repository |
| Precedence | Loses to project on conflict | Wins for that repo |
| Best for | Shared, always-on tools | Repo-specific servers |
| Commit to git | No, it is per-user | Optional, without secrets |
| Startup | Loaded on Cursor launch | Loaded when the repo opens |
The one rule that saves headaches: after you edit either file, fully quit and reopen Cursor. A window reload does not always re-read the config.
Why does Cursor MCP JSON show 0 tools enabled?
Because the server is not reachable, not because Cursor is broken. This is the single most common "cursor mcp not working" report, and it has four usual causes.
- Bad JSON. A trailing comma or a mistyped key means Cursor cannot parse the block. Validate the file, then restart fully.
- Binary not on PATH. For a stdio server, Cursor runs
commandverbatim. If it is not on your shell PATH, use the absolute path. - The server crashed on launch. Check the server's own logs. A local capture server needs macOS permissions such as Accessibility and Screen Recording, and without them it can start and immediately fail.
- Transport mismatch. An SSE server must already be listening at
urlbefore Cursor connects. If nothing is there, you get zero tools.
"0 tools enabled" almost never means the model is at fault. Confirm the process is alive, the path is right, the JSON parses, and macOS granted the permissions the server needs, in that order.
For a walkthrough that covers the same wiring from the Cursor side with screenshots of the panel, our Cursor MCP setup guide is the companion to this one.
What does a local MCP server actually give the Agent?
Structured input it can act on, instead of prose you paste or a screenshot it has to decode. That is the whole reason to run one on 127.0.0.1 rather than lean on chat alone.
Here is a concrete Mac example. Say a button in your running app sits four pixels too low and you want Cursor to fix it.
The slow way is to screenshot the app, drag the image into chat, and type a paragraph describing which button, which routinely costs tokens while pointing the Agent at the wrong element.
The MCP way with a point-and-speak server: you hold ⌥⌘A, circle the button, and say "this button is four pixels too low." PinVari screenshots the region, transcribes on-device, and resolves the exact named accessibility element you circled, with its role, label, frame, and a confidence score, then queues it as an instruction.
Cursor's Agent calls pinvari_next_instruction, which returns the resolved element path, your spoken instruction, the region you circled, and a screenshot cropped to that region. It now knows which control you mean by name, not by guessing, and it calls pinvari_mark_done when it finishes.
The resolution is what makes the tool call worth adding to your config in the first place. macOS builds the accessibility tree lazily for Chromium and Electron surfaces, so PinVari sets AXManualAccessibility and retries for about 150 milliseconds until a labeled element appears, and when a point lands on a bare AXGroup it descends to the deepest labeled child.
That is the plumbing behind a clean element name, and it is the reason the Agent gets a specification instead of coordinates.
Register once, use everywhere. Because MCP is a shared standard, the same server block works for Claude Code, Codex, and Zed, so you are not maintaining four different configs for four agents.
How does the named element beat a screenshot?
macOS exposes the UI element under any point through AXUIElementCopyElementAtPosition, which returns the role, title, value, and frame plus the parent chain. A server that reads that structure hands Cursor a name, while a server that only screenshots hands it a picture to squint at.
The gap in accuracy is the entire reason agents know which UI element you mean instead of editing a lookalike. If accessibility is new to you, the primer on what the macOS Accessibility API is used for explains why it can name any on-screen control, not just help screen readers.
There is a subtlety worth calling out. The capture overlay is topmost, so a naive hit-test resolves to the overlay's own window rather than your app.
The server walks the on-screen window list excluding itself and hit-tests the real app underneath, which is the kind of correctness work that separates a tool returning a true element name from one returning garbage. None of it shows up in your mcp.json, but all of it is why the returned name is trustworthy.
PinVari runs entirely on-device with no API keys in the tool and nothing uploaded by default, and it ships as a notarized DMG for macOS 14 and up because the Mac App Store sandbox forbids the global hotkey and reading other apps' accessibility elements. It is a one-time $39 launch license through Polar rather than a subscription, and the pricing page has the full breakdown.
If you want the deeper argument for a local, structured server over a screenshot pipe, the write-up on a local MCP server for agent screen context shows the exact payload difference.
FAQ
#
Where is the Cursor MCP JSON file on a Mac?
Cursor reads a global config at ~/.cursor/mcp.json and an optional project config at .cursor/mcp.json in your repository root. The project file overrides the global one for that repo, which is handy for servers only one project needs.
#
What is the cursor mcp json schema?
For a stdio server the keys are command, args, and an optional env. For an SSE or HTTP server the keys are url and an optional headers.
Everything nests under a top-level mcpServers object keyed by the server name.
#
Why does my Cursor MCP server show no tools?
The server is not reachable. Check for JSON syntax errors, confirm the command binary is on your PATH or given as an absolute path, verify the process is running, grant any macOS permissions it needs, then fully restart Cursor.
#
Do local MCP servers send my data to the cloud?
A stdio server on 127.0.0.1 runs entirely on your Mac and does not upload anything on its own. Whatever your model call sends is separate and under your control, and on-device tools keep transcription and OCR local by default.
#
Can Cursor and Claude Code share the same MCP server?
Yes. MCP is a shared standard, so one server works with any MCP client.
You register it once, then reference it from each client's config, which is why a single install can serve Cursor, Claude Code, Codex, and Zed.
#
Do I edit mcp.json by hand or use a command?
Either works. You can write the JSON directly, or use an installer that writes the entry for you, such as claude mcp add --scope user pinvari -- "$HOME/.pinvari/mcp/pinvari-mcp", then reference the server from Cursor's mcp.json if it is not picked up automatically.
Hand your agent the exact element
PinVari resolves what you point at into a named, executable instruction — on-device, no keys, your own agent. One click inside PinVari connects Claude Code, Cursor, VS Code or Codex — or paste one CLI line from pinvari.com/connect.
PinVari → Connect → your agent (one click)Get PinVari — $39 →


