MCP 协议
MCP(Model Context Protocol)是由 Anthropic 提出的开放标准协议,用于连接 AI 模型与外部工具和数据源。MateClaw 实现了完整的 MCP 客户端,支持动态发现和调用外部 MCP 服务器暴露的工具,使 Agent 能够像使用内置工具一样使用第三方能力,无需编写额外代码。
什么是 MCP
MCP 采用客户端-服务器架构,基于 JSON-RPC 2.0 进行通信:
┌───────────────────────┐ ┌───────────────────────┐
│ MateClaw │ │ MCP Server │
│ (MCP Client) │ │ (工具提供方) │
│ │ JSON-RPC │ │
│ Agent Engine ───────┼──────────────┼──► Tool A │
│ │ │ Tool B │
│ Tool Registry ◄──────┼──────────────┼─── Tool Discovery │
│ │ │ (tools/list) │
└───────────────────────┘ └───────────────────────┘核心概念:
- MCP Client:MateClaw 作为客户端,负责连接 MCP 服务器、发现工具、转发工具调用请求
- MCP Server:第三方工具服务器,声明自身提供的工具列表,接收并执行工具调用
- Tool Discovery:客户端通过
tools/list请求获取服务器暴露的所有工具及其参数 schema - Tool Invocation:Agent 推理过程中决定调用某工具时,客户端将请求转发给对应 MCP 服务器执行
通过 MCP,MateClaw 可以在不修改代码、不重启服务的情况下,动态接入新的工具能力。
传输类型
MateClaw 支持三种 MCP 传输方式,适用于不同的部署场景:
stdio(标准输入输出)
通过子进程的 stdin/stdout 管道通信。MateClaw 会启动一个本地子进程作为 MCP 服务器,通过标准输入输出交换 JSON-RPC 消息。
MateClaw ── stdin ──► MCP Server 子进程
◄─ stdout ──适用场景:
- 本地 Node.js/Python MCP 工具包(如
@anthropic/mcp-filesystem) - 命令行工具封装
- 开发调试阶段
优点:无需网络配置,启动即用,进程隔离 限制:仅支持本地部署,MateClaw 必须能直接执行指定命令
streamable_http(Streamable HTTP)
MCP 协议最新推荐的 HTTP 传输方式。使用标准 HTTP POST 请求发送 JSON-RPC,响应通过 HTTP 流式返回。
MateClaw ── HTTP POST ──► 远程 MCP Server
◄─ HTTP Stream ──适用场景:
- 云端部署的 MCP 服务器
- 需要负载均衡或反向代理的场景
- 生产环境推荐使用
优点:标准 HTTP 协议,兼容各类网络基础设施(CDN、负载均衡、防火墙),支持认证头 限制:需要服务器支持 Streamable HTTP 传输
sse(Server-Sent Events)
早期 MCP HTTP 传输方式,使用 SSE 进行服务器到客户端的推送。
MateClaw ── HTTP POST ──► 远程 MCP Server
◄─── SSE ────────适用场景:
- 兼容仅支持 SSE 传输的旧版 MCP 服务器
- 当远端服务器尚未升级到 Streamable HTTP 时使用
优点:兼容性好,许多现有 MCP 服务器仍使用此传输方式 限制:已被 Streamable HTTP 逐步替代,新项目建议优先使用 streamable_http
传输类型对比
| 特性 | stdio | streamable_http | sse |
|---|---|---|---|
| 部署位置 | 仅本地 | 本地或远程 | 本地或远程 |
| 网络要求 | 无 | HTTP 可达 | HTTP 可达 |
| 认证支持 | 环境变量传递 | HTTP Headers | HTTP Headers |
| 进程管理 | MateClaw 管理子进程 | 外部管理 | 外部管理 |
| 推荐程度 | 本地工具首选 | 远程服务首选 | 兼容旧版 |
通过管理界面配置
添加 MCP 服务器
- 登录 MateClaw 管理界面
- 进入「工具管理」页面
- 切换到「MCP 服务器」标签页
- 点击「添加 MCP 服务器」按钮
- 填写配置表单:
- 名称:服务器唯一标识(仅允许字母、数字、下划线、连字符、点和空格,1-128 字符)
- 描述:可选,说明该服务器的用途
- 传输类型:选择
stdio、streamable_http或sse - 命令(stdio):启动 MCP 服务器的命令,如
npx、node、python - 参数(stdio):JSON 数组格式的命令行参数,如
["-y", "@anthropic/mcp-filesystem", "/path"] - 工作目录(stdio):可选,命令执行的工作目录
- 环境变量(stdio):JSON 对象格式,如
{"API_KEY": "xxx"},支持${ENV_VAR}引用系统环境变量 - URL(streamable_http/sse):MCP 服务器端点地址
- HTTP 请求头(streamable_http/sse):JSON 对象格式,如
{"Authorization": "Bearer token"} - 连接超时:连接建立超时时间,默认 30 秒
- 读取超时:请求响应超时时间,默认 30 秒
- 点击「保存」
保存后,如果服务器处于启用状态,MateClaw 会自动尝试连接并发现工具。
测试连接
在 MCP 服务器列表中,点击某个服务器的「测试连接」按钮。测试连接会:
- 尝试建立到 MCP 服务器的连接
- 发送
tools/list请求发现可用工具 - 返回连接结果(成功/失败)、延迟时间、发现的工具列表
- 测试连接不会影响当前活跃的连接
启用与禁用
每个 MCP 服务器都有独立的启用/禁用开关:
- 启用:MateClaw 会建立连接,发现的工具可被 Agent 调用
- 禁用:断开连接,该服务器的工具不再可用,但配置保留
查看连接状态
MCP 服务器列表显示每个服务器的实时状态:
- connected:已连接,工具可用
- disconnected:已断开(手动禁用或尚未连接)
- error:连接失败,可查看错误信息
通过 REST API 配置
MCP 服务器的完整 CRUD 操作通过 /api/v1/mcp/servers 接口提供。所有接口需要 JWT 认证。
查询所有 MCP 服务器
curl -s http://localhost:18088/api/v1/mcp/servers \
-H "Authorization: Bearer <token>" | jq返回示例:
{
"code": 200,
"data": [
{
"id": "1",
"name": "filesystem",
"transport": "stdio",
"command": "npx",
"argsJson": "[\"-y\", \"@anthropic/mcp-filesystem\", \"/home/user\"]",
"enabled": true,
"lastStatus": "connected",
"toolCount": 5,
"lastConnectedTime": "2026-04-01T10:30:00"
}
]
}注意:返回的 headersJson 和 envJson 字段中的值会被脱敏处理(如 sk-****abcd),以保护敏感信息。
查询单个 MCP 服务器
curl -s http://localhost:18088/api/v1/mcp/servers/{id} \
-H "Authorization: Bearer <token>"创建 MCP 服务器(stdio 类型)
curl -X POST http://localhost:18088/api/v1/mcp/servers \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <token>" \
-d '{
"name": "filesystem",
"description": "文件系统读写工具",
"transport": "stdio",
"command": "npx",
"argsJson": "[\"-y\", \"@anthropic/mcp-filesystem\", \"/home/user/workspace\"]",
"enabled": true
}'创建 MCP 服务器(streamable_http 类型)
curl -X POST http://localhost:18088/api/v1/mcp/servers \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <token>" \
-d '{
"name": "remote-tools",
"description": "远程工具服务",
"transport": "streamable_http",
"url": "https://mcp.example.com/mcp",
"headersJson": "{\"Authorization\": \"Bearer your-api-key\"}",
"connectTimeoutSeconds": 15,
"readTimeoutSeconds": 60,
"enabled": true
}'更新 MCP 服务器
使用 PATCH 语义 -- 仅传入需要修改的字段,未传入的字段保持不变:
curl -X PUT http://localhost:18088/api/v1/mcp/servers/{id} \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <token>" \
-d '{
"description": "更新后的描述",
"readTimeoutSeconds": 60
}'更新后,如果服务器处于启用状态,会自动重新连接。
删除 MCP 服务器
curl -X DELETE http://localhost:18088/api/v1/mcp/servers/{id} \
-H "Authorization: Bearer <token>"删除前会自动断开连接。注意:标记为 builtin 的内置服务器不允许删除。
启用/禁用 MCP 服务器
# 禁用
curl -X PUT "http://localhost:18088/api/v1/mcp/servers/{id}/toggle?enabled=false" \
-H "Authorization: Bearer <token>"
# 启用
curl -X PUT "http://localhost:18088/api/v1/mcp/servers/{id}/toggle?enabled=true" \
-H "Authorization: Bearer <token>"测试连接
curl -X POST http://localhost:18088/api/v1/mcp/servers/{id}/test \
-H "Authorization: Bearer <token>"返回示例:
{
"code": 200,
"data": {
"success": true,
"message": "Connected",
"toolCount": 5,
"latencyMs": 1234,
"discoveredTools": ["read_file", "write_file", "list_directory", "search_files", "get_file_info"],
"timestamp": "2026-04-01T10:30:00"
}
}刷新所有连接
断开所有现有连接,重新连接所有已启用的 MCP 服务器:
curl -X POST http://localhost:18088/api/v1/mcp/servers/refresh \
-H "Authorization: Bearer <token>"实战示例
示例一:文件系统 MCP 服务器(stdio)
使用 Anthropic 官方提供的文件系统 MCP 服务器,让 Agent 具备读写文件、搜索目录的能力。
前置条件:服务器上已安装 Node.js(v18+)和 npm。
通过 API 创建:
curl -X POST http://localhost:18088/api/v1/mcp/servers \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <token>" \
-d '{
"name": "filesystem",
"description": "文件系统读写(限制在指定目录内)",
"transport": "stdio",
"command": "npx",
"argsJson": "[\"-y\", \"@anthropic/mcp-filesystem\", \"/home/user/workspace\"]",
"enabled": true
}'连接成功后将发现以下工具:
| 工具名 | 说明 |
|---|---|
read_file | 读取文件内容 |
write_file | 写入文件 |
list_directory | 列出目录内容 |
search_files | 搜索文件 |
get_file_info | 获取文件元信息 |
安全提示:@anthropic/mcp-filesystem 只允许访问启动参数中指定的目录及其子目录,不会泄露系统其他文件。
示例二:远程 HTTP MCP 服务器(streamable_http + 认证)
连接一个需要 API Key 认证的远程 MCP 服务器,例如企业内部的数据查询服务。
curl -X POST http://localhost:18088/api/v1/mcp/servers \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <token>" \
-d '{
"name": "internal-data-service",
"description": "企业内部数据查询 MCP 服务",
"transport": "streamable_http",
"url": "https://mcp-api.internal.example.com/mcp",
"headersJson": "{\"Authorization\": \"Bearer sk-your-api-key\", \"X-Team-Id\": \"engineering\"}",
"connectTimeoutSeconds": 10,
"readTimeoutSeconds": 120,
"enabled": true
}'配置说明:
url指向远程 MCP 服务器的 Streamable HTTP 端点headersJson传递认证信息,每次 HTTP 请求都会携带这些头- 头中的值支持环境变量引用:
{"Authorization": "Bearer ${MCP_API_KEY}"}会在运行时替换为系统环境变量的值 - 较长的
readTimeoutSeconds适用于执行时间较长的数据查询
示例三:Tavily 搜索 MCP 服务器(stdio + 环境变量)
接入 Tavily 搜索 MCP 服务器,为 Agent 提供实时网页搜索能力。
curl -X POST http://localhost:18088/api/v1/mcp/servers \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <token>" \
-d '{
"name": "tavily-search",
"description": "Tavily 实时网页搜索",
"transport": "stdio",
"command": "npx",
"argsJson": "[\"-y\", \"@anthropic/mcp-tavily\"]",
"envJson": "{\"TAVILY_API_KEY\": \"${TAVILY_API_KEY}\"}",
"enabled": true
}'配置说明:
envJson中的${TAVILY_API_KEY}会在运行时被替换为 MateClaw 进程的同名系统环境变量- 也支持直接写入明文 key:
{"TAVILY_API_KEY": "tvly-xxxxxx"},但建议使用环境变量引用以避免密钥泄露 - 子进程会继承指定的环境变量
示例四:SSE 兼容的旧版 MCP 服务器
连接一个仅支持 SSE 传输的 MCP 服务器:
curl -X POST http://localhost:18088/api/v1/mcp/servers \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <token>" \
-d '{
"name": "legacy-mcp-server",
"description": "旧版 SSE 传输的 MCP 服务器",
"transport": "sse",
"url": "http://192.168.1.100:3001/sse",
"enabled": true
}'MCP 工具注册机制
MCP 工具从发现到可被 Agent 调用,经过以下流程:
McpServerBootstrapRunner(应用启动)
│
▼
McpServerService.initEnabledServers()
│ 遍历所有 enabled 的 MCP server
▼
McpClientManager.connect(server)
│ 1. 根据 transport 类型构建 McpSyncClient
│ 2. 调用 client.initialize() 建立连接
│ 3. 调用 client.listTools() 发现工具
│ 4. 缓存到 clients 和 toolsCache
▼
McpToolCallbackProvider.getToolCallbacks()
│ 实现 Spring AI 的 ToolCallbackProvider 接口
│ 从 McpClientManager 获取所有 active clients 的 ToolCallback
▼
ToolRegistry(工具注册表)
│ 聚合内置工具 + MCP 工具
▼
Agent 工具集
│ Agent 在推理时可调用任何已注册工具关键实现细节:
- McpToolCallbackProvider 实现了 Spring AI 的
ToolCallbackProvider接口。每次调用getToolCallbacks()都会从McpClientManager获取最新的活跃工具列表,因此新增或删除 MCP 服务器后无需重启应用即可生效。 - SyncMcpToolCallbackProvider(Spring AI 内置)负责将单个
McpSyncClient的工具转换为ToolCallback数组。 - MCP 工具与内置
@Tool注解的工具在 Agent 调用层面完全一致,Agent 无法也无需区分工具来源。 - 每个 MCP 工具的名称、描述和参数 schema 均由 MCP 服务器在
tools/list响应中声明。
连接管理
启动时自动连接
MateClaw 启动完成后,McpServerBootstrapRunner 会自动连接所有数据库中标记为 enabled=true 的 MCP 服务器。单个服务器连接失败不会阻塞其他服务器或应用启动。
线程安全
McpClientManager 使用 ConcurrentHashMap 存储活跃客户端,并为每个 server 维护独立的 ReentrantLock,确保同一服务器的 connect/replace/remove 操作不会并发冲突。
连接替换(Replace)
更新 MCP 服务器配置后,系统执行"先连新再断旧"的替换策略:
- 使用新配置创建并初始化新的
McpSyncClient - 新客户端连接成功后,将其放入活跃客户端池
- 关闭旧客户端
如果新客户端连接失败,旧客户端不受影响(如果有的话)。
子进程清理
对于 stdio 类型的 MCP 服务器,MateClaw 会启动一个子进程。以下场景会确保子进程被正确关闭:
- 手动禁用或删除 MCP 服务器
- 替换 MCP 服务器配置
- 应用关闭时(通过
@PreDestroy钩子) - 连接失败时(初始化过程中已启动的子进程会被关闭)
状态监控
每次连接操作后,系统会将连接结果持久化到数据库:
last_status:connected/disconnected/errorlast_error:错误信息(连接成功时清空)last_connected_time:最后一次成功连接的时间tool_count:当前发现的工具数量
手动刷新
通过「刷新所有连接」操作(API: POST /api/v1/mcp/servers/refresh),可以断开所有现有连接并重新连接所有启用的服务器。适用于排查连接问题或 MCP 服务器端工具列表变更后需要重新发现的场景。
数据库存储
MCP 服务器配置存储在 mate_mcp_server 表中。完整字段如下:
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
id | BIGINT | - | 主键(雪花算法生成) |
name | VARCHAR(128) | - | 服务器名称,唯一标识。允许字母、数字、_、-、.、空格,1-128 字符 |
description | TEXT | NULL | 服务器描述 |
transport | VARCHAR(32) | stdio | 传输类型:stdio / streamable_http / sse |
url | VARCHAR(512) | NULL | 远端 URL(streamable_http/sse 类型必填) |
headers_json | TEXT | NULL | HTTP 请求头,JSON 对象格式,如 {"Authorization": "Bearer xxx"} |
command | VARCHAR(512) | NULL | 启动命令(stdio 类型必填),如 npx、node、python |
args_json | TEXT | NULL | 命令参数,JSON 数组格式,如 ["-y", "@anthropic/mcp-filesystem"] |
env_json | TEXT | NULL | 环境变量,JSON 对象格式,支持 ${VAR} 引用系统环境变量 |
cwd | VARCHAR(512) | NULL | 工作目录(stdio 类型使用) |
enabled | BOOLEAN | TRUE | 是否启用 |
connect_timeout_seconds | INT | 30 | 连接建立超时(秒),用于 HTTP 传输类型 |
read_timeout_seconds | INT | 30 | 请求响应超时(秒),控制 initialize/listTools/callTool 的超时 |
last_status | VARCHAR(32) | disconnected | 最后连接状态:connected / disconnected / error |
last_error | TEXT | NULL | 最后错误信息 |
last_connected_time | DATETIME | NULL | 最后成功连接时间 |
tool_count | INT | 0 | 发现的工具数量 |
builtin | BOOLEAN | FALSE | 是否系统内置(内置服务器不允许删除) |
create_time | DATETIME | - | 创建时间 |
update_time | DATETIME | - | 更新时间 |
deleted | INT | 0 | 逻辑删除标记 |
敏感信息脱敏
通过 API 返回 MCP 服务器列表时,headers_json 和 env_json 字段中的值会被自动脱敏(保留前几位和后四位,中间用 * 替代)。args_json 因不涉及敏感信息而保持原样。
环境变量引用
env_json 和 headers_json 中的值支持引用系统环境变量:
${VAR_NAME}-- 精确匹配并替换$VAR_NAME-- 正则匹配(确保不误替换前缀相同的变量)
例如 {"TAVILY_API_KEY": "${TAVILY_API_KEY}"} 会在运行时替换为 MateClaw 进程环境中对应的值。这样可以避免在数据库中存储明文密钥。
故障排查
命令找不到(stdio 类型)
现象:连接失败,错误信息包含 "command not found" 或 "No such file or directory"。
排查步骤:
- 确认
command字段指定的命令在 MateClaw 运行用户的 PATH 中可用 - 在服务器终端手动执行该命令确认可用:
which npx或npx --version - 如果使用 Docker 部署,确认命令已安装在容器内
- 可以使用完整路径替代命令名,如
/usr/local/bin/npx
连接超时
现象:连接失败,错误信息包含 "timeout" 或 "timed out"。
排查步骤:
- 对于 HTTP/SSE 类型,确认 URL 可达:
curl -v <url> - 检查防火墙规则是否允许出站连接
- 适当增大
connectTimeoutSeconds和readTimeoutSeconds - 对于 stdio 类型,首次执行
npx -y可能需要下载包,耗时较长,建议增大超时或预先安装
SSL/TLS 错误
现象:连接 HTTPS 端点时失败,错误信息包含 "SSL" 或 "certificate"。
排查步骤:
- 确认远端 MCP 服务器的 SSL 证书有效且未过期
- 如果使用自签名证书,需要将 CA 证书添加到 JVM 信任库
- 确认 MateClaw 运行环境的 JDK 版本支持对应的 TLS 版本
工具未显示
现象:MCP 服务器状态为 connected,但在 Agent 工具列表中看不到对应工具。
排查步骤:
- 检查
tool_count字段是否大于 0 - 使用测试连接功能,确认
discoveredTools列表不为空 - 确认 MCP 服务器正确实现了
tools/list接口 - 查看 MateClaw 后端日志中的
McpToolCallbackProvider相关输出
工具调用失败
现象:Agent 调用 MCP 工具时返回错误。
排查步骤:
- 查看 MateClaw 后端日志中的具体错误信息
- 确认 MCP 服务器进程仍在运行(stdio 类型)
- 确认远端 MCP 服务器可用(HTTP/SSE 类型)
- 检查
readTimeoutSeconds是否足够(某些工具执行时间较长) - 尝试刷新连接:
POST /api/v1/mcp/servers/refresh
子进程残留(stdio 类型)
现象:停止 MateClaw 后,MCP 子进程仍在运行。
排查步骤:
- 正常情况下
@PreDestroy钩子会清理所有子进程 - 如果 MateClaw 被强制终止(kill -9),子进程可能残留,需手动清理
- 使用
ps aux | grep mcp查找并终止残留进程
