Overview
Claude Code connects to MCP servers declared in settings.json. Once connected, the server’s tools appear alongside built-in tools and Claude can call them in any turn. The pattern rule is: prefer MCP tools over Bash when the integration will be used across sessions. A one-off gh invocation is fine; recurring GitHub operations belong in the GitHub MCP server. Use the GitHub-maintained github/github-mcp-server, not the archived @modelcontextprotocol/server-github npm package. See mcp-servers for designing servers; this page covers the Claude Code client configuration.
Declare MCP servers in settings.json
Each server gets an entry under mcpServers. The key is the server’s logical name; the value describes how to launch or connect to it.
{
"mcpServers": {
"github": {
"type": "stdio",
"command": "docker",
"args": [
"run", "-i", "--rm",
"-e", "GITHUB_PERSONAL_ACCESS_TOKEN",
"ghcr.io/github/github-mcp-server"
],
"env": {
"GITHUB_PERSONAL_ACCESS_TOKEN": "${GITHUB_TOKEN}"
}
}
}
}GitHub maintains github/github-mcp-server. Run it from the published Docker image (shown above), from the prebuilt Go binary, or point Claude Code at GitHub’s hosted remote server (https://api.githubcopilot.com/mcp/) over Streamable HTTP. The old @modelcontextprotocol/server-github npm package has been archived to modelcontextprotocol/servers-archived and receives no security fixes; do not use it.
Place project-specific servers in .claude/settings.json. Place personal or cross-project servers in ~/.claude/settings.json. Both files are read; project settings merge on top.
Pass secrets through environment variables, never inline
The env block in the server config accepts ${VAR} substitutions resolved from the shell environment. Never write a token or connection string as a literal value in settings.json.
Reasons: settings.json is often committed to version control. Literals leak in diffs, logs, and PR reviews. Environment variables stay in .env (gitignored) or in the CI secrets store.
"env": {
"GITHUB_TOKEN": "${GITHUB_TOKEN}",
"DATABASE_URL": "${DATABASE_URL}"
}Claude Code reads the current shell environment when launching servers. Set the variables in your shell profile or a gitignored .env.local file sourced at session start.
Restrict tool exposure with allowedTools
By default, Claude Code exposes every tool a server advertises. Use allowedTools to restrict access to the tools the project actually needs.
{
"mcpServers": {
"github": {
"type": "stdio",
"command": "docker",
"args": [
"run", "-i", "--rm",
"-e", "GITHUB_PERSONAL_ACCESS_TOKEN",
"ghcr.io/github/github-mcp-server"
],
"env": { "GITHUB_PERSONAL_ACCESS_TOKEN": "${GITHUB_TOKEN}" },
"allowedTools": [
"mcp__github__list_issues",
"mcp__github__create_pull_request",
"mcp__github__pull_request_read",
"mcp__github__merge_pull_request"
]
}
}
}Restricting to read-only tools for a project that should not create issues prevents accidents during exploratory sessions. Allowlists also document the project’s intended integration surface.
Scope servers to specific repositories
Use project-level .claude/settings.json rather than user-level ~/.claude/settings.json when the server is specific to one repo. A Postgres server pointed at the dev database for project A should not appear in project B’s sessions.
For shared servers (GitHub, Notion), declare them at the user level but restrict allowedTools per project. The user-level declaration provides the auth; the project-level restriction limits the blast radius.
Prefer MCP tools over Bash for durable integrations
The tradeoff is:
Bashwithgh pr create: works, no setup, breaks on quoting edge cases, not logged by MCP, not consistent across sessions.mcp__github__create_pull_request: typed inputs, no quoting issues, MCP-level logging, consistent schema across sessions.
Use Bash for one-off commands the agent will not repeat. Use MCP tools for operations that recur: reading PRs, posting comments, querying a database, writing to a project management tool.
The practical test: if you have written the same Bash command in three different briefs, write an MCP server for it or enable the official one.
Confirm server connectivity before relying on it in a brief
MCP servers can fail to start (missing binary, bad token, network error). A brief that assumes GitHub MCP is live will silently fall back to Bash or fail mid-session.
Add a preflight step to briefs that depend on MCP:
Phase 0: Verify MCP connectivity.
Run: list available tools and confirm mcp__github__list_issues is present.
If not present, stop and report the error.
This catches misconfiguration before the expensive phases run.