cheat sheet

Claude Code MCP Servers

Add, configure, and build Model Context Protocol (MCP) servers for Claude Code — HTTP, SSE, and stdio transports, management commands, permission rules, and a curated list of useful servers.

Claude Code MCP Servers

What it is

MCP (Model Context Protocol) is an open standard by Anthropic for connecting AI models to external tools, data sources, and resources through a common JSON-RPC interface. Claude Code acts as an MCP client — you register MCP servers that expose additional tools (databases, APIs, GitHub, Slack, custom scripts), and Claude can call them exactly like its built-in tools during a session. Reach for MCP when the built-in Read/Edit/Bash/WebFetch tools are insufficient and you need Claude to interact with proprietary systems or specialized external APIs. The closest alternative is exposing the same functionality via a shell script that the Bash tool calls, which is simpler but lacks structured input schemas and discoverability.

How it works

Without MCP, Claude Code has built-in tools: Read, Edit, Write, Bash, Glob, Grep, WebSearch, WebFetch. With an MCP server, you add arbitrary new tools — databases, APIs, Slack, GitHub, custom scripts — and Claude can call them like any other tool.

text
Claude Code (MCP client)
    ↕  MCP protocol (JSON-RPC over stdio / SSE / HTTP)
MCP Server (exposes tools)
    ↕  native API
Postgres / GitHub / Slack / your service

Each registered server contributes a set of tools that show up alongside the built-ins. Tool names are prefixed mcp__<server-name>__<tool-name> so they cannot collide with built-ins or with each other.

Transport methods

MCP supports three transports. Pick by latency requirements and where the server lives.

TransportWhen to useLatencySetup
stdioLocal processes, CLI toolsLowestSimplest
sse (Server-Sent Events)Remote servers, shared team serversMediumNeeds HTTP server
httpREST-compatible MCP serversMediumNeeds HTTP server

stdio is the default and most common — Claude Code spawns the server as a subprocess and talks JSON-RPC over its stdin/stdout. sse and http are for servers running elsewhere (or shared across a team) and require the server to expose an authenticated HTTP endpoint.

Add a server — CLI

The claude mcp add subcommand registers an MCP server in your user-global config and immediately validates that it starts and lists tools.

bash
# Add a stdio server (local process)
claude mcp add my-server -- node /path/to/server.js

# Add an SSE server (remote)
claude mcp add my-remote-server --transport sse https://mcp.example.com/sse

# Add an HTTP server (remote)
claude mcp add my-http --transport http https://mcp.example.com/rpc

# Add with environment variables
claude mcp add my-db --env DATABASE_URL=postgresql://localhost/mydb -- node /path/to/db-server.js

Output:

text
✅ Added MCP server "my-server" (8 tools)

The trailing -- separates claude mcp add's own flags from the command to run. Everything after -- is the server command line.

List connected servers

bash
claude mcp list

Output:

text
my-server       stdio   node /path/to/server.js                          ✅ connected (8 tools)
github          stdio   npx @modelcontextprotocol/server-github          ✅ connected (12 tools)
postgres        stdio   npx @modelcontextprotocol/server-postgres        ✅ connected (3 tools)
remote-svc      sse     https://mcp.example.com/sse                      ❌ disconnected

Inspect a server's tools

bash
claude mcp tools github

Output:

text
github exposes 12 tools:
  search_repositories(query: string, sort?: string, order?: string)
  get_file_contents(owner: string, repo: string, path: string, branch?: string)
  create_or_update_file(...)
  create_issue(...)
  create_pull_request(...)
  list_commits(...)
  ...

Remove a server

bash
claude mcp remove my-server

Output:

text
Removed MCP server "my-server".

Restart a server

If a server hangs or you change its environment, restart it without exiting Claude Code:

bash
claude mcp restart github

Output:

text
Restarted "github" (12 tools available).

MCP in settings.json

For team-shared or committed server configs, define them in .claude/settings.json under mcpServers. These are picked up by every session opened in the project.

json
{
  "mcpServers": {
    "github": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-github"],
      "env": {
        "GITHUB_PERSONAL_ACCESS_TOKEN": "${GITHUB_TOKEN}"
      }
    },
    "postgres": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-postgres", "${DATABASE_URL}"]
    },
    "filesystem": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-filesystem", "/home/alice/Code"]
    },
    "remote": {
      "type": "sse",
      "url": "https://mcp.example.com/sse",
      "headers": {
        "Authorization": "Bearer ${MCP_API_KEY}"
      }
    }
  }
}

Use ${ENV_VAR} syntax in settings.json to reference environment variables without hardcoding secrets. The value is expanded at runtime from the shell environment that launched claude.

Useful MCP servers

The MCP ecosystem ships dozens of community servers. The ones below are the most common.

GitHub

Gives Claude tools to search repos, read files, create issues, open PRs, and review code — all authenticated with your GitHub token.

bash
claude mcp add github -- npx -y @modelcontextprotocol/server-github

Output:

text
✅ Added MCP server "github" (12 tools)

Required env: GITHUB_PERSONAL_ACCESS_TOKEN

Tools added: create_or_update_file, search_repositories, create_issue, create_pull_request, list_commits, get_file_contents, and more.

PostgreSQL

Read-only access to a Postgres database — schema inspection, query execution, table listings.

bash
claude mcp add postgres -- npx -y @modelcontextprotocol/server-postgres "$DATABASE_URL"

Output:

text
✅ Added MCP server "postgres" (3 tools)

Tools added: query, list_tables, describe_table.

Example use in-session:

text
> What are the 5 most recently created users in the database?

Output:

text
[Calls mcp__postgres__query with: SELECT id, email, created_at FROM users ORDER BY created_at DESC LIMIT 5]

Filesystem (extended)

Extends Claude's file access beyond the current working directory. Useful for referencing shared docs or a monorepo root from a subdirectory.

bash
claude mcp add filesystem -- npx -y @modelcontextprotocol/server-filesystem /path/to/root

Output:

text
✅ Added MCP server "filesystem" (6 tools)

Fetch (web scraping)

Gives Claude a fetch tool for retrieving web pages as plain text. Useful for pulling documentation from URLs during a session without the limits of WebFetch.

bash
claude mcp add fetch -- npx -y @modelcontextprotocol/server-fetch

Output:

text
✅ Added MCP server "fetch" (1 tool)

Replaces or complements the built-in WebSearch with Brave Search results, which can be more complete.

bash
claude mcp add brave-search -- npx -y @modelcontextprotocol/server-brave-search

Output:

text
✅ Added MCP server "brave-search" (1 tool)

Required env: BRAVE_API_KEY (free tier available)

Slack

Read channels, post messages, and search Slack history.

bash
claude mcp add slack -- npx -y @modelcontextprotocol/server-slack

Output:

text
✅ Added MCP server "slack" (4 tools)

Required env: SLACK_BOT_TOKEN, SLACK_TEAM_ID

Memory (persistent)

Gives Claude a key-value store that persists between sessions. Claude can save and recall facts using store_memory and retrieve_memory tools.

bash
claude mcp add memory -- npx -y @modelcontextprotocol/server-memory

Output:

text
✅ Added MCP server "memory" (2 tools)

Puppeteer (headless browser)

Drive a real browser for scraping or testing — navigate, click, fill forms, screenshot.

bash
claude mcp add puppeteer -- npx -y @modelcontextprotocol/server-puppeteer

Output:

text
✅ Added MCP server "puppeteer" (8 tools)

SQLite

Read/write access to a SQLite file. Great for local prototyping and analytics workflows.

bash
claude mcp add sqlite -- npx -y @modelcontextprotocol/server-sqlite /path/to/db.sqlite

Output:

text
✅ Added MCP server "sqlite" (4 tools)

Build your own MCP server

A minimal stdio MCP server in Python. The server reads JSON-RPC requests from stdin and writes responses to stdout.

python
# my_server.py
import json, sys

def handle(request):
    method = request["method"]
    if method == "initialize":
        return {"protocolVersion": "2024-11-05", "capabilities": {"tools": {}}, "serverInfo": {"name": "ci", "version": "0.1"}}
    if method == "tools/list":
        return {
            "tools": [{
                "name": "get_build_status",
                "description": "Get the current CI build status for a branch.",
                "inputSchema": {
                    "type": "object",
                    "properties": {
                        "branch": {"type": "string", "description": "Git branch name"}
                    },
                    "required": ["branch"]
                }
            }]
        }
    if method == "tools/call":
        if request["params"]["name"] == "get_build_status":
            branch = request["params"]["arguments"]["branch"]
            # Replace with real CI API call
            return {"content": [{"type": "text", "text": f"Branch '{branch}': passing"}]}
    return {"error": {"code": -32601, "message": "Method not found"}}

for line in sys.stdin:
    if not line.strip():
        continue
    req = json.loads(line)
    result = handle(req)
    response = {"jsonrpc": "2.0", "id": req.get("id"), "result": result}
    sys.stdout.write(json.dumps(response) + "\n")
    sys.stdout.flush()

Register it:

bash
claude mcp add ci-status -- python3 /path/to/my_server.py

Output:

text
✅ Added MCP server "ci-status" (1 tool)

Now Claude can call get_build_status(branch="main") during a session.

Using the official SDKs

Anthropic publishes MCP SDKs for Python and TypeScript that handle the JSON-RPC plumbing for you. They're worth using once your server has more than two or three tools.

bash
# Python
pip install mcp

# TypeScript
npm install @modelcontextprotocol/sdk

Output:

text
Successfully installed mcp-1.x.x

A Python SDK-based server is much shorter than the raw version above:

python
from mcp.server import Server
from mcp.server.stdio import stdio_server
from mcp.types import Tool, TextContent

app = Server("ci")

@app.list_tools()
async def list_tools():
    return [Tool(
        name="get_build_status",
        description="Get the current CI build status for a branch.",
        inputSchema={"type": "object", "properties": {"branch": {"type": "string"}}, "required": ["branch"]},
    )]

@app.call_tool()
async def call_tool(name, arguments):
    branch = arguments["branch"]
    return [TextContent(type="text", text=f"Branch '{branch}': passing")]

if __name__ == "__main__":
    import asyncio
    asyncio.run(stdio_server(app))

Output: (none — runs as a stdio MCP server)

Check MCP status in-session

text
> /mcp

Output:

text
Connected MCP servers:
  github      (12 tools)  ✅
  postgres    (3 tools)   ✅
  memory      (2 tools)   ✅

MCP permission rules

MCP tools follow the same permission system as built-in tools. Deny or allow specific MCP tools in settings.json. Tool names follow the pattern mcp__<server-name>__<tool-name>.

json
{
  "permissions": {
    "allow": [
      "mcp__github__search_repositories",
      "mcp__github__get_file_contents",
      "mcp__postgres__query",
      "mcp__memory__retrieve_memory"
    ],
    "deny": [
      "mcp__github__create_pull_request",
      "mcp__github__delete_file",
      "mcp__slack__post_message"
    ]
  }
}

Wildcards work the same way as for built-in tools:

json
{
  "permissions": {
    "allow": ["mcp__postgres__*"],
    "deny":  ["mcp__github__delete_*", "mcp__github__create_pull_request"]
  }
}

Authentication patterns

MCP servers that talk to external services need credentials. There are three common patterns:

Environment variables passed via settings.json

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

Secret-manager-backed env via apiKeyHelper-style script

json
{
  "mcpServers": {
    "github": {
      "command": "bash",
      "args": ["-c", "GITHUB_PERSONAL_ACCESS_TOKEN=$(op read op://Personal/GitHub/token) exec npx -y @modelcontextprotocol/server-github"]
    }
  }
}

OAuth for remote (SSE/HTTP) servers

Some MCP servers (Gmail, Google Calendar, Mintlify) implement an OAuth flow. The first call to a tool from such a server triggers an authenticate step that returns a URL; the user opens it, completes consent, and the server stores the resulting token.

text
> /mcp tools gmail
gmail: 2 tools
  authenticate()                ← call this first
  send_email(to, subject, body)

Output:

text
> Use gmail/authenticate, then send a test email to alice@example.com
[Calls mcp__gmail__authenticate → returns URL → user completes → token stored]

Common pitfalls

  1. Server not startingclaude mcp add validates startup but doesn't always surface the error; run the server command manually and watch stderr.
  2. Env vars not expanded${VAR} only expands inside mcpServers.*.env and mcpServers.*.args; literal $VAR strings are passed through unchanged.
  3. Tool name length — MCP tool names are namespaced mcp__<server>__<tool>; servers with long names produce unwieldy permission entries — keep server names short (≤8 chars).
  4. Permission deny for a server prefix — there's no mcp__github__* deny rule for ALL tools; you must list them individually or use a glob if your version supports it.
  5. npx -y cachingnpx -y re-downloads the package on every cold start; for slow networks, install globally with npm i -g @modelcontextprotocol/server-github and reference it directly.
  6. Server crashes mid-session — when a server dies, Claude sees tool call failures but doesn't auto-restart; check /mcp and run claude mcp restart <name>.
  7. Shared SSE server auth tokens leak — never commit Authorization headers to .claude/settings.json; use .claude/settings.local.json or ${ENV_VAR}.

Real-world recipes

Database-aware code review

Add a Postgres MCP server in read-only mode so Claude can verify migrations against the live schema during reviews.

json
{
  "mcpServers": {
    "postgres": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-postgres", "${READONLY_DATABASE_URL}"]
    }
  },
  "permissions": {
    "allow": ["mcp__postgres__query", "mcp__postgres__list_tables", "mcp__postgres__describe_table"],
    "deny":  ["mcp__postgres__execute"]
  }
}

Team-wide GitHub server

A shared SSE MCP server lets the whole team share one access token and audit log. Run it on an internal host and reference it from each developer's settings.

json
{
  "mcpServers": {
    "team-github": {
      "type": "sse",
      "url": "https://mcp.internal.example.com/github/sse",
      "headers": {"Authorization": "Bearer ${TEAM_MCP_TOKEN}"}
    }
  }
}

Custom CI status server

Wire your build system into Claude with a small Python MCP server. Useful when Claude is iterating on a flaky test and needs to verify whether main is green.

bash
claude mcp add ci-status -- python3 ~/bin/ci-mcp-server.py

Output:

text
✅ Added MCP server "ci-status" (3 tools)

Then in-session:

text
> Is the build green on main?
[Calls mcp__ci-status__get_build_status(branch="main") → "Branch 'main': passing"]

Memory across sessions

Use the memory MCP server as Claude's "scratchpad that survives /clear". Drop key facts there so the next session can pick up where this one left off.

text
> Save to memory: the auth module uses bcrypt rounds=12, never lower.
[Calls mcp__memory__store_memory]

Output:

text
Stored.