MCP Server Setup
A working reference for setting up MCP (Model Context Protocol) servers across clients. Covers config file shape, how to add a server in Claude Desktop, Claude Code, Cursor, and VS Code, the environment-variable and working-directory gotchas that account for most "won't connect" issues, and the debugging steps when nothing's showing up. For Playwright MCP specifically, see /cheat-sheets/playwright-mcp.
Config file basics
Config file locations
The mcpServers config lives in a JSON file per client. Locations vary.
Claude Desktop (macOS): ~/Library/Application Support/Claude/claude_desktop_config.json
Claude Desktop (Windows): %APPDATA%\Claude\claude_desktop_config.json
Claude Code (project): .claude/settings.json (relative to project root)
Claude Code (global): ~/.claude.json (with --scope global)
Cursor: .cursor/mcp.json (in workspace)
VS Code: .vscode/mcp.json (per workspace)
Codex: ~/.codex/config.toml
Restart the client after editing the config — running clients won't reload it. For Claude Desktop, "quit completely and reopen" — closing the window isn't enough.
Standard mcpServers config shape
Almost every MCP client accepts this exact JSON for local (stdio) servers.
{
"mcpServers": {
"myserver": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/Users/username/Desktop"]
}
}
}The server name ("myserver" here) is freeform — it's how the client labels the connection in its UI. The command + args is what the client runs as a child process.
Restart-to-apply discipline
Config changes never take effect until the client restarts. For Claude Desktop, full quit-and-reopen.
Closing the chat window isn't enough. Use the system tray quit or Cmd+Q (macOS) / Alt+F4 (Windows). For Claude Code, exit the CLI and re-run claude. For Cursor and VS Code, the UI usually offers a "Reload" prompt after edits.
Verify the server connected
Confirm the server loaded after restart.
# Claude Code, Cursor, VS Code MCP-aware modes
/mcp
# Claude Desktop — visual MCP indicator in bottom-right of chat input/mcp is a slash command that lists connected servers and their exposed tools. If the server doesn't appear, the config didn't load or the server failed to start.
Adding a server by client
Claude Desktop
Edit the config file directly.
# macOS
open -e "$HOME/Library/Application Support/Claude/claude_desktop_config.json"
# Windows
notepad "%APPDATA%\Claude\claude_desktop_config.json"Then add an entry under "mcpServers" using the standard config shape, save, and fully restart Claude Desktop.
The file may not exist on first run — open the app's Developer settings and click "Edit Config" to create it.
Claude Code
Use the CLI to register a server in the current project's scope.
claude mcp add <server-name> <command> [args...]
# Example — register Playwright MCP
claude mcp add playwright npx @playwright/mcp@latest
# Use --scope global to register across all projects
claude mcp add --scope global playwright npx @playwright/mcp@latestProject scope writes to .claude/settings.json in the current directory. Global scope writes to ~/.claude.json. Per-project is the better default.
Cursor
Add via Cursor Settings → MCP, or by editing the workspace config file directly.
{
"mcpServers": {
"playwright": {
"command": "npx",
"args": ["@playwright/mcp@latest"]
}
}
}Save to .cursor/mcp.json in the workspace root. Cursor's MCP toggle should turn green next to the server name in Settings. If it doesn't, check the Output panel for MCP logs.
VS Code (with Copilot)
Add via the workspace config file.
# Quick install from the command line
code --add-mcp '{"name":"playwright","command":"npx","args":["@playwright/mcp@latest"]}'
# Or edit .vscode/mcp.json directly with the standard config shapeVS Code with GitHub Copilot picks up MCP servers in the workspace's .vscode/mcp.json. Restart VS Code or reload the window for changes to apply.
Codex
Add via the Codex CLI or edit ~/.codex/config.toml directly.
codex mcp add playwright npx "@playwright/mcp@latest"Or in ~/.codex/config.toml:
[mcp_servers.playwright]
command = "npx"
args = ["@playwright/mcp@latest"]TOML, not JSON, for Codex. Pay attention to the syntax — it's the most common Codex config mistake. Codex also supports MCP servers over streamable HTTP — use url = "https://..." in place of command/args for hosted servers.
Common server packages
Filesystem server
Read, write, and search files in specified directories. The canonical first-MCP-server most users install.
{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-filesystem",
"/Users/username/Desktop",
"/Users/username/Downloads"
]
}
}
}Each path after the package name is a directory the server is allowed to access. Use absolute paths — the working directory for stdio servers is undefined. Only grant access to directories you're comfortable with the client reading and modifying.
Git server
Browse, search, and analyse Git repositories. Python-based, uses uvx.
{
"mcpServers": {
"git": {
"command": "uvx",
"args": ["mcp-server-git", "--repository", "/Users/username/code/myrepo"]
}
}
}Requires uv installed (the Python package manager — see github.com/astral-sh/uv). Run uv --version to check.
Fetch server
Fetch URLs and convert HTML to markdown. Useful for letting an agent read documentation.
{
"mcpServers": {
"fetch": {
"command": "uvx",
"args": ["mcp-server-fetch"]
}
}
}Also Python via uvx. No args needed for basic operation.
Finding more servers
The MCP Registry lists official and community-built servers.
https://github.com/modelcontextprotocol/servers
https://modelcontextprotocol.io/registry/about
The reference servers (Filesystem, Git, Fetch, Memory, Sequential Thinking, Time) are in modelcontextprotocol/servers. Community servers are listed in the official registry. Verify the source before adding any community server to a client with access to sensitive data.
Environment variables and secrets
Adding an env block to a server
Stdio servers inherit only a limited subset of environment variables. Specify any the server needs in the env key.
{
"mcpServers": {
"myserver": {
"command": "npx",
"args": ["-y", "@example/mcp-server"],
"env": {
"API_KEY": "sk-...",
"DATABASE_URL": "postgres://..."
}
}
}
}Values in the env block are passed to the child process at launch. They don't leak into your shell environment.
Windows %APPDATA% / ENOENT errors
Servers that fail on Windows with ENOENT errors referencing ${APPDATA} need APPDATA explicitly set in the env block.
{
"mcpServers": {
"brave-search": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-brave-search"],
"env": {
"APPDATA": "C:\\Users\\username\\AppData\\Roaming\\",
"BRAVE_API_KEY": "..."
}
}
}
}This is a known stdio-on-Windows quirk where environment variable expansion isn't applied to paths.
Secrets discipline
API keys, tokens, and other secrets go in the env block — never inline in args, never committed to git.
Treat your client's config file as a secret. .claude/settings.json, .cursor/mcp.json, and .vscode/mcp.json should be in your project's .gitignore unless they contain no credentials. For Claude Desktop, the global config file is outside any repo so it's safer by default — but it's still readable by other applications on your machine.
Remote servers via Custom Connectors
Adding a remote MCP server (Claude.ai)
For internet-hosted servers, use Claude.ai's Custom Connectors feature in Settings.
Navigate to Settings → Connectors → "Add custom connector". Enter the remote MCP server URL (must be https://) and complete authentication. The server's tools become available in chat after connection. Different from local servers — no config file edit, all UI-driven.
Authentication patterns
Most remote MCP servers use OAuth, API keys, or username/password.
The auth flow varies by server. OAuth servers redirect you to the provider's login page. API-key servers prompt for the key in the Add Connector dialog. Never share OAuth tokens or API keys across people — each user should add the connector with their own credentials.
Scoping tool permissions per connector
After connecting, configure which tools the server is allowed to call.
Navigate back to Connectors → click the connected server. Disable tools you don't want Claude to access — the principle of least privilege matters here. Tool-permission scoping is the main difference between "connected" (server is reachable) and "armed" (server's tools can fire).
Debugging when it doesn't connect
MCP Inspector — the first stop
Interactive debugging UI that connects to any MCP server independently of any client.
# Inspect a server installed from npm
npx -y @modelcontextprotocol/inspector npx -y @modelcontextprotocol/server-filesystem /Users/username/Desktop
# Inspect a server installed via uvx (Python)
npx @modelcontextprotocol/inspector uvx mcp-server-git --repository ~/code/myrepo
# Inspect a locally-developed server
npx @modelcontextprotocol/inspector node path/to/server/index.jsInspector opens a web UI that lets you list the server's tools, prompts, and resources, invoke tools with custom inputs, and watch the notification stream. If the server works in Inspector but not in your client, the issue is in the client config — not the server.
Log file locations
Client log files for MCP connection events and errors.
# macOS
~/Library/Logs/Claude/mcp.log
~/Library/Logs/Claude/mcp-server-<servername>.log
# Windows
%APPDATA%\Claude\logs\mcp.log
%APPDATA%\Claude\logs\mcp-server-<servername>.log
mcp.log covers general connection events. mcp-server-<servername>.log captures stderr from the named server — <servername> is the lowercase key you used in mcpServers (e.g. mcp-server-playwright.log for a server named "playwright"). This is where most useful error messages land.
Tail logs in real time
Watch the log file while triggering a reconnect.
# macOS/Linux
tail -n 20 -F ~/Library/Logs/Claude/mcp*.log
# Windows (PowerShell)
Get-Content "$env:APPDATA\Claude\logs\mcp.log" -Wait -Tail 20The -F flag (not -f) follows the file even if it's rotated. Restart Claude Desktop while this is running to see the connection attempt live.
JSON syntax check
Most "server doesn't appear" issues are invalid JSON in the config file.
cat ~/Library/Application\ Support/Claude/claude_desktop_config.json | python3 -m json.toolTrailing commas, mismatched braces, and unescaped quotes are the usual culprits. A JSON-aware editor (VS Code) highlights them in red.
Use absolute paths
Stdio servers run from an undefined working directory (often / on macOS).
Any path in command, args, or env values must be absolute. Relative paths like ./data or ~/Desktop will not resolve correctly. Substitute ~ with the full path (e.g. /Users/username/Desktop on macOS).
Run the server standalone
Test that the server's command actually works outside the client.
# Copy the exact command from your config and run it
npx -y @modelcontextprotocol/server-filesystem /Users/username/DesktopIf this errors in the terminal, it'll error inside the client too. Fix the standalone run first.
npm global install missing
If npx keeps failing on Windows, npm may not be installed globally.
# Check if %APPDATA%\npm exists. If not:
npm install -g npmSome Windows installations don't put npm in the global path. The fix is to reinstall npm globally.
Capability negotiation errors (-32602)
Error code -32602 (JSON-RPC "Invalid params") in logs usually means the client and server disagree on capabilities.
One common cause: the server tries to send sampling or elicitation requests to a client that hasn't declared support. Inspect the initialize exchange in the logs to verify both sides declared compatible capabilities. This is rarer than other errors but distinctive.