
MCP 是 Claude Code SDK 把 Agent 能力边界从「内置 11 工具」扩展到任意外部服务的核心机制。本篇完整拆解三种传输方式的选型逻辑(stdio/HTTP-SSE/SDK内嵌)、工具命名规范 mcp__<server>__<tool>、allowedTools 与 permissionMode 的对比、三种认证方式、连接状态检测,以及大量工具时的 Tool Search 懒加载机制,附 Python/TypeScript 完整代码示例和五条实践建议。
permissionMode 的对比,以及大量工具时必须理解的 Tool Search 懒加载机制。tool_use 块、调用外部 API、把结果塞回 tool_result。MCP 把这套胶水代码变成了一个标准接口:你只需要配置服务器地址,SDK 自动处理工具发现和执行。2npx 启动即用。mcp__<服务器名>__<工具名>github,它提供了 list_issues 工具,那这个工具在 allowedTools 里的写法就是 mcp__github__list_issues。mcp__github__* 表示开放该服务器的全部工具,不需要逐一列举。
npx @modelcontextprotocol/server-github)→ 用 stdio# Python
from claude_agent_sdk import query, ClaudeAgentOptions
async for message in query(
prompt="列出 anthropics/claude-code 最近 3 个 Issues",
options=ClaudeAgentOptions(
mcp_servers={
"github": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"],
"env": {"GITHUB_TOKEN": os.environ["GITHUB_TOKEN"]}
}
},
allowed_tools=["mcp__github__list_issues"]
)
):
...// TypeScript
for await (const message of query({
prompt: "列出最近 3 个 Issues",
options: {
mcpServers: {
github: {
command: "npx",
args: ["-y", "@modelcontextprotocol/server-github"],
env: { GITHUB_TOKEN: process.env.GITHUB_TOKEN }
}
},
allowedTools: ["mcp__github__list_issues"]
}
})) { ... }options=ClaudeAgentOptions(
mcp_servers={
"remote-api": {
"type": "sse", # 或 "http" 用于 Streamable HTTP
"url": "https://api.example.com/mcp/sse",
"headers": {
"Authorization": f"Bearer {os.environ['API_TOKEN']}"
}
}
},
allowed_tools=["mcp__remote-api__*"]
).mcp.json)里可以用 "streamable-http" 作为 "http" 的别名,但代码里只接受 "http"。混淆这两者会导致连接静默失败。@tool 装饰器直接在 Python 代码里定义工具,不需要启动额外进程——开发调试时非常实用:from claude_agent_sdk import tool, create_sdk_mcp_server
@tool("query_db", "按自然语言查询数据库", {"question": str})
async def query_db(args):
sql = translate_to_sql(args["question"])
result = await db.execute(sql)
return {"content": [{"type": "text", "text": str(result)}]}
my_server = create_sdk_mcp_server(
name="db-tools",
tools=[query_db]
)
options = ClaudeAgentOptions(
mcp_servers={"db": my_server},
allowed_tools=["mcp__db__query_db"]
)create_sdk_mcp_server() 返回 McpSdkServerConfig(type="sdk"),直接传给 mcp_servers 即可。
allowedTools 精确授权而非宽泛的权限模式 4| 方式 | 对 MCP 的实际效果 | 问题 |
|---|---|---|
acceptEdits | 不会自动放通 MCP 工具 | 只作用于文件编辑和 Bash 命令 |
bypassPermissions | 会放通 MCP 工具 | 同时跳过所有其他安全检查,范围太大 |
allowedTools 通配符 | 精准放通目标服务器 | ✅ 推荐方式 |
allowedTools 配合通配符:allowed_tools=["mcp__github__*"] # 只开放 github 服务器
allowed_tools=["mcp__db__query"] # 只开放 db 服务器的 query 工具system init 消息里看到所有可用工具,但只有 allowedTools 里列出的才能不经审批直接调用。.mcp.json 里可以用 ${VAR_NAME} 语法引用运行时环境变量:{
"mcpServers": {
"github": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"],
"env": {
"GITHUB_TOKEN": "${GITHUB_TOKEN}"
}
}
}
}headers 字段传认证信息:mcp_servers={
"secure-api": {
"type": "http",
"url": "https://api.example.com/mcp",
"headers": {"Authorization": f"Bearer {token}"}
}
}access_token = await complete_oauth_flow()
mcp_servers={
"oauth-api": {
"type": "http",
"url": "https://api.example.com/mcp",
"headers": {"Authorization": f"Bearer {access_token}"}
}
}async for message in query(prompt="...", options=options):
# 检查连接状态
if hasattr(message, 'subtype') and message.subtype == "init":
servers = message.data.get("mcp_servers", [])
failed = [s for s in servers if s.get("status") != "connected"]
if failed:
print(f"连接失败: {failed}")
break
if hasattr(message, 'result'):
print(message.result)if (message.type === "system" && message.subtype === "init") {
const failed = message.mcp_servers.filter(s => s.status !== "connected");
if (failed.length > 0) console.warn("Failed:", failed);
}ClaudeSDKClient 还提供了两个动态方法:get_mcp_status():随时获取所有服务器的连接状态reconnect_mcp_server(name):对失败的服务器触发重连toggle_mcp_server(name, enabled):在会话中动态启停某个服务器ClaudeAgentOptions(
mcp_servers={ ... },
env={
# auto:5 = 工具定义超过上下文窗口 5% 时启动懒加载
"ENABLE_TOOL_SEARCH": "auto:5"
}
)ENABLE_TOOL_SEARCH 值 | 效果 |
|---|---|
| 未设置(默认) | 开启,在 Vertex AI 和非官方代理上回退为全量加载 |
true | 强制开启(即使在 Vertex AI) |
auto | 超过上下文 10% 时自动开启 |
auto:N | 超过 N% 时开启 |
false | 关闭,全量加载所有工具定义 |
search_slack_messages 比 query_slack 匹配范围更广,描述写"按关键词、频道或日期搜索 Slack 消息"比"查询 Slack"精确得多。system init 消息里读:async for message in query(prompt="...", options=options):
if hasattr(message, 'subtype') and message.subtype == "init":
mcp_info = message.data.get("mcp_servers", [])
for server in mcp_info:
print(f"服务器: {server['name']}")
for tool in server.get('tools', []):
print(f" - {tool['name']}: {tool.get('description', '')}")ClaudeSDKClient 还可以在会话中随时调用 get_mcp_status() 获取每个服务器的工具列表和连接状态。mcp__*__* 通配符一次放通所有 MCP 工具。对每个服务器单独配置通配符(mcp__github__*),或精确到工具名(mcp__db__query),便于审计和限制意外调用。init 消息里检查连接状态,而不是等到任务失败时才发现服务器没接上。allowedTools 的精细配置,可以让 Agent 只拥有读权限的工具(比如 mcp__db__query),而不开放写操作(mcp__db__execute)。这和上一篇子 Agent 里工具最小化的原则一致。print(message.data.get("mcp_servers")) 加进去,确认服务器已连接、工具列表符合预期,再开始测试实际功能。ENABLE_TOOL_SEARCH=auto 跑一下,观察是否自动触发。如果工具定义较重,适当降低阈值(auto:5)。@tool 装饰器在 SDK 内嵌入你自己的工具函数,以及如何用 in-process MCP 服务器在代码里定义完整工具集。文档入口:https://docs.anthropic.com/en/docs/agent-sdk/custom-toolsdocs.anthropic.com
docs.anthropic.com
docs.anthropic.com
docs.anthropic.com
docs.anthropic.com
docs.anthropic.com
This story was produced automatically by a channel. One sentence is all it takes for Neodrop to keep producing for you.