MCP 进阶实战:用 LangChain 将 MCP 工具集成到你的 AI Agent 程序

MCP 进阶实战:用 LangChain 将 MCP 工具集成到你的 AI Agent 程序

上一篇我们学习了如何编写 MCP Server 并在 Cursor 中使用。本文更进一步:如何把 MCP 工具直接嵌入你自己的 Node.js AI 应用,实现完全自主可控的 Agent 工作流。


一、为什么要把 MCP 集成到自己的程序里?

在上一篇文章中,我们通过 Cursor / Trae 的配置文件加载 MCP Server,让 AI 编程助手拥有了查询用户信息的能力。这种方式非常适合交互式编程场景

但如果你正在开发一个:

  • 后台自动化处理任务
  • 企业微信 / 钉钉机器人
  • 数据报表生成服务
  • 内部运维 Agent

你会发现,你需要的不是让 Cursor 去调工具,而是让你自己写的 Node.js / Python 程序去调度大模型 + 调用 MCP 工具

这时候,@langchain/mcp-adapters 就派上用场了。


二、核心组件:MCP 三者关系再梳理

结合我们之前的 readme.md 内容,先来一张关系图:

角色 说明 示例
MCP Host 发起对话、承载 Agent 逻辑的宿主程序 Cursor、Trae、你写的 LangChain 应用
MCP Client 与 MCP Server 通信,管理工具列表 MultiServerMCPClient
MCP Server 提供具体工具 / 资源 / 提示词的执行容器 my-mcp-server.mjs
arduino 复制代码
┌─────────────────┐     ┌─────────────────┐     ┌─────────────────┐
│   MCP Host      │────▶│  MCP Client     │────▶│  MCP Server     │
│ (你的 LangChain │     │ (适配器)         │     │ (工具容器)       │
│  应用程序)       │◀────│                 │◀────│                 │
└─────────────────┘     └─────────────────┘     └─────────────────┘

工作流程回顾:

  1. Host 启动时,Client 与 Server 建立连接(Stdio / HTTP)
  2. Client 向 Server 发起 initialize 请求,获取所有工具列表及详细 schema
  3. Host 收到用户任务,大模型判断需要调用某个工具
  4. Client 将调用请求转发给 Server
  5. Server 执行工具函数,返回结构化结果
  6. Host 将结果以 ToolMessage 形式喂回大模型,继续对话

三、环境准备与依赖安装

我们要在已有 MCP Server 的基础上,新建一个 LangChain 应用来调用它。

bash 复制代码
# 进入你的项目目录(例如 ai/agent/mini-cursor/mcp/)
cd mcp-tool

# 安装所需依赖
npm install @langchain/mcp-adapters @langchain/openai @langchain/core dotenv chalk zod

依赖说明:

  • @langchain/mcp-adapters:官方 MCP 与 LangChain 之间的桥接器
  • @langchain/openai:调用 OpenAI 兼容接口的大模型
  • chalk:美化终端输出(可选)
  • dotenv:加载 .env 环境变量

在项目根目录创建 .env 文件,填入你的大模型配置:

env 复制代码
MODEL_NAME=gpt-4o-mini
OPENAI_API_KEY=sk-xxxxxx
OPENAI_BASE_URL=https://api.openai.com/v1

四、编写 MCP Agent 主程序

创建一个新文件 agent.mjs,内容如下(已包含详细注释):

javascript 复制代码
import 'dotenv/config';
import { MultiServerMCPClient } from '@langchain/mcp-adapters';
import { ChatOpenAI } from '@langchain/openai';
import { HumanMessage, ToolMessage } from '@langchain/core/messages';
import chalk from 'chalk';

// ---------- 1. 初始化大模型 ----------
const model = new ChatOpenAI({
    modelName: process.env.MODEL_NAME,
    apiKey: process.env.OPENAI_API_KEY,
    configuration: {
        baseURL: process.env.OPENAI_BASE_URL,
    }
});

// ---------- 2. 创建 MCP 客户端,连接我们之前写的 Server ----------
const mcpClient = new MultiServerMCPClient({
    mcpServers: {
        'my-mcp-server': {
            command: 'node',
            args: ['C:/Users/29031/Desktop/workspace/lesson_zp/ai/agent/mini-cursor/mcp/mcp-tool/my-mcp-server.mjs'],
        },
    },
});

// ---------- 3. 获取 MCP Server 中的所有工具 ----------
const tools = await mcpClient.getTools();
console.log(chalk.green('✅ 已加载 MCP 工具列表:'), tools.map(t => t.name));

// 将工具绑定到大模型上(让模型知道它可以调用哪些工具)
const modelWithTools = model.bindTools(tools);

// ---------- 4. Agent 循环函数 ----------
async function runAgentWithTools(query, maxIterations = 30) {
    const messages = [new HumanMessage(query)];

    for (let i = 0; i < maxIterations; i++) {
        console.log(chalk.bgGreen(`⏳ 第 ${i + 1} 轮思考...`));
        
        // 调用大模型,它会返回一个 AI 消息,可能包含 tool_calls
        const response = await modelWithTools.invoke(messages);
        messages.push(response);

        // 如果模型没有要求调用工具,说明对话结束,返回最终答案
        if (!response.tool_calls || response.tool_calls.length === 0) {
            console.log(chalk.bgWhite.black('✅ 最终回复:'));
            return response.content;
        }

        // 模型要求调用工具,我们逐一执行
        console.log(chalk.bgBlue(`🔧 检测到 ${response.tool_calls.length} 个工具调用:`));
        for (const toolCall of response.tool_calls) {
            console.log(chalk.blue(`   → 调用工具:${toolCall.name},参数:${JSON.stringify(toolCall.args)}`));
            
            // 从 MCP 工具列表中找到对应的工具实例
            const foundTool = tools.find(t => t.name === toolCall.name);
            if (foundTool) {
                // 执行工具,获得结果
                const toolResult = await foundTool.invoke(toolCall.args);
                
                // 将工具执行结果包装成 ToolMessage,加回对话历史
                messages.push(new ToolMessage({
                    content: toolResult,
                    tool_call_id: toolCall.id
                }));
                
                console.log(chalk.gray(`   ← 工具返回:${toolResult.substring(0, 100)}...`));
            } else {
                console.log(chalk.red(`   ✗ 未找到工具 ${toolCall.name}`));
            }
        }
    }
    
    return '已达到最大迭代次数,对话终止。';
}

// ---------- 5. 执行一个实际任务 ----------
const result = await runAgentWithTools("查一下用户 002 的信息");
console.log(chalk.yellow('\n🎉 最终结果:\n'), result);

// ---------- 6. 关闭 MCP 客户端连接 ----------
await mcpClient.close();

代码关键点解析

代码段 作用
MultiServerMCPClient 管理多个 MCP Server 的连接,内部会自动处理 Stdio 子进程的启动与通信。
mcpClient.getTools() 获取所有 Server 提供的工具列表,这些工具的 schema 已经自动转换为 LangChain 能识别的格式
model.bindTools(tools) 将工具列表告知大模型,后续对话中模型会在需要时返回 tool_calls
ToolMessage LangChain 中专门用于携带工具执行结果的消息类型,必须与对应的 tool_call_id 绑定。
循环调用 Agent 的核心逻辑:模型输出工具调用 → 执行工具 → 将结果喂回模型 → 继续,直到模型不再要求调用工具。

五、运行测试

在终端执行:

bash 复制代码
node agent.mjs

你将看到类似如下的输出:

sql 复制代码
✅ 已加载 MCP 工具列表: [ 'query-user' ]
⏳ 第 1 轮思考...
🔧 检测到 1 个工具调用:
   → 调用工具:query-user,参数:{"userId":"002"}
   ← 工具返回:用户信息:
- ID: 002
- 姓名: 李四
- 邮箱: lisi@example.com
- 角色: user...
⏳ 第 2 轮思考...
✅ 最终回复:
用户 002 的信息如下:
姓名:李四,邮箱:lisi@example.com,角色:user。

🎉 最终结果:
 用户 002 的信息如下:
姓名:李四,邮箱:lisi@example.com,角色:user。

至此,你已经成功将 MCP 工具无缝集成到自己的 LangChain 程序中!

如图


六、进阶:为 MCP Server 添加"资源"(Resource)

MCP 协议不仅支持 Tool(工具) ,还支持 Resource(资源)Prompt(提示模板)

工具:执行动作(查询、写入、计算)

资源:暴露静态数据或文件内容(文档、配置、数据库表结构)

提示模板:预设的对话模板

在我们的 my-mcp-server.mjs 中,我们已经添加了一个资源:

javascript 复制代码
server.registerResource('使用指南', 'docs://guide', {
   description: 'MCP Server 使用指南',
   mimeType: 'text/plain',
},
async () => {
    return {
      contents: [{
        uri: 'docs://guide',
        mimeType: 'text/plain',
        text: `MCP Server 使用指南...`,
      }]
    };
});

资源的使用方式:

在 LangChain 中,你可以通过 mcpClient.getResources() 获取所有资源,然后通过 mcpClient.readResource(uri) 读取内容。这使得大模型可以在对话中主动查阅你提供的"知识库"。


七、为什么说 MCP 是"可拔插"的工具生态?

从上面的实践可以看出,MultiServerMCPClient 通过一个统一的配置对象,就能启动并管理多个 MCP Server。

  • 你想添加一个 Python 写的图像处理 MCP Server ?只需在 mcpServers 里加一项配置。
  • 你想调用公司内部 Java 写的工单查询 MCP 服务?配置 HTTP 地址即可。
  • 你想临时禁用某个工具?注释掉对应配置即可。

这种 "配置即集成" 的模式,让 Agent 的能力扩展变得前所未有的简单。MCP 真正实现了大模型应用层的 Lego 化


如果这篇文章对你有帮助,欢迎点赞、收藏。有任何疑问或想了解的内容,欢迎在评论区留言!

相关推荐
DavidSoCool2 小时前
Springboot AI 创建MCP Server
java·spring·ai·大模型·springboot·mcp
xiaotao1313 小时前
03-深度学习基础:LangChain应用开发
人工智能·深度学习·langchain
BU摆烂会噶3 小时前
【LangGraph】实战:基于 LangGraph 实现的智能文档问答系统
人工智能·python·langchain
花千树-0103 小时前
LangGraph 与 ReAct Agent 调试技巧:从日志到可视化全解析
langchain·react·function call·ai agent·langgraph·mcp·j-langchain
怕浪猫3 小时前
第16章 、LangChain错误处理与鲁棒性设计
langchain·openai·ai编程
庚昀◟3 小时前
基于 LangChain、RAG、LoRA 、Streamlit 的知识库问答客服系统从零到一(附项目源码)
人工智能·langchain·milvus
2601_949816683 小时前
Node.js v16 版本安装
node.js
JaydenAI4 小时前
[FastMCP设计、原理与应用-14]FastMCP——架构之魂,构建MCP应用的统一入口与调度中枢
python·ai编程·ai agent·mcp·fastmcp
weisian1514 小时前
进阶篇-LangChain篇-15--高级Agent架构—复杂任务拆解(Plan-and-Execute架构)和多智能体协作(LangGraph)
java·架构·langchain·langgraph·planexecute架构