MCP & Web Tools
外部服务通过标准协议变成 Agent 工具。
MCP 客户端桥 + Web 搜索/抓取缝。
问题
Agent 的能力不该止步于本地。现实世界在 Agent 之外:
- 一个记忆系统、一个数据库服务、一个内部 API——它们各有各的协议;
- 互联网搜索、网页抓取——模型训练数据里没有今天的信息。
外部世界成为工具,需要两种桥:一是标准协议桥(MCP:Model Context Protocol——外部服务器暴露工具,harness 发现并注册),二是能力缝桥(web 搜索/抓取,提供者可换)。
解决方案
第 1 类:MCP 客户端——连接一个 MCP 服务器,发现它的工具,注册进本地注册表:
// 连接 MCP 服务器(stdio 或 HTTP),发现工具
async function connectMcpServer(name, transport) {
const client = await mcpConnect(transport); // 启动/连接服务器
const { tools } = await client.listTools(); // 发现工具
for (const t of tools) {
define(`mcp__${name}__${t.name}`, t.inputSchema, async (args) => {
const r = await client.callTool(t.name, args); // 转发调用
return formatMcpResult(r);
});
}
return `已注册 ${tools.length} 个工具`;
}
第 2 类:Web 能力缝——搜索与抓取走同一套提供者接口:
// ctx.web 缝:注册搜索提供者
registerWebProvider("search", { name: "deepseek", async search(q) { /* ... */ } });
registerWebProvider("search", { name: "exa", async search(q) { /* ... */ } });
registerWebProvider("fetch", { name: "http", async fetch(url) { /* ... */ } });
define("web_search", { type: "object", properties: { query: { type: "string" } }, required: ["query"] },
async ({ query }) => await webSearch(query)); // 按配置选择提供者
define("web_fetch", { type: "object", properties: { url: { type: "string" } }, required: ["url"] },
async ({ url }) => await webFetch(url));
工作原理
第 1 步:MCP 工具命名带服务器前缀(mcp__server__tool),避免不同服务器的同名工具冲突;stdio 服务器的生命周期挂在 harness 插件生命周期上(启动/停止跟随插件)。
第 2 步:web 缝的搜索与抓取共享提供者选择服务——选一个搜索后端(DeepSeek/Exa/Perplexity)、一个抓取后端(HTTP),工具描述不变,后端可换(s17 的哲学再次出现)。
第 3 步:外部工具的返回要规整成文本(或结构化 JSON)——工具结果的形态决定模型消费的难易。MCP 结果、搜索摘要、页面正文,最终都变成模型能读的字符串。
试一下
运行 s19:
- 用一个本地 MCP 服务器(stdio),让模型调用它暴露的工具
- 用 web_search 问一个需要实时信息的问题("今天 DeepSeek 发布了什么")
- 用 web_fetch 抓一个 URL 并让模型总结
观察重点:外部工具的延迟与失败——MCP 服务器挂了会怎样?搜索超时了会怎样?(答案:进入 s11 的错误恢复与超时策略。)
以下内容基于 packages/mcp 与 packages/web 的核查。
一、MCP 桥
packages/mcp/mcp-client 是 MCP 客户端桥:解析配置、启动 stdio 命令或连接 Streamable HTTP、发现工具并注册为 mcp__<serverName>__<tool>。可运行的参考配置在 examples/mcp-memory/(三个默认关闭的第三方记忆系统示例)。安全细节:stdio 桥在启动子进程前移除常见凭据环境变量与所有 DSH_* 变量;凭据通过配置行显式传入。
二、Web 能力缝
packages/web:ctx.web 定义提供者注册、选择、共享错误;提供者:web-search-deepseek(原生 DeepSeek 搜索)、web-search-exa、web-search-perplexity、web-fetch-http;消费方 tool-web 暴露 web_search / web_fetch。
安全细节:带凭据的提供者请求拒绝重定向——HTTP 客户端在跟随任何重定向前失败,防止凭据被转发到其他源。这是配置层面的强制,有回归测试证明重定向目标不被接触。
| 你的最小实现 | DSH 的真实实现 |
|---|---|
mcpConnect 示意 |
完整 MCP 客户端(stdio/HTTP、生命周期、凭据剥离) |
registerWebProvider 内存注册 |
ctx.web 提供者缝 + 配置驱动选择 |
| 工具返回任意文本 | 结构化请求/结果类型 + 共享 WebError |
一句话:外部世界接入 Agent 的两条路——标准协议桥(MCP)与能力缝(web)。它们的共同点是:外部是提供者,模型侧是稳定工具。