ClaudeMap

·MCP Servers

A practical guide to the MCP server config format — where Claude Desktop and Claude Code read their config, working examples for filesystem, GitHub, and Postgres servers, and a troubleshooting checklist for when a server won't load.

Configuring MCP Servers in Claude Desktop and Claude Code

The Model Context Protocol (MCP) only pays off once you actually wire servers into the apps you use. The good news is that every MCP-compatible host reads essentially the same kind of config: a small JSON file that tells the host how to spawn each server, what arguments to pass, and which environment variables it needs. This guide walks through the config format in detail, shows working examples for three real reference servers (filesystem, GitHub, and Postgres), covers the differences between Claude Desktop and Claude Code, and ends with a troubleshooting checklist you can run through when a server refuses to load.

Where each host reads its config

Before writing anything, know where the file lives.

Claude Desktop reads a single config file:

  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
  • Windows: %APPDATA%\Claude\claude_desktop_config.json
  • Linux: ~/.config/Claude/claude_desktop_config.json

Claude Desktop also exposes this file through its UI: open Settings → Developer → Edit Config and it opens the file in your editor. You can enable, disable, and inspect servers there too.

Claude Code reads MCP servers from several layers, all merged:

  • .mcp.json in your project root (checked into the repo, shared with the team)
  • ~/.claude.json or your user settings (personal servers)
  • Plugin-provided servers

The project .mcp.json is the one you commit. It is the standard way to share a set of MCP servers with everyone working in a repository.

Both hosts use the same mcpServers shape, so a server entry you write once can move between them with minor path changes.

The config shape

Every config is an object with one key, mcpServers, whose value is a map of server name to server definition. The name is just a label you pick — it shows up in the host UI and in tool names. Each definition needs a command and args, and optionally env:

{
  "mcpServers": {
    "my-server": {
      "command": "node",
      "args": ["/absolute/path/to/index.js"],
      "env": {
        "API_KEY": "sk-..."
      }
    }
  }
}

A few rules worth internalizing:

  • Use absolute paths. Relative paths are resolved against the host's working directory, which is not always where you expect. Hardcoding the absolute path to your server's entry point removes a whole class of "it works on my machine" bugs.
  • command is an executable, not a shell string. If you need a shell, run bash or cmd and pass -c plus the script in args.
  • env is additive. The spawned process inherits the host's environment, and entries here are merged on top. This is where API tokens and config flags go.
  • The server name must be unique within one config file. Duplicate keys silently overwrite.

A filesystem server

The official @modelcontextprotocol/server-filesystem server exposes a set of directories to the model as readable and writable resources. It is the simplest real server to configure and a good first smoke test.

Install it once so the host can find it:

npm install -g @modelcontextprotocol/server-filesystem

Then add it to claude_desktop_config.json:

{
  "mcpServers": {
    "filesystem": {
      "command": "npx",
      "args": [
        "-y",
        "@modelcontextprotocol/server-filesystem",
        "/Users/me/projects",
        "/Users/me/notes"
      ]
    }
  }
}

The trailing path arguments are the directories the server is allowed to see. Anything outside that list is invisible to the model — that boundary is the security model, so list exactly the roots you want to expose and nothing more. After saving the file and restarting Claude Desktop, you can ask "what files are in my projects directory?" and the model will call the filesystem server to answer.

For Claude Code, the same entry goes into .mcp.json in the project root. Claude Code also lets you add it interactively:

claude mcp add filesystem -- npx -y @modelcontextprotocol/server-filesystem /Users/me/projects

The CLI writes the entry into the right config layer for you and validates the JSON on the way in.

A GitHub server

The official GitHub MCP server (@modelcontextprotocol/server-github or the newer @modelcontextprotocol/server-github) lets the model read issues, pull requests, and repository metadata through the GitHub REST API. It needs a personal access token, which is exactly what the env block is for.

{
  "mcpServers": {
    "github": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-github"],
      "env": {
        "GITHUB_PERSONAL_ACCESS_TOKEN": "ghp_your_token_here"
      }
    }
  }
}

Create the token at github.com/settings/tokens with the scopes you actually need (repo for private repos, read:org for org data). Treat the token like a password — never commit the config file with a real token in it. If you are sharing a project config, use a placeholder and document where to put the real value, or load it from a separate local file that is gitignored.

Once loaded, you can ask the model things like "list the open issues in my repo labeled bug" or "summarize the comments on PR #1234" and it will call the GitHub server to fetch the data. Tools show up as mcp__github__<tool_name> in Claude Code, which makes it obvious which server a given tool came from.

A Postgres server

The official Postgres server (@modelcontextprotocol/server-postgres) exposes a read-only (by default) view of a database: tables, schemas, and the ability to run SELECT queries. You pass a connection string:

{
  "mcpServers": {
    "postgres": {
      "command": "npx",
      "args": [
        "-y",
        "@modelcontextprotocol/server-postgres",
        "postgresql://user:password@localhost:5432/mydb"
      ]
    }
  }
}

A few notes specific to databases:

  • Prefer a read-only role. The Postgres server is read-only by default, but connecting with a role that only has SELECT privileges is belt-and-suspenders. Never hand the model a connection string for a production write user.
  • Schema is everything. The model reads the schema to decide what queries to run, so a well-named schema produces far better queries than a cryptic one.
  • Connection pooling. Each MCP server process holds its own connection. For a local dev database that is fine; for a shared database, point it at a connection pooler like PgBouncer.

Claude Desktop vs Claude Code

The two hosts overlap heavily but differ in a few practical ways.

Claude Desktop is a desktop app with a graphical settings panel. You edit claude_desktop_config.json, restart the app, and the servers appear under the hammer icon in the composer. There is no per-project config — every chat sees the same set of servers.

Claude Code is a terminal tool that lives alongside your code. Its .mcp.json is per-project and checked into git, so a repository can declare the servers it depends on. It also layers user-level and plugin-provided servers on top. You can scope servers to a project, inspect them with claude mcp list, and remove them with claude mcp remove <name>. The tool-prefix convention (mcp__<server>__<tool>) makes the source of every tool call explicit.

In practice: use Claude Desktop config for personal, cross-project servers (your notes, your calendar). Use a project .mcp.json for servers that are part of how a specific codebase works (its database, its issue tracker, its internal APIs).

Making changes take effect

MCP servers are spawned by the host, so config changes only apply after the host picks them up:

  • Claude Desktop — fully quit and relaunch the app. Closing the window is not enough; the server processes keep running until the app exits.
  • Claude Code — start a new session, or run /mcp to reconnect within a running session.

If a server still does not appear after a restart, the first thing to check is whether the JSON parses. A trailing comma or a missing brace will make the host silently ignore the whole config, and no servers will load at all. Paste the file through a JSON validator if you are unsure.

Troubleshooting checklist

When a server refuses to load or a tool does not show up, work through these in order:

  1. Does the JSON parse? One syntax error disables every server in the file.
  2. Is the path absolute and correct? Print the full command from your config and run it in a terminal. If it errors there, it will error in the host too.
  3. Are the dependencies installed? npx -y <package> downloads on first run, which needs network access. In air-gapped environments install the package globally first.
  4. Are the environment variables set? A server that needs GITHUB_PERSONAL_ACCESS_TOKEN and does not get it will start, then fail on the first tool call. Check the token has the right scopes.
  5. Does the server print anything to stderr? Claude Desktop writes server logs to ~/Library/Logs/Claude/mcp-server-<name>.log on macOS; Claude Code surfaces them through the /mcp panel. Read them before guessing.
  6. Is there a version mismatch? MCP is still maturing. If a server was written against an older protocol version, pin the version in args (e.g. @modelcontextprotocol/server-filesystem@0.6.0) until the host catches up.

The fastest debugging loop is usually: run the server command directly in a terminal, watch it print its startup banner, then kill it and let the host spawn it. If the standalone run works but the host run does not, the problem is in the config or environment, not the server.

Frequently asked questions

Do I need to restart Claude Desktop after editing the config file?

Yes. Claude Desktop spawns MCP servers when the app starts and keeps them alive for the session. Editing claude_desktop_config.json changes nothing until you fully quit and relaunch the app; closing the window is not a restart.

What is the difference between claude_desktop_config.json and .mcp.json?

claude_desktop_config.json is Claude Desktop's single global config file and applies to every chat. .mcp.json is Claude Code's per-project config file, checked into the repo so the whole team gets the same servers. Both use the same mcpServers shape.

Can a server access my whole filesystem?

Only what you explicitly allow. The filesystem server takes the allowed directories as command-line arguments, and anything outside that list is invisible to the model. Treat that allowlist as the security boundary and list exactly the roots you want to expose.

How do I pass an API token to a server safely?

Put it in the env block of the server definition. The host passes those variables to the spawned process. Never commit a real token in a shared config file — use a placeholder, load it from a gitignored local file, or inject it from a secrets manager at deploy time.

Official references

This article reflects publicly available information as of July 2026; relevant APIs may evolve.