On this page6 sections
ReferenceIntermediate5-7 min reference

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@latest

Project 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 shape

VS 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.js

Inspector 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 20

The -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.tool

Trailing 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/Desktop

If 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 npm

Some 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.