- 首页
- Documentation
- MCP
- MCP 服务器与工具编写
MCP 服务器与工具编写
本文档介绍 MCP 服务器定义如何在 coding-agent 中转化为可调用的 mcp_* 工具,以及当配置无效、重复、禁用或受认证限制时,运维人员应有何预期。
Config sources (.xcsh/.claude/.cursor/.vscode/mcp.json, mcp.json, etc.) -> discovery providers normalize to canonical MCPServer -> capability loader dedupes by server name (higher provider priority wins) -> loadAllMCPConfigs converts to MCPServerConfig + skips enabled:false -> MCPManager connects/listTools (with auth/header/env resolution) -> MCPTool/DeferredMCPTool bridge exposes tools as mcp_<server>_<tool> -> AgentSession.refreshMCPTools replaces live MCP tools immediately1) 服务器配置模型与验证
Section titled “1) 服务器配置模型与验证”src/mcp/types.ts 定义了 MCP 配置编写者和运行时使用的编写模型:
stdio(type缺省时的默认值):需要command,可选args、env、cwdhttp:需要url,可选headerssse:需要url,可选headers(为兼容性保留)- 共享字段:
enabled、timeout、auth
validateServerConfig()(src/mcp/config.ts)执行传输层基本验证:
- 拒绝同时设置
command和url的配置 - stdio 要求提供
command - http/sse 要求提供
url - 拒绝未知的
type
config-writer.ts 在添加/更新操作时应用此验证,同时验证服务器名称:
- 非空
- 最多 100 个字符
- 仅允许
[a-zA-Z0-9_.-]
传输层注意事项
Section titled “传输层注意事项”- 省略
type意味着 stdio。如果你原本打算使用 HTTP/SSE 但省略了type,则command变为必填项。 sse仍然被接受,但在内部作为 HTTP 传输处理(createHttpTransport)。- 验证是结构性的,而非可达性验证:语法上合法的 URL 在连接时仍可能失败。
2) 发现、规范化与优先级
Section titled “2) 发现、规范化与优先级”基于能力的发现
Section titled “基于能力的发现”loadAllMCPConfigs()(src/mcp/config.ts)通过 loadCapability(mcpCapability.id) 加载规范的 MCPServer 项。
能力层(src/capability/index.ts)随后:
- 按优先级顺序加载提供者
- 按
server.name去重(先到先得 = 最高优先级) - 验证去重后的项
结果:跨来源的重复服务器名称不会合并。只有一个定义生效;较低优先级的重复项将被遮蔽。
.mcp.json 及相关文件
Section titled “.mcp.json 及相关文件”src/discovery/mcp-json.ts 中的专用回退提供者读取项目根目录的 mcp.json 和 .mcp.json(低优先级)。
实际上 MCP 服务器也来自更高优先级的提供者(例如原生 .xcsh/... 和工具特定的配置目录)。编写建议:
- 优先使用
.xcsh/mcp.json(项目级)或~/.xcsh/mcp.json(用户级)以获得明确控制。 - 当需要回退兼容性时使用根目录
mcp.json/.mcp.json。 - 在多个来源中使用相同的服务器名称会导致优先级遮蔽,而非合并。
convertToLegacyConfig()(src/mcp/config.ts)将规范的 MCPServer 映射为运行时 MCPServerConfig。
关键行为:
- 传输类型推断为
server.transport ?? (command ? "stdio" : url ? "http" : "stdio") - 已禁用的服务器(
enabled === false)在连接前被丢弃 - 可选字段存在时予以保留
发现过程中的环境变量展开
Section titled “发现过程中的环境变量展开”mcp-json.ts 使用 expandEnvVarsDeep() 展开字符串字段中的环境变量占位符:
- 支持
${VAR}和${VAR:-default} - 未解析的值保持为字面量
${VAR}字符串
mcp-json.ts 还对用户 JSON 执行运行时类型检查,并对无效的 enabled/timeout 值记录警告,而非导致整个文件加载失败。
3) 认证与运行时值解析
Section titled “3) 认证与运行时值解析”MCPManager.prepareConfig()/#resolveAuthConfig()(src/mcp/manager.ts)是连接前的最终处理环节。
OAuth 凭据注入
Section titled “OAuth 凭据注入”如果配置包含:
auth: { type: "oauth", credentialId: "..." }且凭据存在于认证存储中:
http/sse:注入Authorization: Bearer <access_token>请求头stdio:注入OAUTH_ACCESS_TOKEN环境变量
如果凭据查找失败,管理器会记录警告并在未解析认证的情况下继续运行。
请求头/环境变量值解析
Section titled “请求头/环境变量值解析”连接前,管理器通过 resolveConfigValue()(src/config/resolve-config-value.ts)解析每个请求头/环境变量值:
- 以
!开头的值 => 执行 shell 命令,使用修剪后的 stdout(有缓存) - 否则,首先将值视为环境变量名(
process.env[name]),回退为字面值 - 未解析的命令/环境变量值将从最终的 headers/env 映射中省略
运维注意事项:这意味着拼写错误的密钥命令/环境变量名可能会静默移除该请求头/环境变量条目,导致下游 401/403 或服务器启动失败。
4) 工具桥接:MCP -> 代理可调用工具
Section titled “4) 工具桥接:MCP -> 代理可调用工具”src/mcp/tool-bridge.ts 将 MCP 工具定义转换为 CustomTool。
命名与冲突域
Section titled “命名与冲突域”工具名称生成规则为:
mcp_<sanitized_server_name>_<sanitized_tool_name>规则:
- 转为小写
- 非
[a-z_]字符变为_ - 重复的下划线合并
- 工具名称中冗余的
<server>_前缀被剥离一次
这避免了许多冲突,但并非全部。不同的原始名称仍可能清理为相同的标识符(例如 my-server 和 my.server 清理后相似),且注册表插入采用后写覆盖策略。
Schema 映射
Section titled “Schema 映射”convertSchema() 基本保持 MCP JSON Schema 不变,但为缺少 properties 的对象 schema 补充 {} 以确保提供者兼容性。
MCPTool.execute() / DeferredMCPTool.execute():
- 调用 MCP
tools/call - 将 MCP 内容扁平化为可展示的文本
- 返回结构化详情(
serverName、mcpToolName、提供者元数据) - 将服务器报告的
isError映射为Error: ...文本结果 - 将抛出的传输/运行时故障映射为
MCP error: ... - 通过将 AbortError 转换为
ToolAbortError保留中止语义
5) 运维生命周期:添加/编辑/删除与实时更新
Section titled “5) 运维生命周期:添加/编辑/删除与实时更新”交互模式在 src/modes/controllers/mcp-command-controller.ts 中暴露 /mcp 命令。
支持的操作:
add(向导或快速添加)remove/rmenable/disabletestreauth/unauthreload
配置写入是原子性的(writeMCPConfigFile:临时文件 + 重命名)。
更改后,控制器调用 #reloadMCP():
mcpManager.disconnectAll()mcpManager.discoverAndConnect()session.refreshMCPTools(mcpManager.getTools())
refreshMCPTools() 替换所有 mcp_ 注册表条目并立即重新激活最新的 MCP 工具集,因此更改无需重启会话即可生效。
- 交互/TUI 模式:
/mcp提供应用内用户体验(向导、OAuth 流程、连接状态文本、即时运行时重绑定)。 - SDK/无头集成:
discoverAndLoadMCPTools()(src/mcp/loader.ts)返回已加载的工具 + 按服务器的错误信息;无/mcp命令用户体验。
6) 用户可见的错误信息
Section titled “6) 用户可见的错误信息”用户/运维人员常见的错误字符串:
- 添加/更新验证失败:
Invalid server config: ...Server "<name>" already exists in <path>
- 快速添加参数问题:
Use either --url or -- <command...>, not both.--token requires --url (HTTP/SSE transport).
- 连接/测试失败:
Failed to connect to "<name>": <message>- 超时帮助文本建议增加超时时间
401/403的认证帮助文本
- 认证/OAuth 流程:
Authentication required ... OAuth endpoints could not be discoveredOAuth flow timed out. Please try again.OAuth authentication failed: ...
- 使用已禁用的服务器:
Server "<name>" is disabled. Run /mcp enable <name> first.
发现过程中格式错误的源 JSON 通常以警告/日志形式处理;config-writer 路径会抛出明确的错误。
7) 实用编写指南
Section titled “7) 实用编写指南”在此代码库中进行可靠的 MCP 编写:
- 在所有支持 MCP 的配置来源中保持服务器名称全局唯一。
- 优先使用字母数字/下划线名称,以避免生成的
mcp_*工具名称中出现清理后的命名冲突。 - 使用显式
type以避免意外的 stdio 默认行为。 - 将
enabled: false视为硬关闭:服务器将从运行时连接集合中省略。 - 对于 OAuth 配置,存储有效的
credentialId;否则认证注入将被跳过。 - 如果使用基于命令的密钥解析(
!cmd),请验证命令输出是稳定且非空的。