How Claude Code talks to external tools via Model Context Protocol
import type { Client } from '@modelcontextprotocol/sdk/client/index.js'import type {Resource,
ServerCapabilities,
} from '@modelcontextprotocol/sdk/types.js'
import { z } from 'zod/v4'import { lazySchema } from '../../utils/lazySchema.js'// Configuration schemas and types
export const ConfigScopeSchema = lazySchema(() =>
z.enum([
'local',
'user',
'project',
'dynamic',
'enterprise',
'claudeai',
'managed',
]),
)
export type ConfigScope = z.infer<ReturnType<typeof ConfigScopeSchema>>
export const TransportSchema = lazySchema(() =>
z.enum(['stdio', 'sse', 'sse-ide', 'http', 'ws', 'sdk']),
)
export type Transport = z.infer<ReturnType<typeof TransportSchema>>
export const McpStdioServerConfigSchema = lazySchema(() =>
z.object({ type: z.literal('stdio').optional(), // Optional for backwards compatibilitycommand: z.string().min(1, 'Command cannot be empty'),
args: z.array(z.string()).default([]),
env: z.record(z.string(), z.string()).optional(),
}),
)
// Cross-App Access (XAA / SEP-990): just a per-server flag. IdP connection
// details (issuer, clientId, callbackPort) come from settings.xaaIdp — configured
// once, shared across all XAA-enabled servers. clientId/clientSecret (parent
// oauth config + keychain slot) are for the MCP server's AS.
const McpXaaConfigSchema = lazySchema(() => z.boolean())
const McpOAuthConfigSchema = lazySchema(() =>
z.object({clientId: z.string().optional(),
callbackPort: z.number().int().positive().optional(),
authServerMetadataUrl: z
.string()
.url()
.startsWith('https://', {message: 'authServerMetadataUrl must use https://',
})
.optional(),
xaa: McpXaaConfigSchema().optional(),
}),
)
export const McpSSEServerConfigSchema = lazySchema(() =>
z.object({ type: z.literal('sse'),url: z.string(),
headers: z.record(z.string(), z.string()).optional(),
headersHelper: z.string().optional(),
oauth: McpOAuthConfigSchema().optional(),
}),
)
// Internal-only server type for IDE extensions
export const McpSSEIDEServerConfigSchema = lazySchema(() =>
z.object({ type: z.literal('sse-ide'),url: z.string(),
ideName: z.string(),
ideRunningInWindows: z.boolean().optional(),
}),
)
// Internal-only server type for IDE extensions
export const McpWebSocketIDEServerConfigSchema = lazySchema(() =>
z.object({MCP (Model Context Protocol) lets external services expose tools to Claude Code. A local Python server, a remote REST API, or a cloud service can all become Claude Code tools by implementing the MCP protocol.
MCP supports 6 transport types — from spawning a local subprocess (`stdio`) to connecting to a cloud service (`claudeai-proxy`). The transport is an implementation detail; tool invocation looks identical from Claude's perspective.
The MCPConnectionManager maintains one persistent connection per server. If a server disconnects, it reconnects with exponential backoff. Tools from all connected servers are merged with built-in tools before each query.
MCP servers that need OAuth (e.g., a GitHub integration) declare their auth endpoints in config. Claude Code handles PKCE exchange, token storage, and refresh automatically — the server just receives a bearer token.
Ask anything about MCP Integration — Plugin Protocol
Powered by Groq · Enter to send, Shift+Enter for newline