MCP server configuration
To add an MCP server to Claude Desktop, open Settings -> Developer -> Edit Config, which opens claude_desktop_config.json. Add an entry under the top-level "mcpServers" object -- a key (the server's name) mapping to either a local stdio launcher ("command" plus "args" and optional "env") or a remote endpoint ("url") -- then save and fully restart Claude Desktop. On launch it spawns one MCP client per server, runs the JSON-RPC 2.0 capability handshake, and then discovers and calls that server's tools, resources and prompts. Because a server's tool descriptions and outputs flow straight into the model's context, audit any third-party server before you add it.
Where the config lives and how to open it
Claude Desktop reads its MCP servers from a single JSON file called claude_desktop_config.json. The easiest way to find it is inside the app: open Settings, go to the Developer tab, and click "Edit Config" -- that creates the file if it does not exist and reveals it in your file manager. On macOS it lives at ~/Library/Application Support/Claude/claude_desktop_config.json; on Windows at %APPDATA%\Claude\claude_desktop_config.json.
The file is plain JSON, so it must be valid: no trailing commas, no comments, all strings double-quoted. A single syntax error stops every server from loading, so validate the file (any JSON linter works) after editing.
Claude Desktop only re-reads this file on launch. After any change you must fully quit the app -- not just close the window -- and reopen it for the new or edited server to take effect.
The mcpServers schema
Everything lives under one top-level object named "mcpServers". Each key is a name you choose for the server (it is just a label shown in the UI), and each value is the configuration object for that server.
For a local server over the stdio transport, the value is a launcher: "command" is the executable to run (for example "npx", "uvx", "node", or an absolute path to a binary), "args" is an array of arguments passed to it, and the optional "env" object injects environment variables -- the standard place to pass API keys and tokens rather than hardcoding them into args. Claude Desktop spawns this command as a subprocess and speaks JSON-RPC 2.0 over its stdin/stdout.
For a remote server over Streamable HTTP (or the legacy HTTP+SSE transport), the value points at an endpoint with a "url" field instead of a command, and remote servers commonly sit behind OAuth 2.1 or a bearer token. Whichever transport you use, the host (Claude Desktop) starts one MCP client per entry, performs the capability handshake to negotiate what each side supports, then discovers and calls that server's tools, resources and prompts.
A minimal config example
A working file with one local stdio server and one remote server looks like this: { "mcpServers": { "my-local-tool": { "command": "uvx", "args": ["some-mcp-server"], "env": { "API_KEY": "..." } }, "my-remote-tool": { "url": "https://example.com/mcp" } } }. Save it, fully restart Claude Desktop, and the servers appear in the tools menu.
If a server fails to appear, the usual causes are invalid JSON, a "command" that is not on the app's PATH (use an absolute path if in doubt), a missing required "env" value, or simply not having restarted the app. Claude Desktop writes MCP logs you can inspect to see the handshake succeed or fail.
Keep real secrets in "env", never in "args" or in a tool's schema, and prefer named environment references over pasting long-lived keys directly into a file that may end up in a backup or a screen-share.
Adding a server safely
Adding an MCP server grants it real reach into your session: the server's tool descriptions are read into the model's context as authoritative text, and the tool outputs it returns are read back as data the model may act on. A malicious or compromised server can abuse either channel to steer the agent -- this is tool poisoning and tool-output prompt injection -- without the text ever appearing in the UI.
The risk compounds when you load several servers at once. Capabilities are additive across your whole config: a server that can read private data, a server that can fetch untrusted content, and a server that can send data out can together form the lethal trifecta -- the combination under which a single injection can turn into real data exfiltration -- even if each server looked harmless alone.
The practical defenses are straightforward: add servers from sources you trust, keep credentials in "env", prefer servers whose tools clearly mark destructive operations (via annotations), and audit any unfamiliar server before you add it. Servers can also silently change their tool definitions after you approve them (a rug pull), so re-checking on updates -- not just on day one -- is part of staying safe.
How CheckMCP handles it
Before you paste a third-party server into claude_desktop_config.json, CheckMCP tells you whether it is safe to add. Paste the server's URL at checkmcp.dev -- or run `uvx checkmcp <url>` from the open-source CLI -- and CheckMCP probes the live endpoint and returns an explainable, vendor-neutral MCP Score 0-100 (grade A-F) across seven weighted pillars led by security (weight 20), which runs an OWASP MCP Top 10 pass for tool poisoning, hardcoded secrets, command injection and the lethal trifecta. Hard caps surface the worst configurations immediately: a secret found in a tool schema caps the grade at D, and a failed MCP handshake caps it at F. Opt-in behavioral evals exercise read-only tools with canary inputs to catch prompt-injection and data-exfiltration in tool responses. For servers you depend on, the GitHub Action (`uses: H129hj/checkmcp@v1`) and drift monitoring re-check on every change so a rug pull after approval does not go unnoticed, and an in-band Gateway (passive or active mode) can block tool-poisoning and drift before they reach your agent. CheckMCP audits the server; you keep your config clean.