DeepAgents.js教程09——MCP工具集成

7 阅读6分钟

承接上一节的后端配置与多存储路由,我们已经掌握了虚拟文件系统的各种后端方案,智能体可以灵活地读写不同存储中的文件了。但智能体的能力还受限于我们手动编写的工具——每加一个新能力就要写一个 tool 函数,效率不高。

本节我们学习 MCP (模型上下文协议) ,了解如何通过标准协议快速接入外部工具服务,并以百度搜索为例,让智能体获得实时网页搜索能力。


一、认识 MCP(模型上下文协议)

1.1 什么是 MCP?

MCP(Model Context Protocol,模型上下文协议)是一个开放的标准协议,用于让 AI 助手(智能体)连接外部工具和数据源。简单说,MCP 就是智能体世界的「USB 接口」——只要设备支持 USB 标准,插上去就能用,不需要每个设备单独装驱动。

核心价值

  • 标准化:所有 MCP 服务器遵循统一协议,智能体不需要为每个工具写适配代码
  • 即插即用:配置一个 MCP 服务器地址,智能体自动发现并使用所有工具
  • 生态丰富:社区已经有大量 MCP 服务器(文件系统、数据库、API、搜索引擎等)
  • 语言无关:MCP 服务器可以用任何语言写,智能体用任何语言都能调用

1.2 MCP 的三种传输方式

MCP 服务器支持三种传输方式,适用于不同场景:

方式说明适用场景
stdio通过标准输入输出通信,服务器作为本地子进程运行本地工具、命令行工具
sseServer-Sent Events,HTTP 长连接远程服务、实时推送
streamableHttp / http可流式 HTTP 传输远程 API 服务、云服务

💡 百度搜索 MCP 使用的就是 streamableHttp 方式,通过 HTTP 接口提供搜索能力。

1.3 MCP 工具的工作流程

用户提问 → 智能体判断需要搜索 → 调用 MCP 搜索工具
→ 请求发送到 MCP 服务器 → 服务器执行搜索 → 返回结果
→ 智能体基于搜索结果生成回答

整个过程对智能体来说,MCP 工具和我们手动写的自定义工具没有区别——都是接收参数、返回结果。区别在于 MCP 工具是自动发现的,不需要我们手动定义。


二、百度搜索 MCP

百度搜索是百度智能云推出的 MCP 工具服务,提供实时网页搜索能力:

配置格式

百度搜索 MCP 的标准配置如下:

{
    "mcpServers": {
        "web-search-mcp-server": {
            "type": "streamableHttp",
            "description": "根据用户提问,搜索实时网页信息",
            "url": "https://qianfan.baidubce.com/v2/tools/web-search/mcp",
            "headers": {
                "Authorization": "Bearer 你的API密钥"
            }
        }
    }
}

参数说明

字段说明
type传输方式,千帆搜索使用 streamableHttp
description服务器描述,帮助智能体理解这个服务器能做什么
urlMCP 服务器的端点地址
headers.Authorization认证信息,格式为 Bearer + API密钥

💡 你需要在百度智能云千帆平台申请 API 密钥,替换上面的 你的API密钥


三、在 Deep Agents 中使用 MCP 工具

Deep Agents 原生支持 MCP 协议,通过官方 @langchain/mcp-adapters 包可以快速接入任意 MCP 服务器,只需要几行代码。

3.1 安装依赖

npm install @langchain/mcp-adapters

3.2 基本用法

集成 MCP 工具只需要三步:

import { createDeepAgent } from "deepagents";
import { MultiServerMCPClient } from "@langchain/mcp-adapters";

// 第一步:创建 MCP 客户端,配置服务器
const client = new MultiServerMCPClient({
  "qianfan-search": {
    transport: "http",
    url: "https://qianfan.baidubce.com/v2/tools/web-search/mcp",
    headers: {
      Authorization: "Bearer 你的API密钥",
    },
  },
});

// 第二步:获取所有 MCP 工具
const tools = await client.getTools();

// 第三步:传入 createDeepAgent
const agent = createDeepAgent({
  model: model,
  tools: tools,  // MCP 工具直接传入,和自定义工具一样
  systemPrompt: "你是一个智能助手,可以使用搜索工具查找实时信息。",
});

就是这么简单!MultiServerMCPClient 会自动:

  • 连接到所有配置的 MCP 服务器

  • 发现每个服务器提供的工具

  • 将 MCP 工具转换为 LangChain 工具格式

  • 处理工具调用和结果返回

3.3 配置多个 MCP 服务器

MultiServerMCPClient 支持同时配置多个服务器,智能体自动管理所有工具:

const client = new MultiServerMCPClient({
  // 百度搜索
  "qianfan-search": {
    transport: "http",
    url: "https://qianfan.baidubce.com/v2/tools/web-search/mcp",
    headers: {
      Authorization: `Bearer ${process.env.QIANFAN_MCP_API_KEY}`,
    },
  },
  // 本地文件系统 MCP(stdio 方式)
  "filesystem": {
    transport: "stdio",
    command: "npx",
    args: ["-y", "@modelcontextprotocol/server-filesystem", "./workspace"],
  },
  // GitHub MCP(stdio 方式)
  "github": {
    transport: "stdio",
    command: "npx",
    args: ["-y", "@modelcontextprotocol/server-github"],
    env: { GITHUB_TOKEN: process.env.GITHUB_TOKEN },
  },
});

const tools = await client.getTools();

💡 每个服务器的 key(比如 qianfan-search)是自定义的名称,用于区分不同的服务器。工具名会自动加上服务器前缀,避免冲突。


四、实战:百度千帆网页搜索

下面我们做一个完整的示例,用百度搜索 MCP 让智能体获得实时搜索能力。

4.1 环境准备

.env 中添加千帆 API 密钥:

# .env
# 百度搜索 MCP 密钥
QIANFAN_MCP_API_KEY=你的千帆API密钥

4.2 完整代码

新建 09-mcp-tools.js

/*
 * Deep Agents 教程 09:MCP 工具集成(百度搜索)
 */
import "dotenv/config";
import { createDeepAgent } from "deepagents";
import { MultiServerMCPClient } from "@langchain/mcp-adapters";
import { model } from "./00-model.js";

// ============================================================
// 1. 创建 MCP 客户端并加载工具
// ============================================================

async function createAgentWithMcp() {
  console.log("🔌 正在连接 MCP 服务器...\n");

  // 创建 MCP 客户端,配置千帆搜索服务器
  const mcpClient = new MultiServerMCPClient({
    "qianfan-search": {
      transport: "http",
      url: "https://qianfan.baidubce.com/v2/tools/web-search/mcp",
      headers: {
        Authorization: `Bearer ${process.env.QIANFAN_MCP_API_KEY || ""}`,
      },
    },
  });

  // 获取所有 MCP 工具
  const tools = await mcpClient.getTools();

  console.log(`✅ 已加载 ${tools.length} 个 MCP 工具:`);
  tools.forEach((tool) => {
    console.log(`   - ${tool.name}: ${tool.description?.slice(0, 50) || "无描述"}...`);
  });
  console.log("");

  // 创建智能体,注入 MCP 工具
  const agent = createDeepAgent({
    model: model,
    tools: tools,
    systemPrompt: `你是一个智能助手,可以使用百度千帆搜索工具查找实时网页信息。

使用搜索工具的规则:
1. 当用户询问时事新闻、最新动态、实时数据等需要最新信息的问题时,请使用搜索工具
2. 搜索时用简洁的关键词,不要用完整句子
3. 搜索结果可能包含多个来源,请综合整理后回答
4. 回答事实性问题时,如果不确定,请搜索确认
5. 回答中可以简要提及信息来自搜索结果

回答语言:中文`,
  });

  return { agent, mcpClient };
}

// ============================================================
// 2. 流式输出辅助函数
// ============================================================

async function streamAgent(agent, input) {
  console.log("\n🧑 用户:", input);
  console.log("\n🤖 思考中...\n");

  const stream = await agent.streamEvents(
    { messages: [{ role: "user", content: input }] },
    { version: "v3" }
  );

  await Promise.all([
    // AI 回答
    (async () => {
      for await (const message of stream.messages) {
        if (message.reasoning) {
          process.stdout.write("💭 思考: ");
          for await (const token of message.reasoning) {
            if (token) process.stdout.write(token);
          }
          console.log("\n");
        }
        if (message.text) {
          process.stdout.write("🤖 回答: ");
          for await (const token of message.text) {
            if (token) process.stdout.write(token);
          }
          console.log("\n");
        }
      }
    })(),
    // 工具调用
    (async () => {
      for await (const call of stream.toolCalls) {
        const inputStr = JSON.stringify(call.input).slice(0, 100);
        console.log(`🔧 [工具调用] ${call.name}`);
        console.log(`   参数: ${inputStr}...`);
        const status = await call.status;
        if (status === "finished") {
          const output = await call.output;
          const shortOutput = typeof output === "string"
            ? output.slice(0, 150) + "..."
            : JSON.stringify(output).slice(0, 150) + "...";
          console.log(`   ✅ 结果: ${shortOutput}`);
        } else if (status === "error") {
          console.log(`   ❌ 错误: ${await call.error}`);
        }
        console.log("");
      }
    })(),
  ]);
}

// ============================================================
// 3. 主函数
// ============================================================

async function main() {
  console.log("\n" + "=".repeat(60));
  console.log("🔍 Deep Agents MCP 工具集成演示");
  console.log("=".repeat(60));
  console.log("MCP 服务器: 百度千帆 AI 搜索");
  console.log("=".repeat(60) + "\n");

  // 创建带 MCP 工具的智能体
  const { agent } = await createAgentWithMcp();

  // 支持命令行传入自定义问题
  const args = process.argv.slice(2);
  if (args.length > 0) {
    const customQuestion = args.join(" ");
    await streamAgent(agent, customQuestion);
  } else {
    // 默认演示问题
    const questions = [
      "搜索一下今天的热点新闻有哪些",
      "Deep Agents 框架最新版本是多少?",
    ];

    for (const q of questions) {
      await streamAgent(agent, q);
      console.log("─".repeat(60) + "\n");
    }
  }

  console.log("\n✅ 演示完成!");
  console.log("\n💡 使用方式:");
  console.log("   node 09-mcp-tools.js 你的问题");
  console.log("   例如:node 09-mcp-tools.js 今天的天气怎么样");
  console.log("");
}

main().catch(console.error);

4.3 运行测试

# 默认演示
node 09-mcp-tools.js

# 自定义问题
node 09-mcp-tools.js 今天的热点新闻有哪些

运行后你会看到:

  1. 程序连接到千帆 MCP 服务器,加载搜索工具
  2. 智能体根据问题判断是否需要搜索
  3. 调用搜索工具,传入查询参数
  4. 获取搜索结果,整理后生成回答

五、MCP 工具的更多用法

5.1 stdio 类型的 MCP 服务器

除了 HTTP 方式,MCP 还支持 stdio 方式——服务器作为本地子进程运行,通过标准输入输出通信。

const client = new MultiServerMCPClient({
  // 文件系统 MCP(stdio 方式)
  "filesystem": {
    transport: "stdio",
    command: "npx",
    args: ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/directory"],
  },
  // GitHub MCP(stdio 方式)
  "github": {
    transport: "stdio",
    command: "npx",
    args: ["-y", "@modelcontextprotocol/server-github"],
    env: {
      GITHUB_TOKEN: process.env.GITHUB_TOKEN,
    },
  },
});

stdio 方式的特点

  • 服务器在本地运行,延迟低
  • 适合本地工具、文件系统操作
  • 不需要公网访问
  • 通过环境变量传递配置和密钥

5.2 工具过滤

如果 MCP 服务器提供了很多工具,但你只想让智能体用其中一部分,可以在配置中过滤:

const client = new MultiServerMCPClient({
  "my-server": {
    transport: "http",
    url: "https://example.com/mcp",
    // 只允许这些工具
    allowedTools: ["search", "get_news"],
    // 或者禁用某些工具
    // disabledTools: ["delete_file", "format_disk"],
  },
});
  • allowedTools:白名单,只保留列出的工具
  • disabledTools:黑名单,移除列出的工具

5.3 MCP 工具 + 自定义工具混合使用

MCP 工具和自定义工具可以一起使用,直接放在同一个数组里就行:

import { tool } from "langchain";
import { z } from "zod";

// 自定义工具
const myCustomTool = tool(
  async ({ input }) => {
    return `处理结果: ${input}`;
  },
  {
    name: "my_custom_tool",
    description: "一个自定义工具",
    schema: z.object({
      input: z.string().describe("输入参数"),
    }),
  }
);

// MCP 工具
const mcpTools = await client.getTools();

// 合并使用
const agent = createDeepAgent({
  model: model,
  tools: [...mcpTools, myCustomTool],  // 合并在一起
});

六、核心要点总结

6.1 MCP 集成三步法

  1. 配置:用 MultiServerMCPClient 配置 MCP 服务器地址和参数
  2. 获取:调用 client.getTools() 获取所有工具
  3. 注入:把工具数组传给 createDeepAgenttools 参数

6.2 MCP vs 自定义工具

对比项自定义工具MCP 工具
开发方式手动写函数配置服务器地址即可
工具数量自己写多少有多少取决于 MCP 服务器
维护成本自己维护代码服务器方维护
灵活性完全可控受限于服务器提供的功能
适用场景项目特定逻辑通用能力(搜索、文件、数据库等)

6.3 百度搜索使用建议

  • 适合:时事新闻、最新资讯、事实核查、产品信息查询
  • 不适合:纯推理、计算、代码生成等不需要外部信息的任务
  • 技巧:在系统提示词中说明搜索的使用场景,智能体会更准确地判断何时调用

6.4 安全注意事项

  • API 密钥不要硬编码在代码里,用环境变量管理

  • MCP 工具的权限要控制好,不要让智能体调用危险操作

  • 生产环境建议做好调用频率限制和成本监控

  • allowedTools / disabledTools 控制工具暴露范围


七、常见问题排查

1. 连接 MCP 服务器失败

  • 检查 URL 是否正确
  • 确认 API 密钥有效
  • 检查网络是否能访问该地址(国内服务可能需要特定网络环境)
  • 确认传输方式(transport)是否正确

2. 智能体不调用 MCP 工具

  • 检查工具的 description 是否清晰描述了功能
  • 在系统提示词中说明工具的使用场景
  • 用户的问题要足够明确,让智能体判断需要调用工具

3. getTools() 返回空数组

  • 确认 MCP 服务器是否正常运行
  • 检查配置的 transport 类型是否正确
  • 查看控制台的错误信息,可能是认证失败或连接超时

4. 工具调用超时

  • MCP 服务器响应可能较慢,搜索类工具通常需要 2-5 秒
  • 可以在配置中调整超时时间

5. stdio 服务器启动失败

  • 检查 command 和 args 是否正确
  • 确认依赖包已安装(比如 npx 能拉到对应的包)
  • 检查环境变量是否正确设置

6. 多个 MCP 服务器的工具重名怎么办?

  • MultiServerMCPClient 会自动给工具名加上服务器前缀
  • 比如服务器 qianfan-searchsearch 工具会变成 qianfan-search_search
  • 不会有命名冲突

下一节我们将学习 Deep Agents 的技能(Skills)体系,了解如何用渐进式披露的方式管理大量专业知识,让智能体既能拥有丰富的领域能力,又不会浪费上下文 token。