Learn Build MCP Servers: Extend Claude with Custom Tools Connecting Your Server to Claude

Connecting Your Server to Claude

Advanced 🕐 20 min Lesson 8 of 15
What you'll learn
  • Configure Claude Desktop, Cursor, and VS Code to connect to local stdio MCP servers
  • Pass environment variables to server processes using the env key in the config
  • Diagnose connection failures using MCP log files

The MCP Client Ecosystem

Claude Desktop is not the only client that speaks MCP. As of 2026, a growing list of tools support the protocol. The ones you are most likely to encounter as a developer are:

  • Claude Desktop — the reference client; supports stdio servers on macOS and Windows
  • Claude.ai (Projects) — browser-based; supports remote HTTP servers only (no stdio)
  • Cursor — AI code editor; stdio and HTTP servers; per-project or global config
  • VS Code with GitHub Copilot — workspace-level .vscode/mcp.json
  • Windsurf — supports MCP via its AI panel settings
  • Zed — configurable via ~/.config/zed/settings.json
  • Cline and Continue — VS Code extensions with MCP support built in

The good news: all of these clients use the same conceptual config structure — a named server entry with a command, args, and optional env. The file location and key names vary slightly, but the mental model is identical.

Claude Desktop Config: The Full Picture

The Claude Desktop config file lives at:

  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
  • Windows: %APPDATA%Claudeclaude_desktop_config.json

Here is a complete config showing two servers, environment variable injection, and the disabled field:

{
  "mcpServers": {
    "weather": {
      "command": "node",
      "args": ["/Users/yourname/weather-mcp/build/index.js"],
      "env": {
        "WEATHER_API_KEY": "your-key-here"
      }
    },
    "filesystem": {
      "command": "npx",
      "args": [
        "-y",
        "@modelcontextprotocol/server-filesystem",
        "/Users/yourname/documents"
      ]
    },
    "old-experiment": {
      "command": "node",
      "args": ["/Users/yourname/old-server/build/index.js"],
      "disabled": true
    }
  }
}

Key fields:

  • command — the executable to run (node, npx, uv, python)
  • args — array of command-line arguments passed to the process
  • env — key/value pairs injected as environment variables into the server process
  • disabled — set to true to skip a server without removing its config

Passing API Keys with env

Never hardcode API keys inside your server code. Use the env key in the config instead, and read the value with process.env.WEATHER_API_KEY (TypeScript) or os.environ["WEATHER_API_KEY"] (Python).

This approach has two benefits: the key stays out of your source code, and you can configure different keys per client (development Claude Desktop config vs production Cursor config) without touching the server.

For Python servers managed with uv, you can also use a .env file in the project directory. uv will load it automatically when running the server. But the env config key is more portable because it works regardless of where the server file lives.

Verifying the Connection

After saving the config, fully quit and restart Claude Desktop — a window close is not enough, you need to quit the application. On macOS, right-click the Dock icon and choose Quit.

When the app reopens, look for the hammer icon in the bottom-left of the chat input area. Click it to see how many tools are available and which servers they came from. If your server appears with its tools listed, the connection succeeded.

If the hammer shows zero tools, or your server does not appear, proceed to the debugging section below.

Debugging Connection Failures

Most MCP connection failures fall into one of five categories:

1. Relative Path

Claude Desktop launches server processes from its own working directory, not yours. A path like ./build/index.js will not resolve. Always use absolute paths:

// Wrong
"args": ["./build/index.js"]

// Right
"args": ["/Users/yourname/weather-mcp/build/index.js"]

2. Wrong Command

The command field must be a binary that exists on the system PATH as seen by Claude Desktop — not by your terminal session. If uv or node is installed via a version manager like nvm or mise, Claude Desktop may not see it. Use the absolute path to the binary instead:

"command": "/Users/yourname/.nvm/versions/node/v22.0.0/bin/node"

Run which node (or which uv) in your terminal to find the absolute path.

3. Forgot to Build (TypeScript)

TypeScript servers must be compiled before use. If you edited the source but forgot to run npm run build, Claude Desktop will load the old compiled version — or fail entirely if no build output exists yet. Always build after changes:

npm run build

4. Server Crashes on Startup

If the server process exits immediately after launch, Claude Desktop will silently drop it. Check the MCP log files:

  • macOS: ~/Library/Logs/Claude/mcp-server-<name>.log — per-server stderr output
  • macOS: ~/Library/Logs/Claude/mcp.log — overall MCP connection events
  • Windows: %APPDATA%Claudelogs

The per-server log captures everything your server writes to stderr. A missing import, a syntax error, or a failed environment variable read will show up here. This should always be your first debugging stop.

5. JSON Syntax Error in Config

The config file is plain JSON — trailing commas and comments are not allowed. A single syntax error silently disables all servers. Use a JSON linter or your editor's built-in validation before restarting Claude Desktop.

Cursor: Per-Project and Global Config

Cursor reads MCP config from two locations:

  • Project: .cursor/mcp.json in the project root — applies only to that workspace
  • Global: ~/.cursor/mcp.json — applies to all projects

The format is identical to Claude Desktop's claude_desktop_config.json — same mcpServers structure, same fields. Copy your config directly.

Cursor also supports HTTP servers via the url field instead of command/args:

{
  "mcpServers": {
    "my-remote-server": {
      "url": "https://my-server.example.com/mcp"
    }
  }
}

VS Code with GitHub Copilot

VS Code reads MCP config from .vscode/mcp.json in the workspace root. The structure uses a servers key (not mcpServers):

{
  "servers": {
    "weather": {
      "type": "stdio",
      "command": "node",
      "args": ["/Users/yourname/weather-mcp/build/index.js"]
    }
  }
}

The type field is required in VS Code's format: "stdio" for local servers, "http" for remote ones. After adding the file, open the Copilot Chat panel — your tools will appear in the tool picker.

Claude.ai Web (Projects)

The Claude.ai web interface supports MCP in Projects via Settings > Integrations, but only for remote HTTP servers — it cannot launch local stdio processes. You will need to deploy your server to a publicly accessible HTTPS endpoint. Lessons 13 and 14 cover remote deployment. For local development, Claude Desktop remains the right choice.

What to Try Next

  1. Add a second server entry to your Claude Desktop config (try the official @modelcontextprotocol/server-filesystem package to give Claude access to a specific folder).
  2. Intentionally introduce a typo in the config JSON, restart Claude Desktop, and observe that no servers load — then fix it and confirm they return.
  3. Add an env key to your weather server config with a dummy variable, log it to stderr on startup, and verify it appears in the MCP log file.
Key takeaways
  • Every MCP client uses the same config structure: mcpServers object with server name, command, args, and optional env
  • Always use absolute paths in MCP config files — relative paths silently fail
  • Claude Desktop log files at ~/Library/Logs/Claude/mcp-server-<name>.log are the first place to look when a server does not appear
  • The env key in the config injects environment variables into the server process — use this for API keys instead of hardcoding them
  • Cursor uses .cursor/mcp.json (project) or ~/.cursor/mcp.json (global); VS Code with Copilot uses .vscode/mcp.json with a 'servers' key instead of 'mcpServers'