跳到正文
FunCoding

搜索

搜索文档、智能体、博客、Skill 和 MCP

用 MCP 连接外部工具

在 Agent SDK 里配置 MCP 服务器:快速开始、在代码里或配置文件里添加、连接时序、允许 MCP 工具、传输类型(stdio、HTTP/SSE、SDK)、工具搜索、认证(环境变量、HTTP 头、OAuth2)、示例与错误处理、排障。

Model Context Protocol(MCP)是把 AI 智能体连接到外部工具和数据源的开放标准。有了 MCP,你的智能体可以查询数据库、集成 Slack 和 GitHub 这样的 API,并连接到其他服务,而不必编写自定义工具实现。MCP 服务器可以作为本地进程运行、通过 HTTP 连接,或直接在你的 SDK 应用内部执行。

本页讲 Agent SDK 的 MCP 配置;要给 Claude Code CLI 添加在每个项目里都加载的 MCP 服务器,见「MCP 安装范围」。

快速开始

这个例子用 HTTP 传输连接到 Claude Code 文档 MCP 服务器,并用带通配符的 allowedTools 允许该服务器的所有工具。

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 in Claude Code",
  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);
  }
}
import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage


async def main():
    options = ClaudeAgentOptions(
        mcp_servers={
            "claude-code-docs": {
                "type": "http",
                "url": "https://code.claude.com/docs/mcp",
            }
        },
        allowed_tools=["mcp__claude-code-docs__*"],
    )

    async for message in query(
        prompt="Use the docs MCP server to explain what hooks are in Claude Code",
        options=options,
    ):
        if isinstance(message, ResultMessage) and message.subtype == "success":
            print(message.result)


asyncio.run(main())

智能体连接到文档服务器,搜索关于 hooks 的信息,并返回结果。

添加 MCP 服务器

你可以在调用 query() 时在代码里配置 MCP 服务器,或在经 settingSources 加载的 .mcp.json 文件里配置。

在代码里

直接在 mcpServers 选项里传 MCP 服务器。这个例子为 /Users/me/projects 启动一个本地文件系统 MCP 服务器;把该路径换成你机器上的目录:

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

for await (const message of query({
  prompt: "List files in my project",
  options: {
    mcpServers: {
      filesystem: {
        command: "npx",
        args: ["-y", "@modelcontextprotocol/server-filesystem", "/Users/me/projects"]
      }
    },
    allowedTools: ["mcp__filesystem__*"]
  }
})) {
  if (message.type === "result" && message.subtype === "success") {
    console.log(message.result);
  }
}
import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage


async def main():
    options = ClaudeAgentOptions(
        mcp_servers={
            "filesystem": {
                "command": "npx",
                "args": [
                    "-y",
                    "@modelcontextprotocol/server-filesystem",
                    "/Users/me/projects",
                ],
            }
        },
        allowed_tools=["mcp__filesystem__*"],
    )

    async for message in query(prompt="List files in my project", options=options):
        if isinstance(message, ResultMessage) and message.subtype == "success":
            print(message.result)


asyncio.run(main())

从配置文件

在项目根目录创建 .mcp.json 文件。启用 project 设置来源时该文件会被拾取(默认的 query() 选项是启用的);如果你显式设置了 settingSources,要包含 "project" 这个文件才会加载。把 /Users/me/projects 换成你机器上的目录:

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

连接时序

Claude Code 在启动时注册你在 options.mcpServers 里传入的服务器,并在第一个轮次的等待(如果有)解决之后发出 init 消息。options.mcpServers 里的每个服务器是否延迟第一个轮次、以及何时连接,取决于它的类型:

服务器类型是否延迟第一个轮次?第一个轮次的等待超时
stdio 服务器,或没有缓存工具列表的 HTTP/SSE 服务器是,直到它连接MCP_TIMEOUT,默认 30 秒;连接在该截止时间失败
有缓存工具列表(Claude Code 从先前连接保存的)的远程服务器否;缓存的工具从第一个轮次起可用无;在第一次工具调用时连接,该推迟的连接有自己的超时
进程内 SDK 服务器是,直到它连接并列出它的工具MCP_TIMEOUT,默认 30 秒,按每次连接尝试;连接在该截止时间失败

从 .mcp.json 这样的设置文件或插件加载的服务器,在 init 消息里通常显示 pending。当 options.mcpServers 持有 stdio、HTTP 或 SSE 服务器时,第一个轮次也会等这些 pending 的服务器,最多 MCP_TIMEOUT;当 options.mcpServers 为空或只持有 SDK 服务器时,第一个轮次改为最多等 2 秒:

  • 有工具搜索(默认):等待涵盖仍 pending 的、配置了 alwaysLoad: true 的服务器,不涵盖其余的;其余的继续在后台连接(Claude 在它们连接之后如何获得它们的工具,见「工具可用性」)。
  • 没有工具搜索:等待涵盖每个 pending 的服务器(什么会关闭工具搜索,见「配置工具搜索」;如果你把 ToolSearch 工具排除出会话,例如通过 disallowedTools,会话也在没有工具搜索的情况下运行)。

如果你设了 permissionPromptToolName,第一个轮次在任何情况下也会等待该工具的服务器,最多 MCP_TIMEOUT。要自己设置第一个轮次的等待,在 env 选项里加 CLAUDE_CODE_MCP_STARTUP_WAIT_MS,例如 CLAUDE_CODE_MCP_STARTUP_WAIT_MS: "5000":第一个轮次随后最多等那么多毫秒,等待每个 pending 的服务器,不论工具搜索是否可用;这个截止时间还会取代 options.mcpServers 里 stdio、HTTP 和 SSE 服务器的 MCP_TIMEOUT 第一轮次等待(CLAUDE_CODE_MCP_STARTUP_WAIT_MS 需要 Claude Code v2.1.274 及以上)。等待结束时仍 pending 的服务器继续在后台连接;把该变量设为 0 可跳过等待;permissionPromptToolName 服务器不论该值如何都保持自己的 MCP_TIMEOUT 等待。要在比第一轮次等待更早的、单独的阶段(在发送 init 消息之前)阻塞启动本身:

  • 把 MCP_CONNECTION_NONBLOCKING 设为 0,在整个连接批次上阻塞;Claude Code 默认把该等待限制在 5 秒,用环境变量 MCP_CONNECT_TIMEOUT_MS(毫秒)调整该上限;在该截止时间仍 pending 的服务器继续在后台连接。
  • 在服务器配置上设 alwaysLoad: true,使它的工具在第一个轮次以完整 schema 可用,免于工具搜索推迟;Claude Code 在启动时等待该服务器的工具(限制在同一个截止时间),其他服务器继续在后台连接;有缓存工具列表的远程服务器按上表不经连接就提供它们。

subtype 为 init 的 system 消息报告每个服务器在它被发出那一刻的状态(读取这些状态见「错误处理」)。

允许 MCP 工具

MCP 工具需要显式权限,Claude 才能使用它们。没有权限时,Claude 会看到工具可用,但无法调用它们。

工具命名约定

MCP 工具遵循命名模式 mcp__<server-name>__<tool-name>。例如,名为 "github" 的 GitHub 服务器带有 list_issues 工具,就成为 mcp__github__list_issues。

用 allowedTools 自动批准

用 allowedTools 自动批准特定 MCP 工具,让 Claude 无需权限提示就能使用它们:

const options = {
  mcpServers: {
    // 你的服务器
  },
  allowedTools: [
    "mcp__github__*", // github 服务器的所有工具
    "mcp__db__query", // 只有 db 服务器的 query 工具
    "mcp__slack__send_message" // 只有 slack 服务器的 send_message
  ]
};
options = ClaudeAgentOptions(
    mcp_servers={
        # 你的服务器
    },
    allowed_tools=[
        "mcp__github__*",  # github 服务器的所有工具
        "mcp__db__query",  # 只有 db 服务器的 query 工具
        "mcp__slack__send_message",  # 只有 slack 服务器的 send_message
    ],
)

通配符(*)让你无需逐个列出就允许某个服务器的所有工具。对 MCP 访问,优先用 allowedTools 而不是权限模式:permissionMode: "acceptEdits" 不会自动批准 MCP 工具(只批准文件编辑和文件系统 Bash 命令);permissionMode: "bypassPermissions" 确实会自动批准 MCP 工具,但也禁用大多数其他安全提示,比必要的更宽(仍保留哪些提示见「权限如何评估」);allowedTools 里的通配符恰好授予你想要的 MCP 服务器,不多不少(完整比较见「权限模式」)。

发现可用工具

要查看 MCP 服务器提供哪些工具,查看服务器的文档,或检查 system init 消息里的 tools 数组;MCP 工具名以 mcp__ 开头。对经 options.mcpServers 传入的服务器,Claude Code 在第一个轮次的连接等待之后才发出 init 消息,所以 tools 数组列出到那时已连接的每个服务器的 mcp__ 工具,外加有缓存工具列表(在首次使用时连接)的服务器的工具;任何其他尚未连接的服务器的工具缺席(读取每个服务器的状态见「错误处理」)。这个过滤器打印 MCP 工具名:

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

const options = {
  mcpServers: {
    // 你的服务器
  },
};

for await (const message of query({ prompt: "...", options })) {
  if (message.type === "system" && message.subtype === "init") {
    const mcpTools = message.tools.filter((name) => name.startsWith("mcp__"));
    console.log("Available MCP tools:", mcpTools);
  }
}
import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions, SystemMessage


async def main():
    options = ClaudeAgentOptions(
        mcp_servers={
            # 你的服务器
        },
    )

    async for message in query(prompt="...", options=options):
        if isinstance(message, SystemMessage) and message.subtype == "init":
            mcp_tools = [t for t in message.data.get("tools", []) if t.startswith("mcp__")]
            print("Available MCP tools:", mcp_tools)


asyncio.run(main())

你也可以让 Claude 列出某个服务器可用的工具。

传输类型

MCP 服务器用不同的传输协议与你的智能体通信,要查看服务器的文档了解它支持哪种传输:如果文档给你的是要运行的命令(如 npx @modelcontextprotocol/server-filesystem),用 stdio;如果文档给你的是 URL,用 HTTP 或 SSE;如果你在代码里构建自己的工具,用 SDK MCP 服务器。

stdio 服务器

通过 stdin/stdout 通信的本地进程,用于你在同一台机器上运行的 MCP 服务器。.mcp.json 形式用「从配置文件」里所示的同样字段;在代码里,传命令及其参数(把 /Users/me/projects 换成你机器上的目录):

const options = {
  mcpServers: {
    filesystem: {
      command: "npx",
      args: ["-y", "@modelcontextprotocol/server-filesystem", "/Users/me/projects"]
    }
  },
  allowedTools: ["mcp__filesystem__read_file", "mcp__filesystem__list_directory"]
};
options = ClaudeAgentOptions(
    mcp_servers={
        "filesystem": {
            "command": "npx",
            "args": [
                "-y",
                "@modelcontextprotocol/server-filesystem",
                "/Users/me/projects",
            ],
        }
    },
    allowed_tools=["mcp__filesystem__read_file", "mcp__filesystem__list_directory"],
)

HTTP/SSE 服务器

对云端托管的 MCP 服务器和远程 API,用 HTTP 或 SSE。.mcp.json 形式用「远程服务器的 HTTP 头」那个例子里的同样字段,SSE 服务器用 "type": "sse";在代码里,传服务器的 URL:

const options = {
  mcpServers: {
    "remote-api": {
      type: "sse",
      url: "https://api.example.com/mcp/sse",
      headers: {
        Authorization: `Bearer ${process.env.API_TOKEN}`
      }
    }
  },
  allowedTools: ["mcp__remote-api__*"]
};
options = ClaudeAgentOptions(
    mcp_servers={
        "remote-api": {
            "type": "sse",
            "url": "https://api.example.com/mcp/sse",
            "headers": {"Authorization": f"Bearer {os.environ['API_TOKEN']}"},
        }
    },
    allowed_tools=["mcp__remote-api__*"],
)

对可流式 HTTP 传输,改用 "type": "http"。在 .mcp.json 和其他 JSON 配置文件里,"streamable-http" 被接受为 "http" 的别名;SDK 的 McpHttpServerConfig 类型只声明 "http",所以对你在代码里传入的服务器要用 "http"。

SDK MCP 服务器

直接在你的应用代码里定义自定义工具,而不是运行单独的服务器进程(实现细节见自定义工具指南)。由 initialize 控制请求注册的 SDK MCP 服务器,在 Claude Code 处理该请求时就开始连接。

MCP 工具搜索

当你配置了许多 MCP 工具时,工具定义可能占用上下文窗口的很大一部分。工具搜索通过把工具定义扣在上下文之外、只加载 Claude 每个轮次需要的那些来解决这个问题。工具搜索默认启用(配置选项、最佳实践以及对自定义 SDK 工具使用工具搜索,见「工具搜索」)。

认证

多数 MCP 服务器需要认证才能访问外部服务。通过服务器配置里的环境变量传递凭据。

通过环境变量传递凭据

用 env 字段把 API key、令牌和其他凭据传给 MCP 服务器。在代码里:

const options = {
  mcpServers: {
    "api-server": {
      command: "npx",
      args: ["-y", "@your-org/api-mcp-server"],
      env: {
        API_KEY: process.env.API_KEY
      }
    }
  },
  allowedTools: ["mcp__api-server__*"]
};
options = ClaudeAgentOptions(
    mcp_servers={
        "api-server": {
            "command": "npx",
            "args": ["-y", "@your-org/api-mcp-server"],
            "env": {"API_KEY": os.environ["API_KEY"]},
        }
    },
    allowed_tools=["mcp__api-server__*"],
)

在 .mcp.json 里:

{
  "mcpServers": {
    "api-server": {
      "command": "npx",
      "args": ["-y", "@your-org/api-mcp-server"],
      "env": {
        "API_KEY": "${API_KEY}"
      }
    }
  }
}

${API_KEY} 语法在运行时展开环境变量。

远程服务器的 HTTP 头

对 HTTP 和 SSE 服务器,直接在服务器配置里传认证头。在代码里:

const options = {
  mcpServers: {
    "secure-api": {
      type: "http",
      url: "https://api.example.com/mcp",
      headers: {
        Authorization: `Bearer ${process.env.API_TOKEN}`
      }
    }
  },
  allowedTools: ["mcp__secure-api__*"]
};
options = ClaudeAgentOptions(
    mcp_servers={
        "secure-api": {
            "type": "http",
            "url": "https://api.example.com/mcp",
            "headers": {"Authorization": f"Bearer {os.environ['API_TOKEN']}"},
        }
    },
    allowed_tools=["mcp__secure-api__*"],
)

在 .mcp.json 里:

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

${API_TOKEN} 语法在运行时展开环境变量。用头认证的远程服务器的完整可运行示例见「列出仓库的 issue」。

OAuth2 认证

MCP 规范支持用于授权的 OAuth 2.1。SDK 不会打开浏览器或运行交互式 OAuth 流程。当已配置的服务器返回授权质询而没有可用的已存储令牌时,智能体运行继续进行但没有该服务器的工具,且该服务器报告状态 needs-auth;系统 init 消息的 mcp_servers 数组在它被发出时仍可能为该服务器显示 pending。要确认某个服务器是否需要凭据,在 TypeScript SDK 里轮询 mcpServerStatus(),或在 Python 里轮询 get_mcp_status()。要提供凭据,在你自己的应用里完成 OAuth 流程,并把得到的访问令牌传进服务器的 headers:

// 在你的应用里完成 OAuth 流程之后。
// 为你的 OAuth 提供商实现 getAccessTokenFromOAuthFlow。
const accessToken = await getAccessTokenFromOAuthFlow();

const options = {
  mcpServers: {
    "oauth-api": {
      type: "http",
      url: "https://api.example.com/mcp",
      headers: {
        Authorization: `Bearer ${accessToken}`
      }
    }
  },
  allowedTools: ["mcp__oauth-api__*"]
};
# 在你的应用里完成 OAuth 流程之后。
# 为你的 OAuth 提供商实现 get_access_token_from_oauth_flow。
access_token = await get_access_token_from_oauth_flow()

options = ClaudeAgentOptions(
    mcp_servers={
        "oauth-api": {
            "type": "http",
            "url": "https://api.example.com/mcp",
            "headers": {"Authorization": f"Bearer {access_token}"},
        }
    },
    allowed_tools=["mcp__oauth-api__*"],
)

示例

列出仓库的 issue

这个例子连接到远程 GitHub MCP 服务器来列出最近的 issue,并包含调试日志以验证 MCP 连接和工具调用。运行之前,创建一个对你想查询的仓库有读取权限的 GitHub 个人访问令牌,并把它设为环境变量:

export GITHUB_TOKEN=YOUR_GITHUB_PAT
import { query } from "@anthropic-ai/claude-agent-sdk";

for await (const message of query({
  prompt: "List the 3 most recent issues in anthropics/claude-code",
  options: {
    mcpServers: {
      github: {
        type: "http",
        url: "https://api.githubcopilot.com/mcp/",
        headers: {
          Authorization: `Bearer ${process.env.GITHUB_TOKEN}`
        }
      }
    },
    allowedTools: ["mcp__github__list_issues"]
  }
})) {
  // 验证 MCP 服务器连接成功
  if (message.type === "system" && message.subtype === "init") {
    console.log("MCP servers:", message.mcp_servers);
  }

  // 记录 Claude 何时调用 MCP 工具
  if (message.type === "assistant") {
    for (const block of message.message.content) {
      if (block.type === "tool_use" && block.name.startsWith("mcp__")) {
        console.log("MCP tool called:", block.name);
      }
    }
  }

  // 打印最终结果
  if (message.type === "result" && message.subtype === "success") {
    console.log(message.result);
  }
}
import asyncio
import os
from claude_agent_sdk import (
    query,
    ClaudeAgentOptions,
    ResultMessage,
    SystemMessage,
    AssistantMessage,
)


async def main():
    options = ClaudeAgentOptions(
        mcp_servers={
            "github": {
                "type": "http",
                "url": "https://api.githubcopilot.com/mcp/",
                "headers": {"Authorization": f"Bearer {os.environ['GITHUB_TOKEN']}"},
            }
        },
        allowed_tools=["mcp__github__list_issues"],
    )

    async for message in query(
        prompt="List the 3 most recent issues in anthropics/claude-code",
        options=options,
    ):
        # 验证 MCP 服务器连接成功
        if isinstance(message, SystemMessage) and message.subtype == "init":
            print("MCP servers:", message.data.get("mcp_servers"))

        # 记录 Claude 何时调用 MCP 工具
        if isinstance(message, AssistantMessage):
            for block in message.content:
                if hasattr(block, "name") and block.name.startswith("mcp__"):
                    print("MCP tool called:", block.name)

        # 打印最终结果
        if isinstance(message, ResultMessage) and message.subtype == "success":
            print(message.result)


asyncio.run(main())

在 MCP servers: 那一行里,github 的 status 为 connected 就确认令牌有效。如果 Claude Code 为该服务器有缓存的工具列表,状态可能改为显示 pending,服务器在第一次工具调用时连接。如果状态是 failed 或 needs-auth,在信任结果之前先看「错误处理」,因为服务器不可用时 Claude 可能回退到内置工具。

查询数据库

这个例子用 DBHub 查询 Postgres 数据库。智能体自动发现数据库 schema、编写 SQL 查询并返回结果。DBHub 的 execute_sql 工具会运行智能体发出的任何 SQL(包括写入),除非你限制它。在 DBHub 配置文件里设 readonly = true 会让 DBHub 拒绝 INSERT、UPDATE、DELETE 和 DDL 语句,所以即使智能体发出写入,这个例子也不能修改你的数据。DBHub 在加载配置时从进程环境解析 ${DATABASE_URL},所以连接串不会出现在文件里。在你的脚本旁边创建这个 dbhub.toml:

[[sources]]
id = "production"
dsn = "${DATABASE_URL}"

[[tools]]
name = "execute_sql"
source = "production"
readonly = true

脚本随后把 DBHub 指向该配置文件,而不是直接传连接串。运行之前,把 DATABASE_URL 环境变量设为你的连接串(把占位值换成你自己的数据库细节):

export DATABASE_URL=postgresql://user:password@localhost:5432/mydb
import { query } from "@anthropic-ai/claude-agent-sdk";

for await (const message of query({
  // 自然语言查询——Claude 编写 SQL
  prompt: "How many users signed up last week? Break it down by day.",
  options: {
    mcpServers: {
      postgres: {
        command: "npx",
        // dbhub.toml 设了 readonly = true,所以 execute_sql 拒绝写入
        args: ["-y", "@bytebase/dbhub", "--config", "dbhub.toml"]
      }
    },
    allowedTools: ["mcp__postgres__execute_sql"]
  }
})) {
  if (message.type === "result" && message.subtype === "success") {
    console.log(message.result);
  }
}
import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage


async def main():
    options = ClaudeAgentOptions(
        mcp_servers={
            "postgres": {
                "command": "npx",
                # dbhub.toml 设了 readonly = true,所以 execute_sql 拒绝写入
                "args": [
                    "-y",
                    "@bytebase/dbhub",
                    "--config",
                    "dbhub.toml",
                ],
            }
        },
        allowed_tools=["mcp__postgres__execute_sql"],
    )

    # 自然语言查询——Claude 编写 SQL
    async for message in query(
        prompt="How many users signed up last week? Break it down by day.",
        options=options,
    ):
        if isinstance(message, ResultMessage) and message.subtype == "success":
            print(message.result)


asyncio.run(main())

错误处理

MCP 服务器可能因各种原因连接失败:服务器进程可能没安装、凭据可能无效,或远程服务器可能不可达。Claude Code 在每次查询开始时发出 subtype 为 init 的 system 消息,该消息包含每个 MCP 服务器的连接状态。status 字段可以是 "pending"、"connected"、"failed"、"needs-auth" 或 "disabled"。Claude Code 对经 options.mcpServers 传入的服务器在第一个轮次的连接等待之后才发出 init 消息,所以在该等待内连接上的这种服务器显示 "connected"。

在 init 消息里,不要仅凭 "pending" 就把它当作失败,它可能意味着:服务器还没连接(见 Claude Code 在第一个轮次之前等它多久);服务器的工具列表来自缓存,连接在首次使用时建立;连接截止时间已过期(这样的服务器根据时机报告 "pending" 或 "failed")。检查 "failed" 或 "needs-auth" 来发现不可用的服务器:

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

try {
  for await (const message of query({
    prompt: "Process data",
    options: {
      mcpServers: {
        // 把 dataServer 换成你的服务器配置
        "data-processor": dataServer
      }
    }
  })) {
    if (message.type === "system" && message.subtype === "init") {
      const unavailableServers = message.mcp_servers.filter(
        (s) => s.status === "failed" || s.status === "needs-auth"
      );

      if (unavailableServers.length > 0) {
        console.warn("Unavailable MCP servers:", unavailableServers);
      }
    }

    if (message.type === "result" && message.subtype === "error_during_execution") {
      console.error("Execution failed");
    }
  }
} catch (error) {
  // 单次 query() 在产出错误结果之后抛出。如果失败是错误结果,
  // 上面的错误 subtype 分支已经运行过了;无法启动或到达 Claude Code
  // 进程的失败不产生结果消息。连接失败的 MCP 服务器不会抛出:
  // 用上面的状态检查,并注意在 init 时仍为 "pending" 的服务器
  // 需要之后再检查状态。
  console.log(`Session ended with an error: ${error}`);
}
import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions, SystemMessage, ResultMessage


async def main():
    # 把 data_server 换成你的服务器配置
    options = ClaudeAgentOptions(mcp_servers={"data-processor": data_server})

    try:
        async for message in query(prompt="Process data", options=options):
            if isinstance(message, SystemMessage) and message.subtype == "init":
                unavailable_servers = [
                    s
                    for s in message.data.get("mcp_servers", [])
                    if s.get("status") in ("failed", "needs-auth")
                ]

                if unavailable_servers:
                    print(f"Unavailable MCP servers: {unavailable_servers}")

            if (
                isinstance(message, ResultMessage)
                and message.subtype == "error_during_execution"
            ):
                print("Execution failed")
    except Exception as error:
        # 单次 query() 在产出错误结果之后抛出。如果失败是错误结果,
        # 上面的错误 subtype 分支已经运行过了;无法启动或到达 Claude Code
        # 进程的失败不产生结果消息。连接失败的 MCP 服务器不会抛出:
        # 用上面的状态检查,并注意在 init 时仍为 "pending" 的服务器
        # 需要之后再检查状态。
        print(f"Session ended with an error: {error}")


asyncio.run(main())

远程服务器的状态在它报告 "connected" 之后也可能变化:到它的连接在会话中途断开时,Claude Code 在重连期间把该服务器移回 "pending";之后在 TypeScript 里调用 mcpServerStatus(),或在 Python 里调用 ClaudeSDKClient.get_mcp_status(),可能对你之前看到已连接的服务器报告 "pending",而你这边没有任何配置变化。五次重连尝试都失败之后,该服务器报告 "failed",需要重新授权时报告 "needs-auth"。要手动重试,在 TypeScript 里调用 reconnectMcpServer(),或在 Python 里调用 ClaudeSDKClient.reconnect_mcp_server()。

排障

服务器显示 "failed" 状态

检查 init 消息,看哪些服务器连接失败:

if (message.type === "system" && message.subtype === "init") {
  for (const server of message.mcp_servers) {
    if (server.status === "failed") {
      console.error(`Server ${server.name} failed to connect`);
    }
  }
}
if isinstance(message, SystemMessage) and message.subtype == "init":
    for server in message.data.get("mcp_servers", []):
        if server.get("status") == "failed":
            print(f"Server {server['name']} failed to connect")

"pending" 状态不表示服务器失败(init 时它涵盖的情形见「错误处理」)。要在会话稍后获得更新的状态,在 TypeScript SDK 里调用查询的 mcpServerStatus() 方法,或在 Python 里调用 ClaudeSDKClient.get_mcp_status()。常见原因:

  • 缺少环境变量:确保设置了所需的令牌和凭据;对 stdio 服务器,检查 env 字段与服务器期望的匹配。
  • 服务器未安装:对 npx 命令,验证包存在且 Node.js 在你的 PATH 里。
  • 无效的连接串:对数据库服务器,验证连接串格式以及数据库可访问。
  • 网络问题:对远程 HTTP/SSE 服务器,检查 URL 可达以及任何防火墙允许该连接。

工具没有被调用

如果 Claude 看到了工具但不使用它们,检查你是否用 allowedTools 授予了权限:

const options = {
  mcpServers: {
    // 你的服务器
  },
  allowedTools: ["mcp__servername__*"] // 自动批准来自该服务器的调用
};
options = ClaudeAgentOptions(
    mcp_servers={
        # 你的服务器
    },
    allowed_tools=["mcp__servername__*"],  # 自动批准来自该服务器的调用
)

连接超时

MCP 服务器连接默认在 30 秒后超时。要更改一个运行中的工具调用可以持续多久,设 MCP_TOOL_TIMEOUT。如果你的服务器启动更慢,连接会失败;用环境变量 MCP_TIMEOUT(毫秒)提高连接限制。对需要更多启动时间的服务器,还可以考虑:使用更轻量的服务器(如果有);在启动你的智能体之前预热服务器;检查服务器日志里初始化缓慢的原因。在 TypeScript 里,可以通过向 createSdkMcpServer() 传 timeout 来设置单个 SDK MCP 服务器的工具调用限制。

工具输出超过允许的最大 token 数

SDK 应用与 Claude Code 相同的 MCP 输出限制。当没有图片内容的工具结果大于 25,000 个 token 时,Claude Code 把输出保存到文件,并把工具结果替换成点名文件路径的错误消息,使智能体能分段读回输出。用 MAX_MCP_OUTPUT_TOKENS 环境变量提高限制(完整行为见「MCP 输出限制与警告」,包括服务器如何用 anthropic/maxResultSizeChars 注解声明更高的每工具限制)。

相关资源

  • 自定义工具指南:构建与你的 SDK 应用一起在进程内运行的 MCP 服务器
  • 权限:用 allowedTools 和 disallowedTools 控制你的智能体能使用哪些 MCP 工具
  • TypeScript SDK 参考:完整的 API 参考,包括 MCP 配置选项
  • Python SDK 参考:完整的 API 参考,包括 MCP 配置选项
  • MCP 服务器目录:浏览适用于数据库、API 等的可用 MCP 服务器