obsidian/wiki/agent-sdk/mcp-integration.md
2026-04-17 12:40:31 +01:00

200 lines
5.7 KiB
Markdown

---
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`