---
title: "MCP Integration in Agent SDK"
aliases: [mcp-servers, model-context-protocol, agent-mcp]
tags: [agent-sdk, mcp, tools, typescript, authentication]
sources: [raw/Connect to external tools with MCP.md]
created: 2026-04-17
updated: 2026-04-17
---

# MCP Integration in Agent SDK

The Model Context Protocol (MCP) is an open standard for connecting AI agents to external tools and data sources — databases, GitHub, Slack, APIs — without writing custom tool implementations.

## Quickstart

```typescript
import { query } from "@anthropic-ai/claude-agent-sdk";

for await (const message of query({
  prompt: "Use the docs MCP server to explain what hooks are",
  options: {
    mcpServers: {
      "claude-code-docs": {
        type: "http",
        url: "https://code.claude.com/docs/mcp"
      }
    },
    allowedTools: ["mcp__claude-code-docs__*"]
  }
})) {
  if (message.type === "result" && message.subtype === "success") {
    console.log(message.result);
  }
}
```

## Adding MCP Servers

### In code (mcpServers option)

Pass directly to `query()`:

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

### From `.mcp.json` config file

Place at project root — loaded automatically when `"project"` is in `settingSources`:

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

## Allowing MCP Tools

MCP tools require **explicit permission** before Claude can call them.

### Naming convention

`mcp__<server-name>__<tool-name>` — e.g., `mcp__github__list_issues`

### allowedTools patterns

```typescript
allowedTools: [
  "mcp__github__*",          // all tools from github server
  "mcp__db__query",          // single tool
  "mcp__slack__send_message" // single tool
]
```

**Use `allowedTools` wildcards, not permission modes:**
- `permissionMode: "acceptEdits"` — does NOT auto-approve MCP tools
- `permissionMode: "bypassPermissions"` — approves MCP but disables all safety prompts (too broad)
- Wildcard in `allowedTools` — grants exactly the server you want, nothing more

### Discover available tools

```typescript
if (message.type === "system" && message.subtype === "init") {
  console.log("Available MCP tools:", message.mcp_servers);
}
```

## Transport Types

| Transport | When to use | Config key |
|-----------|-------------|------------|
| **stdio** | Local process (npx command given) | `command` + `args` |
| **HTTP** | Cloud-hosted, non-streaming URL | `type: "http"` + `url` |
| **SSE** | Cloud-hosted, streaming URL | `type: "sse"` + `url` |
| **SDK MCP** | Custom in-process tools | See custom tools guide |

### stdio example

```typescript
mcpServers: {
  github: {
    command: "npx",
    args: ["-y", "@modelcontextprotocol/server-github"],
    env: { GITHUB_TOKEN: process.env.GITHUB_TOKEN }
  }
}
```

### HTTP/SSE example

```typescript
mcpServers: {
  "remote-api": {
    type: "sse",
    url: "https://api.example.com/mcp/sse",
    headers: { Authorization: `Bearer ${process.env.API_TOKEN}` }
  }
}
```

## MCP Tool Search

When many tools are configured, definitions can fill the context window. **Tool search is enabled by default** — it withholds tool definitions from context and loads only what Claude needs per turn.

See [[wiki/agent-sdk/typescript-api-reference|TypeScript API Reference]] for configuration options.

## Authentication

### Environment variables (stdio)

```typescript
env: { GITHUB_TOKEN: process.env.GITHUB_TOKEN }
```

### HTTP headers (remote servers)

```typescript
headers: { Authorization: `Bearer ${process.env.API_TOKEN}` }
```

### OAuth2

SDK doesn't handle OAuth flows automatically. Complete the flow in your app, then pass the access token via headers:

```typescript
const accessToken = await getAccessTokenFromOAuthFlow();
headers: { Authorization: `Bearer ${accessToken}` }
```

## Error Handling

Check the `system` / `init` message for connection status before the agent starts:

```typescript
if (message.type === "system" && message.subtype === "init") {
  const failedServers = message.mcp_servers.filter(s => s.status !== "connected");
  if (failedServers.length > 0) console.warn("Failed:", failedServers);
}
```

## Troubleshooting

| Problem | Cause | Fix |
|---------|-------|-----|
| Server shows "failed" | Missing env vars, package not installed, bad connection string, network | Check `init` message `status` field |
| Tools not called | Missing `allowedTools` | Add `"mcp__servername__*"` |
| Connection timeout | Server slow to start (60s default) | Pre-warm server or use lighter package |

## Key Takeaways

- MCP tool names follow `mcp__<server>__<tool>` — wildcards with `*` allow all tools from a server
- Always use `allowedTools` for MCP access, not `permissionMode`
- Three transport types: stdio (local process), HTTP (remote non-streaming), SSE (remote streaming)
- Credentials go in `env` (stdio) or `headers` (HTTP/SSE) — never hardcoded
- Check `message.type === "system" && message.subtype === "init"` for connection status and tool discovery
- Tool search is on by default — prevents context overflow with large tool sets
- Default connection timeout is 60 seconds; pre-warm servers that need longer startup

## Related

- [[wiki/agent-sdk/configure-permissions|Configure Permissions]] — `allowedTools`, `disallowedTools`, permission modes
- [[wiki/agent-sdk/typescript-api-reference|TypeScript API Reference]] — full `mcpServers` config options
- [[wiki/agent-sdk/python-api-reference|Python API Reference]] — Python equivalent
- [[wiki/agent-sdk/hooks-guide|Hooks Guide]] — automate workflows alongside MCP tools

## Sources

- `raw/Connect to external tools with MCP.md`
