第十五章 MCP 协议工具:tools.json 声明式接入 MCP Server,配置即集成
先别急着看代码,我们得搞清楚 MCP 到底是个什么玩意儿。Model Context Protocol(MCP)是 Anthropic 在 2024 年放出来的一个开放协议,核心目标就一个:让 LLM 应用能够用一种统一的方式,发现并调用外部工具。不用再为每个工具写适配器,不用折腾自定义 API——你只要声明一下,Agent 那边自动就接上了。
AgentScope 2.0 把 MCP server 当作 agent 工具的一种“来源”。怎么用?很简单:在 tools.json 里声明一个 MCP server,agent 启动的时候通过 stdio 或 sse 协议连上它,server 暴露的每个工具都会被自动注册成 agent 自己的 tool。对,就是“配置即集成”,不需要额外写一行 Ja va 代码去调工具。

15.2 第一个 MCP 集成
来看一个实实在在的例子。假设你想让 agent 操作 GitHub——创建 Issue、搜索代码、列出仓库,这些能力不需要自己写,直接拿官方 MCP server 就行。配置长这样:
{ "mcpServers": { "github": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-github"], "env": { "GITHUB_PERSONAL_ACCESS_TOKEN": "${env:GITHUB_TOKEN}" } } } }
注意 HarnessAgent.builder().workspace(path) 启动的时候,会自动扫描 workspace/tools.json 里的 mcpServers 段,连接每个 server,然后把工具注册到 agent——不需要额外开关,一切自动。
对应的 Ja va 启动代码也简洁:
HarnessAgent agent = HarnessAgent.builder()
.workspace(Path.of("./workspace"))
.build();
跑起来后,agent 就能直接调用 GitHub MCP server 暴露的 create_issue、list_repos、search_code 等工具了。这不比手写 REST 调用舒服?
15.3 三种连接方式
MCP server 的连接方式主要有三种,适用场景不同,配置方式也略有区别:
| 协议 | 适用 | 声明方式 |
|---|---|---|
stdio | 本地进程,最常见 | command + args |
sse | 远程 HTTP SSE server | url + headers |
ws | 双向 WebSocket | url + headers |
stdio 的例子:你想让 agent 操作本地文件系统,启动一个官方 filesystem server,配置如下:
{ "mcpServers": { "filesystem": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-filesystem", "./data"] } } }
sse 的例子:远程知识库 server,需要通过 HTTP 长连接来通信,此时需要指定 url 和可能的认证头:
{ "mcpServers": { "remote-knowledge": { "url": "https://mcp.example.com/sse", "headers": { "Authorization": "Bearer ${env:MCP_TOKEN}" } } } }
15.4 不想写 JSON 文件?可以在 Ja va 代码里直接配
JSON 文件当然是推荐的配置方式,毕竟可以随时改、不用重新编译。但有些场景你确实想在代码里动态拼参数——比如 token 从环境变量读,超时按环境切换。这时候直接用 ToolsConfig 加 McpServerConfig 在 Ja va 代码里配,效果和 tools.json 完全一样,但更灵活。
import io.agentscope.harness.agent.tools.McpServerConfig;
import io.agentscope.harness.agent.tools.ToolsConfig;
ToolsConfig cfg = new ToolsConfig();
Map servers = new LinkedHashMap<>();
McpServerConfig github = new McpServerConfig();
github.setTransport("stdio");
github.setCommand("npx");
github.setArgs(List.of("-y", "@modelcontextprotocol/server-github"));
github.setEnv(Map.of("GITHUB_PERSONAL_ACCESS_TOKEN", System.getenv("GITHUB_TOKEN")));
servers.put("github", github);
cfg.setMcpServers(servers);
HarnessAgent agent = HarnessAgent.builder()
.toolsConfig(cfg)
.build();
McpServerConfig 这个类在 io.agentscope.harness.agent.tools 包下,支持 transport、command、args、env、url、headers、timeout 等字段,和 tools.json 的 mcpServers 段一一对应。说白了,JSON 配置和 Ja va 代码配置是同一套数据结构的不同表达,选哪种全看你心情。
15.5 与 Permission 协作
MCP 工具默认会经过 Permission 系统——意思是你可以在 rule 里直接写 MCP 工具的名字,就像对待本地 @Tool 一样。比如:
PermissionContextState perms = PermissionContextState.builder()
.mode(PermissionMode.ACCEPT_EDITS)
.addAskRule("create_issue",
new PermissionRule("create_issue", null, PermissionBeha vior.ASK, "userSettings"))
.addDenyRule("drop_table",
new PermissionRule("drop_table", null, PermissionBeha vior.DENY, "userSettings"))
.build();
这里 create_issue 是来自 GitHub MCP server 的工具,drop_table 是本地 Ja va 类的工具。在 Permission 系统里,两者的地位完全平等——你可以对任意工具设置 ASK(弹窗询问)、DENY(直接拒绝)或 ALLOW(自动放行)。
15.6 常见 MCP server 一览
官方维护了一批常用 MCP server,开箱即用:
| 名称 | 工具集 |
|---|---|
@modelcontextprotocol/server-github | 仓库、Issue、PR |
@modelcontextprotocol/server-filesystem | 读、写、列目录 |
@modelcontextprotocol/server-postgres | 查 SQL、DDL |
@modelcontextprotocol/server-slack | 发消息、查频道 |
@modelcontextprotocol/server-puppeteer | 浏览器自动化 |
@modelcontextprotocol/server-git | git 操作 |
完整列表可以去 MCP 官方 server 仓库看,这里只列了几个最常用的。
15.7 工具命名冲突
如果两个 MCP server 都暴露了同名工具,AgentScope 会按优先级保留一个:
- 最高优先级:
Toolkit中 Ja va 端注册的工具 - 其次:第一个启动成功的 MCP server
- 后面同名的工具被忽略(启动日志里会 WARN 提示)
要避免冲突,可以用 toolFilter 来限定:
{ "mcpServers": { "...": "..." }, "toolFilter": { "deny": ["github_legacy_*"] } }
这样就能过滤掉那些不想要的工具,比如旧版本遗留的同名工具。
15.8 完整可运行示例
这个例子演示了怎么在 Ja va 代码里 mock MCP server 的工具,然后注册到 agent:
public class Chapter15_McpTools {
// Mock MCP GitHub server 工具
public static class MockGitHubTools {
@Tool(name = "create_issue", description = "创建 GitHub Issue")
public String createIssue(String repo, String title) {
return "Issue \"" + title + "\" 已创建到 " + repo + "。";
}
@Tool(name = "list_repos", description = "列出用户的仓库")
public String listRepos() {
return "- agentscope/agentscope-ja va\n- agentscope/agentscope-python";
}
@Tool(name = "search_code", description = "在代码仓库中搜索")
public String searchCode(String query) {
return "搜索 \"" + query + "\" 的结果。";
}
}
// Mock MCP Filesystem server 工具
public static class MockFilesystemTools {
@Tool(name = "read_file", description = "读取文件内容")
public String readFile(String path) {
return "文件 " + path + " 的内容。";
}
@Tool(name = "list_directory", description = "列出目录内容")
public String listDirectory(String path) {
return "目录 " + path + " 的内容。";
}
}
public static void main(String[] args) {
Toolkit toolkit = new Toolkit();
toolkit.registerTool(new MockGitHubTools());
toolkit.registerTool(new MockFilesystemTools());
HarnessAgent agent = HarnessAgent.builder()
.name("devops")
.sysPrompt("你是一个 devops 助理,可以查 GitHub issue 和操作本地文件。")
.model(model())
.workspace(Path.of("./workspace"))
.toolkit(toolkit)
.build();
agent.call(List.of(new UserMessage("user", "看看 agentscope/agentscope-ja va 最近有什么 Issue。")),
RuntimeContext.empty()).block();
}
}
生产环境可以直接用 workspace/tools.json 替代上面的 mock,配置如下:
{
"mcpServers": {
"github": {
"transport": "stdio",
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"],
"env": { "GITHUB_PERSONAL_ACCESS_TOKEN": "${env:GITHUB_TOKEN}" }
},
"filesystem": {
"transport": "stdio",
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "./data"]
}
}
}
15.9 MCP Tool Meta:在工具调用中传递元数据
RC2 新增了一个 McpMeta 机制,让你可以在 RuntimeContext 中放入元数据,比如 traceId、userId、回调地址等。框架会把这些元数据自动放在 MCP CallToolRequest 的 meta 参数中原样传递过去。
import io.agentscope.core.tool.mcp.McpMeta;
McpMeta meta = new McpMeta(Map.of(
"traceId", "abc-123",
"callbackUrl", "https://hook.example.com/cb"
));
RuntimeContext ctx = RuntimeContext.builder()
.put(McpMeta.class, meta)
.build();
agent.call(List.of(new UserMessage("user", "创建 issue")), ctx).block();
当 agent 调用 MCP 工具时,traceId 和 callbackUrl 会自动出现在 MCP server 收到的 meta 参数中。MCP server 可以用这些 meta 来做日志关联、结果推送等操作。这个设计极大地方便了链路追踪和结果回调,不用自己手动拼接参数。
15.10 本章小结
- MCP server 通过
stdio/sse/ws三种方式接入 agent,覆盖本地和远程场景。 workspace/tools.json用mcpServers段声明,运行时可以热改(重新加载即可)。- Ja va 端
McpServerSpec可以补强配置,比如超时、env、headers 等。 - MCP 工具与 Permission 系统无缝集成,可以像本地工具一样设置行为规则。
