第十五章 MCP 协议工具:tools.json 声明式接入 MCP Server,配置即集成
"我们想把 GitHub MCP server、PostgreSQL MCP server、Slack MCP server 一起接进 agent。1.x 时代我们写 3 个
Tool子类;2.0 用workspace/tools.json一行声明一个 MCP server,agent 启动时自动发现工具。这是 2.0 推荐的『配置即集成』。"本章你将学到:MCP server 是什么、
tools.json里怎么写 MCP 段、如何在 Java 端补强 MCP、常见 MCP server 接入示例。
15.1 MCP 是什么?
Model Context Protocol(MCP) 是 Anthropic 在 2024 年推出的开放协议,让 LLM 应用以统一方式发现并调用外部工具。AgentScope 2.0 把 MCP server 作为 agent 工具的一种"来源"——你在 tools.json 里声明一个 MCP server,agent 启动时通过 stdio 或 sse 协议连上它,自动把 server 暴露的工具当作 agent 自己的 tool。
15.2 第一个 MCP 集成
{
"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——不需要额外开关。
HarnessAgent agent = HarnessAgent.builder()
...
.workspace(Path.of("./workspace"))
.build();
跑起来后,agent 就能调用 GitHub MCP server 暴露的 create_issue / list_repos / search_code 等工具了。
15.3 三种连接方式
| 协议 | 适用 | 声明方式 |
|---|---|---|
stdio |
本地进程,最常见 | command + args |
sse |
远程 HTTP SSE server | url + headers |
ws |
双向 WebSocket | url + headers |
stdio 例子:
{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "./data"]
}
}
}
sse 例子:
{
"mcpServers": {
"remote-knowledge": {
"url": "https://mcp.example.com/sse",
"headers": {
"Authorization": "Bearer ${env:MCP_TOKEN}"
}
}
}
}
15.4 不想写 JSON 文件?可以在 Java 代码里直接配
用 JSON 文件当然可以,但有时候你想在代码里动态拼参数——比如 token 从环境变量读、超时按环境切换。这时候直接用 ToolsConfig + McpServerConfig 在 Java 代码里配,效果和 tools.json 完全一样:
import io.agentscope.harness.agent.tools.McpServerConfig;
import io.agentscope.harness.agent.tools.ToolsConfig;
ToolsConfig cfg = new ToolsConfig();
Map<String, McpServerConfig> 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 段一一对应。
15.5 与 Permission 协作
MCP 工具默认会经过 Permission 系统——你可以在 rule 里直接写 MCP 工具名:
PermissionContextState perms = PermissionContextState.builder()
.mode(PermissionMode.ACCEPT_EDITS) // 大部分操作直接放行
.addAskRule("create_issue", // create_issue 是 MCP GitHub server 的工具
new PermissionRule("create_issue", null,
PermissionBehavior.ASK, "userSettings")) // 建 Issue 前要弹窗问用户
.addDenyRule("drop_table", // drop_table 是本地工具
new PermissionRule("drop_table", null,
PermissionBehavior.DENY, "userSettings")) // 删表直接拒绝
.build();
MCP 工具和本地 @Tool 工具在 Permission 系统里地位完全平等——create_issue(来自 GitHub MCP server)和 drop_table(来自本地 Java 类)同等待遇。
15.6 常见 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中 Java 端注册的工具(最高)- 第一个启动成功的 MCP server
- 后面的同名工具被忽略 + 启动日志里 WARN
要避免冲突:用 toolFilter 限定:
{
"mcpServers": {
"...": "..." },
"toolFilter": {
"deny": ["github_legacy_*"]
}
}
15.8 完整可运行示例
这个例子在演示什么?
你有一个 devops agent,可以查 GitHub Issue 和操作本地文件。生产环境通过
workspace/tools.json声明两个 MCP server(GitHub、Filesystem);开发环境先用@Tool模拟 MCP 行为,避免依赖外部进程。两种方式代码结构相同,仅工具来源不同。
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-java\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-java 最近有什么 Issue。")),
RuntimeContext.empty())
.block();
}
}
workspace/tools.json(生产环境用,替代上面 Java 端的 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"]
}
}
}
开发时用
@Toolmock,生产时去掉 mock 换成tools.json——业务代码完全不变,只改工具来源。
15.9 MCP Tool Meta:在工具调用中传递元数据
RC2 新增 McpMeta 机制——你可以在 RuntimeContext 中放入元数据(traceId、userId、回调地址等),框架自动在 MCP CallToolRequest 的 meta 参数中原样传递。
import io.agentscope.core.tool.mcp.McpMeta;
// 把 traceId 和 callbackUrl 放进 McpMeta
McpMeta meta = new McpMeta(Map.of(
"traceId", "abc-123", // 链路追踪 ID
"callbackUrl", "https://hook.example.com/cb" // 结果回调地址
));
RuntimeContext ctx = RuntimeContext.builder()
.put(McpMeta.class, meta) // 注入 RuntimeContext
.build();
// 当 agent 调 MCP 工具时,meta 自动透传给 MCP server
agent.call(List.of(new UserMessage("user", "创建 issue")), ctx).block();
当 agent 调用 MCP 工具时,traceId 和 callbackUrl 会自动出现在 MCP server 收到的 meta 参数中。MCP server 可用这些 meta 做日志关联、结果推送等。
只实现了
McpMeta接口的对象才会被提取——普通RuntimeContext条目不会泄露给 MCP server。
15.10 本章小结
- MCP server 通过
stdio/sse/ws接入 agent。 workspace/tools.json用mcpServers段声明,运行时可改。- Java 端
McpServerSpec可补强:超时、env、headers。 - MCP 工具与 Permission 系统无缝集成。