MCP Servers in Claude Code: A Practical Integration Guide

MCP Servers in Claude Code: A Practical Integration Guide

Most teams discover MCP servers the same way: they spend a week getting Claude Code working well, then face a new bottleneck: they become the courier between tools.. Claude Code can only reason about what you put in front of it. Your production incident is in Sentry. Your task is described in Jira. Your schema lives in PostgreSQL. Without a direct connection, you become the intermediary — copy-pasting context from one system into another, which defeats much of the point.

The Model Context Protocol (MCP) is the solution to this. It’s an open standard — developed by Anthropic and now broadly supported across AI tooling — that defines a standardised way for AI applications to connect to external data sources and tools. Within Claude Code, a connected MCP server means Claude can query your database directly, pull a Jira ticket by ID, check Sentry for recent errors, or push a GitHub PR without you pasting anything.

This guide covers the architecture, key configuration decisions, integration patterns, and failure modes.

 

What MCP Actually Is

The protocol specification describes MCP using a USB-C analogy: a standardised connector that works regardless of what’s on either end. That’s useful but incomplete. MCP defines three participants — a host, clients, and servers — each with a distinct role.

Claude Code is the host. It manages overall connections and coordinates one MCP client per server it connects to. Each client maintains a dedicated connection to its corresponding server.

MCP servers are programs — local processes or remote services — that expose capabilities through three primitive types:

  • Tools are executable functions Claude can invoke: querying a database, creating a GitHub issue, fetching a Sentry trace. These are actions. 
  • Resources are data sources Claude can read: a database schema, a file tree, an API response. These are context loaded when referenced. 
  • Prompts are reusable templates that become available as slash commands in Claude Code, following the format /mcp__servername__promptname.

 

The underlying communication protocol is JSON-RPC 2.0, running over one of two transport mechanisms: stdio for local processes, and Streamable HTTP for remote services. Everything else — capability negotiation, tool discovery, tool execution, real-time notifications when a server’s available tools change — is built on top of this foundation.

One thing worth understanding early: MCP is a stateful protocol. When Claude Code connects to an MCP server, it negotiates capabilities upfront and maintains that connection throughout the session. This has real implications for connection failure handling, which we’ll return to.

 

The Two Transports and When to Use Each

Claude Code supports three transport configurations. The official documentation is explicit that SSE (Server-Sent Events) is deprecated — use HTTP for remote servers wherever you might otherwise reach for SSE.

 

Stdio

Stdio runs the MCP server as a local process on the same machine, communicating via standard input/output streams. It’s ideal for tools that need direct system access — local databases, custom scripts, filesystem tools. The Performance is excellent; no network overhead. However, Claude Code won’t reconnect stdio servers if they crash. If your stdio server exits mid-session, you’ll need to restart manually.

# Add a local PostgreSQL integration via stdio

claude mcp add --transport stdio --env PGPASSWORD=your-pass db \

  -- npx -y @bytebase/dbhub --dsn "postgresql://user@localhost:5432/mydb"

 

HTTP (Streamable HTTP)

HTTP is the recommended transport for remote services — anything cloud-based or running on a separate host. When an HTTP server drops, Claude Code retries with exponential backoff: five attempts, starting at one second.. This automatic resilience makes HTTP the right choice for production integrations where availability matters.

 

# Connect to Sentry’s remote MCP server
claude mcp add –transport http sentry https://mcp.sentry.dev/mcp

 

HTTP supports three authentication options: OAuth 2.0, static headers, and dynamic headers via headersHelper. Claude Code supports OAuth 2.0 for cloud services, static headers for API keys and Bearer tokens, and a headersHelper mechanism for dynamic authentication schemes. The transport choice is usually straightforward: running on the same machine? Use stdio. Cloud service or separate host? Use HTTP.

 

Scopes: Getting Configuration Strategy Right

Most teams make their first MCP mistake here: picking the wrong scope. There are three scopes, and choosing wrong creates either security problems or coordination headaches.

 

  • Local scope (default)

Local scope stores the server configuration in your ~/.claude.json, scoped to the current project path. It’s private to you, available only in that project, and never appears in version control. Use this for anything involving personal credentials, individual API tokens, or experimental servers you’re testing before sharing with the team.

 

  • Project scope

Project scope stores configuration in a .mcp.json file at your project root, designed to be checked into version control. When a team member clones the repository and opens Claude Code, they get the same set of MCP servers automatically. This is the right scope for tools the whole team needs — the shared issue tracker, the team database, the internal monitoring integration.

 

# Add a shared integration for the whole team
claude mcp add –transport http jira –scope project https://mcp.atlassian.com/mcp

 

Note that Claude Code prompts for approval before loading .mcp.json servers. This is a security checkpoint, not a bug.

The resulting .mcp.json supports environment variable expansion, which resolves the tension between sharing configuration and protecting credentials:

{
  "mcpServers": {
    "internal-api": {
      "type": "http",
      "url": "${API_BASE_URL:-https://api.example.com}/mcp",
      "headers": {
        "Authorization": "Bearer ${API_KEY}"
      }
    }
  }
}

 

The syntax ${API_BASE_URL:-https://api.example.com} uses a fallback if the variable isn’t set. ${API_KEY} has no fallback — if it’s missing from the environment, Claude Code fails to parse the entire configuration file. Always provide defaults for non-sensitive configuration; document which variables are required.

 

  • User scope

User scope uses the same ~/.claude.json file but applies no project filter — the server loads everywhere. Use this for personal utility servers — a notes integration, a calendar tool — that you want everywhere but aren’t specific to any project.

 

Design Decisions That Determine Whether Integrations Are Actually Useful

Connecting a server is the easy part. The decisions that shape whether the integration works well happen before and after that command.

 

Design your tools around Claude’s reasoning, not your API’s structure

A common mistake is to expose internal API endpoints one-for-one as MCP tools. This creates a tool called get_user_by_id that requires knowing a user ID to call — which Claude won’t have unless you told it. A better tool — find_users — accepts partial matches or natural language, so Claude doesn’t need a pre-loaded identifiers. Tools should be designed for how an AI navigates a task, not for how a REST client navigates an API.

 

Use resources for context, tools for actions

If you’re integrating a database, the schema belongs as a resource (static context Claude loads once) and the query function belongs as a tool (an action Claude invokes when needed). Resources are loaded into context when referenced — they consume your context window — while tools are invoked on demand. A database schema as a resource is perfectly reasonable; the entire table contents as a resource will rapidly exhaust your available context.

 

Manage output size deliberately

Claude Code warns when any MCP tool output exceeds 10,000 tokens. At 25,000 it writes the output to disk and inserts a file reference instead. For tools that legitimately need to return large responses, you can annotate individual tools in the server’s tools/list response:

{
  "name": "get_schema",
  "description": "Returns the full database schema",
  "_meta": {
    "anthropic/maxResultSizeChars": 200000
  }
}

 

This raises the threshold for that specific tool without requiring users to adjust MAX_MCP_OUTPUT_TOKENS globally. For tools that return variable-size results, design pagination in from the start — it’s significantly easier than retrofitting it when you discover your log analysis tool is returning 80,000 tokens of output.

 

Be selective about which tools load upfront

Claude Code defers MCP tool loading by default — only tool names enter context at session start, and Claude searches for relevant tools as needed. This keeps context consumption low when you have many servers connected. For tools Claude needs on every turn, you can override this with alwaysLoad: true in the server configuration. Use it sparingly: each upfront-loaded tool consumes context that would otherwise be available for your conversation.

 

Practical Patterns for Common Integrations

Database integration

The cleanest approach for a team database is a read-only connection string created specifically for MCP use. This provides meaningful access — schema inspection, query execution — while making the scope of what Claude can do explicit and auditable. Project-scope the configuration with the connection string in an environment variable so the configuration is safe to commit:

claude mcp add --transport stdio --scope project db \
  -- npx -y @bytebase/dbhub --dsn "${DB_READONLY_DSN}"

 

Once connected, ‘find all users who haven’t logged in for 90 days’ replaces writing SQL.

 

Internal APIs with dynamic authentication

For APIs using non-standard authentication — internal SSO (single-sign-on), rotating tokens, Kerberos — the headersHelper mechanism generates authentication headers dynamically at each connection:

{
  "mcpServers": {
    "internal-api": {
      "type": "http",
      "url": "https://mcp.internal.example.com",
      "headersHelper": "/opt/bin/get-mcp-auth-headers.sh"
    }
  }
}

 

The script must write a JSON object of string key-value pairs to stdout within 10 seconds. Claude Code runs it fresh on each connection with no caching — well-suited for short-lived token schemes. One script can serve multiple servers. Claude Code passes CLAUDE_CODE_MCP_SERVER_NAME and CLAUDE_CODE_MCP_SERVER_URL so the script knows which server is calling.

 

Monitoring and observability tools

Remote HTTP servers like Sentry or your internal monitoring platform use OAuth 2.0 authentication handled through the /mcp panel in Claude Code. Tokens are stored securely and refreshed automatically. Once connected, debugging shifts from “let me check Sentry, then cross-reference the deploy logs” to a single conversation.

 

Enterprise Access Control

For organisations deploying Claude Code across engineering teams, MCP configuration needs central management rather than engineer-by-engineer setup.

Claude Code supports two approaches. IT administrators deploy managed-mcp.json to a system-wide directory. This file locks all MCP servers —engineers cannot add or modify any. Platform-specific paths: /Library/Application Support/ClaudeCode/managed-mcp.json on macOS, /etc/claude-code/managed-mcp.json on Linux, C:\Program Files\ClaudeCode\managed-mcp.json on Windows.

The second approach uses allowlists and denylists in the managed settings, permitting engineers to configure their own servers while enforcing policy constraints. URL patterns with wildcard support (https://*.internal.corp/*) let you allow entire internal domains while blocking external endpoints. Command-based restrictions for stdio servers require exact array matching — [“npx”, “-y”, “approved-package”] will not match [“npx”, “approved-package”] without the -y flag. This precision is intentional.

For teams that want standardised MCP configuration without full lockdown, project-scoped .mcp.json files in version control are often sufficient. Engineers get shared tools automatically, add personal servers at local scope or user scope, and review config changes through pull requests.

 

Failure Modes Worth Knowing Before You Hit Them

Prompt injection through MCP content

Anthropic’s documentation includes an explicit warning: be careful with MCP servers that fetch untrusted content, as these can expose you to prompt injection risk. A server that reads arbitrary web pages or processes user-submitted text can inadvertently inject instructions into Claude’s context. Treat this as a real architectural constraint when designing servers that process external content.

 

The reserved name

The server name workspace is reserved for internal Claude Code use. If your .mcp.json defines a server with that name, Claude Code silently skips it at load time and logs a warning. Easy to create, confusing to debug if you don’t know the reservation exists.

 

Stdio servers and process lifecycle

Unlike HTTP servers, Claude Code doesn’t reconnect stdio servers if they exit. Crashes —OOM (out of memory), dependency failures, bugs — end the session. The /mcp panel will show it as failed, and you’ll need to restart the session. Design your stdio servers for stability, or use process supervision if they’re critical to your workflow.

 

Context consumption at scale

The more MCP servers you connect with alwaysLoad: true, or the more frequently they return large outputs, the more your effective context window shrinks. The default deferred loading handles this well for most setups — be deliberate when overriding it.

 

Where to Start

The highest-return first integration for most engineering teams is whatever system they copy-paste from most often into Claude Code conversations. That’s usually an issue tracker or a monitoring tool — both of which have mature MCP server implementations available today.

Add it at project scope so the team gets it automatically. Use an environment variable for credentials so the configuration is safe to commit. Run /mcp in Claude Code to verify the connection and inspect available tools. That panel is useful enough as a diagnostic tool that it’s worth making a habit of checking it first when something isn’t working.

The shift MCP enables isn’t just convenience. It changes what Claude Code can accomplish on a task without constant human intervention. With your database, issue tracker, and error logs connected, Claude Code can reason about problems — not just answer questions. That’s the difference between a capable tool and an autonomous collaborator — and MCP is what bridges it.

 

Sources: 

Share this post

Do you have any questions?

Newsletter

Zartis Tech Review

Your monthly source for AI and software related news.