TL;DR: Claude Desktop MCP setup is one JSON file. It lives at ~/Library/Application Support/Claude/claude_desktop_config.json on macOS and %APPDATA%\Claude\claude_desktop_config.json on Windows. Servers go under a top-level mcpServers key, paths must be absolute, and you must fully quit and reopen the app before anything loads.
Most guides describe a version of the app that no longer looks that way, and they skip the same three things: what happens when the JSON is invalid, why a server that runs in your terminal refuses to start inside the app, and what you agree to when you add someone else's server.
This is verified against the Model Context Protocol documentation at revision 2026-07-28 and Anthropic's own help centre, both read on 28 August 2026. Every path, key name and menu label below came off one of those pages, not from memory. MCP moves fast enough that you should check the current spec rather than trust any dated blog post, this one included.
Where does Claude Desktop keep its MCP config file?
In one file, in your user application-support directory. The path differs by platform.
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Windows:
%APPDATA%\Claude\claude_desktop_config.json
Both are published in the MCP quickstart for connecting to local servers. You need not navigate there by hand: click the Claude menu in your system menu bar (the docs are specific that this is the OS menu bar, not the settings inside the Claude window), choose Settings, open the Developer tab, and click Edit Config. That opens the file, creating it if it does not exist.
What does the MCP config JSON actually look like?
The top-level key is mcpServers. Not servers, not mcp, not mcpServer. The filesystem quickstart, the build-a-server tutorial and the debugging guide all use that exact spelling.
Each entry inside it is a nickname you choose, whose object carries command (the executable to run), args (an array of arguments), and optionally env (environment variables to inject).
Here is a complete, working macOS config using the official filesystem server:
{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-filesystem",
"/Users/username/Desktop",
"/Users/username/Downloads"
]
}
}
}
And the Windows equivalent. Note the doubled backslashes: JSON treats a single backslash as an escape character, so a Windows path written normally will either fail to parse or silently mangle itself.
{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-filesystem",
"C:\\Users\\username\\Desktop",
"C:\\Users\\username\\Downloads"
]
}
}
}
Replace username with your account name. The trailing arguments are the directories that server may touch: a permission boundary, not decoration.
Two servers means a second entry in the same file:
{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/Users/username/Projects"]
},
"weather": {
"command": "/Users/username/.local/bin/uv",
"args": ["--directory", "/Users/username/code/weather", "run", "weather.py"],
"env": {
"WEATHER_API_KEY": "replace-me"
}
}
}
}
Two details there are doing real work, both covered below: command is an absolute path to the interpreter rather than a bare name, and the API key arrives through env rather than your shell.
Should a beginner use stdio or a remote server?
Use a remote server if one exists for the tool you want. Use stdio when the server needs your local machine.
stdio is the local transport. Claude Desktop launches your server as a subprocess and the two talk over its standard streams. The spec is blunt about the implication: the server "MUST NOT write anything to its stdout that is not a valid MCP message." Debug output has to go to stderr instead, which is why a stray print() in a Python server can take the whole connection down. This is what claude_desktop_config.json configures.
Streamable HTTP is the remote transport: each message is an HTTP POST to a single endpoint, and replies arrive as a JSON object or a request-scoped SSE stream. Remote servers are not added through the config file at all. They go in through Settings, Connectors, Add custom connector, where you paste a URL and complete an OAuth sign-in. The MCP walkthrough uses https://example-server.modelcontextprotocol.io/mcp; ours is https://mcp.prompt-architects.com/mcp, exposing four prompt operations named improve, refine, shorten and enhance (setup details here). Every remote server is added the same way.
That split is the biggest source of confusion here: two guides can both be correct and describe completely different screens. If a server's README gives you a URL, stop looking for the JSON file.
| You have | Where it goes | What you need installed |
|---|---|---|
An npx or uvx command | claude_desktop_config.json | Node.js or Python, plus a full app restart |
| A path to a script you wrote | claude_desktop_config.json | That language runtime, plus a full app restart |
An https:// endpoint | Settings, Connectors, Add custom connector | Nothing local; usually a browser sign-in |
Do you have to restart Claude Desktop, or is there a reload?
You have to restart, and closing the window does not count.
The build-a-server tutorial states it directly: "Simply closing the window does not fully quit the application, and your MCP server configuration changes will not take effect." On macOS that means Cmd+Q or Quit Claude from the menu bar. On Windows it means right-clicking the Claude tray icon, which the docs note may be hidden inside the overflow menu, and choosing Quit or Exit.
The debugging guide draws the same line for code: configuration changes need a client restart, and server code changes need one too: "for Claude Desktop, fully quit and reopen; closing the window is not enough".
Remote connectors are the exception: the documented walkthrough never asks you to restart, and neither does toggling individual tools. That is an absence of instruction rather than a promise, but it matches the architecture, since stdio servers are subprocesses spawned once at launch.
How do you tell whether it actually worked?
Open a conversation, click the plus icon in the message input, and hover over Connectors.
The debugging guide describes exactly this: click the "Add files, connectors, and more" plus icon in the chat input, then hover over the Connectors menu "to see connected servers and available tools." Your server appears under the nickname you gave it in the JSON, and selecting it lists its tools.
Anthropic's help centre adds a more diagnostic route: its developer FAQ points to the Developer settings section, which shows connection status per server and links to the logs. If a server is missing from the Connectors menu, look there next.
Where are the logs when it does not work?
Two files, in a directory the app never mentions in its UI.
- macOS:
~/Library/Logs/Claude - Windows:
%APPDATA%\Claude\logs
mcp.log carries general logging about MCP connections and connection failures. Files named mcp-server-SERVERNAME.log carry that server's stderr. One caveat: "Stdio servers may use stderr for all their logging, so these files are not limited to errors." A wall of text is not proof of a problem.
To watch them live on macOS:
tail -n 20 -F ~/Library/Logs/Claude/mcp*.log
On Windows, PowerShell:
type "$env:AppData\Claude\logs\mcp*.log"
Start the tail, then quit and reopen Claude Desktop. Everything interesting happens in the first two seconds of launch; attach later and you miss it.
If the logs are not enough, the documented next step is the MCP Inspector, a transport-agnostic testing UI that connects to your server directly. It removes Claude Desktop from the equation, which is the fastest way to learn whether you are debugging the server or the config.
Why does nothing load at all after you edit the config?
Because the file is one JSON document, and a single syntax error means there is no server list to read.
This wastes the most time, because it presents as my new server did not appear when in fact every server stopped appearing. A trailing comma, a smart quote pasted from a web page, or one unescaped Windows backslash is enough. The debugging guide names invalid JSON syntax first among configuration errors.
Validate before you restart:
python3 -m json.tool ~/Library/Application\ Support/Claude/claude_desktop_config.json
Get-Content "$env:AppData\Claude\claude_desktop_config.json" | ConvertFrom-Json
Either prints the parsed document on success and names the offending position on failure. Thirty seconds here beats twenty minutes of log-reading for a server that was never registered. Still stuck? Why isn't my MCP server showing up works the same symptom from the other direction.
Why does the server run in your terminal but not in Claude Desktop?
Because your terminal and the app have different environments. This is the most common failure here and nobody warns you about it.
A GUI application launched from Finder, the Dock or the Start menu does not read your shell profile, so nothing in .zshrc or .bash_profile is guaranteed to be present. Anything installed by a version manager (nvm, pyenv, asdf, mise, volta) is therefore not on PATH as far as Claude Desktop is concerned. Your server works when you test it and dies instantly when the app spawns it.
The docs confirm the environment half of this directly: "MCP servers launched over stdio inherit only a limited subset of environment variables automatically (the exact set is platform-dependent)."
There are two halves to the fix, and you generally need both.
Use an absolute path for command. The debugging guide lists "Try using an absolute path for command" among its startup fixes, and the build-a-server tutorial says you may need the full path to the uv executable there, obtainable with which uv or where uv. The same applies to any runtime:
which node # macOS/Linux, e.g. /Users/you/.nvm/versions/node/v22.11.0/bin/node
which python3
where node # Windows
Paste whatever that prints into command.
Use absolute paths for arguments too. A stdio server's working directory "may be undefined (like / on macOS) since the client could be started from anywhere", so a relative ./server.js resolves against a directory you did not choose. Get the absolute path with pwd, or cd with no arguments in Windows Command Prompt.
What if Node or Python is not found at all?
Install the runtime system-wide, not just inside a version-managed shell. The filesystem quickstart lists Node.js as a prerequisite and recommends the LTS build from nodejs.org, because that installer puts node and npx where a GUI-launched process can find them. An nvm install does not.
One Windows case is documented explicitly: if a server fails to load and its log mentions ${APPDATA} inside a path, add the expanded value of %APPDATA% to that server's env block. The same note warns that npx can keep failing when npm is not installed globally, and gives npm install -g npm as the remedy.
Desktop Extensions are a real alternative. Anthropic's help centre describes them as single-click installable packages that replace manual JSON editing, and its developer FAQ states that Claude Desktop ships a built-in Node.js environment, so Node installation is not required for an extension. That guarantee covers extensions specifically. It does not cover a Node server you wire up by hand in claude_desktop_config.json, which still needs Node on PATH.
Why does a server connect but expose no tools?
Because connecting and advertising capabilities are separate steps, and only the first is visible.
If the server appears under Connectors with an empty tool list, the handshake succeeded and tool registration did not: the server started, answered discovery, then either registered nothing or crashed after the connection was established. The server-specific log file is where to look, since a stack trace written to stderr lands there.
Anthropic's troubleshooting for the extension version of this symptom, installed but tools unavailable, is worth borrowing: restart the client to refresh the registry, check the configuration for missing required fields, and verify any API keys. A server that needs a key it never received will often start cleanly and register nothing.
The other possibility is that tools are registered but disabled. Connector settings let you toggle individual tools per server, and Anthropic's guidance encourages turning off ones you are not using. Check that panel before rewriting code. For the wider catalogue, MCP not working? 15 fixes covers cases beyond Claude Desktop.
What are you agreeing to when you add someone else's server?
You are agreeing to run their code on your machine, with your permissions. This is not a footnote and it should change what you install.
The MCP quickstart puts it plainly in its own security warning: "The server runs with your user account permissions, so it can perform any file operations you can perform manually." A stdio server is a subprocess you launched. By default nothing sandboxes it from your files, and command is an arbitrary command.
The protocol's security guidance is specific about local servers from untrusted sources. It lists arbitrary code execution, where "Attackers can execute any command with MCP client privileges", alongside a risk it calls no visibility: "Users have no insight into what commands are being executed." Its worked example of a malicious startup command is a package install chained to a curl that POSTs your SSH private key to a remote host. That is a config-file entry, not an exotic exploit.
The spec's own trust principles say tools "represent arbitrary code execution and must be treated with appropriate caution", and that even the descriptions of what a tool does "should be considered untrusted, unless obtained from a trusted server."
Then there is prompt injection through tool results, a documented concern rather than a theoretical one. Anthropic's connector guidance says: "Malicious MCP servers may include hidden instructions that try to make Claude perform unintended actions. Claude has built-in protections that attempt to block these attacks, but it's important to pay attention to tool inputs & outputs and connect only to trusted servers." A tool result is text that enters the model's context. If a server decides what that text says, it can try to steer the conversation, and no amount of care in your own prompt fixes that.
Four habits follow, none of them onerous:
- Prefer first-party and well-known servers. A server published by the vendor whose API it wraps, or listed in the official servers repository, has an accountable maintainer. An anonymous gist does not.
- Read the source before you add it. For a small server that is ten minutes: what
commandruns, what network calls it makes, what it reads from disk. - Scope the arguments. The filesystem server takes directories as arguments precisely so you can hand it one project folder instead of your home directory. Do that.
- Review tool calls rather than blanket-approving them. Anthropic's guidance is to review approval requests carefully and reserve "Allow always" for servers and tools you trust unsupervised. The spec asks clients to show tool inputs before calling the server "to avoid malicious or accidental data exfiltration", which only helps if you read them.
How do you keep this current when the spec keeps moving?
By treating the version number as part of the answer.
Everything above was read on 28 August 2026 against MCP revision 2026-07-28, where modelcontextprotocol.io/specification/latest currently redirects. That revision moved the capability declaration into DiscoverResult and deprecated protocol-level logging via notifications/message, so guidance written against an earlier revision can be wrong in ways that look like your mistake.
Two places to check rather than trusting a post like this one. modelcontextprotocol.io/specification/latest tells you which revision is current: if the date in the URL after the redirect is later than the one above, assume something here has moved. And the connect-to-local-servers quickstart carries the config path and the JSON shape, so it is the page that changes when the UI does.
One live inconsistency, so it does not surprise you. The MCP debugging guide states that Claude Desktop is available on macOS and Windows, while the build-a-server tutorial on the same site gives Linux log paths (~/.config/Claude/logs/) and Linux quit instructions. Both pages are current at revision 2026-07-28. I have not resolved which is right and I am not going to guess on your behalf.
Two things have been stable through every revision so far, and they are the ones worth memorising: the top-level key is mcpServers, and a config change needs a full quit rather than a window close. Almost every it just does not work report reduces to one of those, an unparseable file, or a command that is not on PATH.
Once the plumbing works, the question stops being setup and becomes what you connect. Using MCP inside Claude Code covers the same protocol with different scoping and auth rules, MCP prompt management in Cursor and Claude Desktop covers keeping prompts in the tool rather than the clipboard, and MCP for beginners skips the terminal entirely.
Stop rewriting prompts. Start shipping.
Works with ChatGPT, Claude, Gemini, Grok, Midjourney, Ideogram, Veo3 & Kling. 5.0★ on the Chrome Web Store.
Create An Account