Claude Code Agent SDK 的 MCP 工具命名规范(详解为何权限控制依赖该规范)

Claude Code Agent SDK 把 MCP 工具的名字统一拼接为 mcp__{server_name}__{tool_name},双下划线是固定分隔符,非法字符会被替换为下划线。该规范直接决定了 SDK 能否在多服务器场景下精准定位工具、并把白名单/黑名单规则命中到正确的工具实例上——名字一旦错位,权限控制就会形同虚设。

一、命名规范本身

1.1 格式定义

官方文档给出明确的拼装规则:服务器名与工具名之间使用双下划线 __ 作为分隔符,工具名遵循 mcp__{server_name}__{tool_name} 的三段式结构。例如 weather 服务器里名为 get_temperature 的工具,暴露给 Claude 时就变成 mcp__weather__get_temperature。多个服务器同时挂载时,这一前缀保证 get_temperature、search、query 这类常见名字不会互相覆盖。

1.2 字符归一化

服务器名与工具名在拼装前会做归一化处理,只保留 a-z、A-Z、0-9、_、- 几类字符,其他符号(包括空格、点号、斜杠)都会被替换为下划线。这样做的好处是命名在配置文件、权限规则、日志里都能被直接复制粘贴,不需要转义;代价是同名相近的服务器可能被压成同一个名字,所以命名阶段就要避免重名。

1.3 与其它 SDK 的差异

同样是 MCP 生态,Claude Agent SDK 用 __ 双下划线,而社区一些实现(如 Spring AI 的 Claude Agent SDK Java 教程)使用单下划线 {server}_{tool}。二者各有好处:双下划线在文本里更易一眼看出边界,单下划线更紧凑。Claude Code 自身的插件、内置工具、SDK 一律遵循 mcp__xxx__yyy 形式,自定义 MCP 服务器若改了前缀,反而会让 allowedTools、disallowedTools 规则无法命中。

二、命名规范如何决定权限控制

2.1 三层控制机制

Claude Code 的工具访问分两层:可用性(availability)与权限(permission)。前者决定工具是否出现在 Claude 上下文里,后者决定 Claude 调用时是否被放行。MCP 工具的名字正是这两层规则的命中键。

控制层 配置项 对 MCP 工具的影响 行为
可用性 tools: ["Read","Grep"] 不影响 MCP 工具 只裁剪内置工具
可用性 tools: [] 不影响 MCP 工具 移除全部内置工具,仅留 MCP
可用性 disallowedTools: ["Bash"] 裸名匹配,按前缀同样有效 把 MCP 工具从上下文删除
权限 allowedTools: ["mcp__weather__get_temperature"] 作用域匹配 调用时跳过权限提示
权限 disallowedTools: ["mcp__weather__*"] 作用域匹配 命中调用直接拒绝,但工具仍可见

可以看到,权限规则全部基于工具全名生效。一旦 mcp__<server>__<tool> 在不同服务器间出现重名,规则会同时命中多台服务器,可能造成”想放开 A,结果放开了 B”的越权。

2.2 一个真实的踩坑

团队在引入两个 MCP 服务器 github 与 gitlab 时,都各自带了一个叫 search 的工具。Claude Code 会自动拼成 mcp__github__search 与 mcp__gitlab__search,互不冲突。但如果其中一台服务器名里带点(比如 git.hub),归一化后变成 mcp__git_hub__search,与另一个叫 git_hub 的服务器撞名,权限规则就会同时影响两台服务器。命名阶段在 server_name 里就避开点、空格,是规避这类问题的最稳妥手段。

三、配合 disallowedTools 的最小规则集

3.1 按命名空间批量拒绝

利用前缀 * 通配,可以一次禁掉某台服务器的全部工具或某种类型。常见做法是先把所有 MCP 工具加进上下文,再用 disallowedTools: ["mcp__*__delete_*"] 之类规则守住危险操作。

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

const options: ClaudeAgentOptions = {
  mcpServers: {
    filesystem: { command: "npx", args: ["@modelcontextprotocol/server-filesystem"] },
    weather:    { command: "npx", args: ["@modelcontextprotocol/server-weather"] },
  },
  allowedTools: [
    "mcp__filesystem__read_file",
    "mcp__filesystem__list_directory",
    "mcp__weather__get_temperature",
  ],
  disallowedTools: [
    // 作用域规则:匹配所有 mcp 工具里名字含 delete 的调用
    "mcp__*__delete_*",
  ],
};

for await (const message of query({ prompt: "列出当前目录", options })) {
  // ...
}

3.2 规则生效顺序

Claude Code 在评估一次工具调用时,先看 disallowedTools 中是否有作用域规则命中——命中即拒绝;再看 allowedTools 是否有精准匹配——命中即放行;都没有则进入默认的权限提示流程。命名规范稳定的前提下,这条链路是可预期的;一旦名字拼错,整条链路都会偏移到不期望的工具上。

四、为什么这套规范对权限控制至关重要

权限规则本质上是字符串匹配。匹配的目标字符串一旦由”服务器名 + 工具名”决定,命名规范就成了整个权限模型的”坐标轴”:

  1. 全局唯一性:双下划线 + 归一化规则让工具全名在全局内互不重复,避免”放开 A 误放 B”。
  2. 可读性:日志、配置文件、用户审查界面里,mcp__weather__get_temperature 一眼能定位到来源。
  3. 可表达性:* 通配配合命名空间,能用一行规则禁掉一类操作(如所有 delete_*、所有 *__admin_*),比逐个列举省心。
  4. 可审计性:当规则出现”明明没放行却调通了”的情况,第一反应就是核对服务器名是否被归一化掉、名字是否撞车。

常见问题(FAQ)

Q1:自定义 MCP 服务器必须使用 mcp__ 前缀吗?

不是。前缀是 Claude Code 在注册阶段自动加上的,工具开发者只在 server_name 与工具本地名字上保持简洁清晰即可,避免特殊字符。

Q2:allowedTools 写错了会怎么样?

写错名字(拼写、归一化后不一致)不会报错,只会被视作”没有匹配项”,调用走默认权限流程,体感是”规则没生效”。

Q3:能用一个规则同时禁掉多台服务器的同种工具吗?

可以。disallowedTools: ["mcp__*__delete_*"] 这种通配写法会命中所有服务器里以 delete_ 开头的工具。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 qiqicto@qq.com 举报,一经查实,本站将立刻删除。
赞 (0)
其AI的头像其AI普通用户

相关推荐

返回顶部