AI Agent的“万能工具箱”:MCP协议实战,让工具调用不再受语言和进程束缚

你是否遇到过这种情况:辛辛苦苦给Agent写了一个本地工具,换个项目、换种语言就得重写?MCP(Model Context Protocol)就是为了解决这个问题而生的。本文将带你从零实现一个MCP Server,并用LangChain调用它,让你彻底理解MCP如何让工具跨语言、跨进程"即插即用"。


一、从"自嗨工具"到"通用能力":我们为什么需要MCP?

先灵魂拷问一下:你平时给AI Agent写的工具(Tool)有什么痛点?

  • 绑定特定项目:工具只能在一个代码库中用,换个项目就得复制粘贴。
  • 语言限制:你用Node.js写了工具,但团队可能用Python、Java,想复用?得重写。
  • 进程隔离:工具作为函数直接集成在Agent进程里,一崩溃全完蛋,而且无法分布式部署。

说白了,工具和LLM耦合太紧,变成了一次性的"自嗨玩具"。

如果有一种方式,让工具独立于LLM,无论本地还是远程,无论什么语言,Agent都能像插USB一样即插即用,那该多好?

MCP(Model Context Protocol) 就是来填补这个空白的。


二、MCP是什么?一句话说清核心价值

MCP = 标准化 LLM 与工具/资源通信的协议,让跨进程、跨语言的工具调用成为家常便饭。

MCP定义了Agent(作为客户端)与工具提供者(作为服务端)之间的通信规范:

  • 通信方式 :支持 stdio (本地跨进程,基于标准输入输出)和 HTTP(远程调用)。
  • 暴露内容:Tool(可执行工具)、Resource(只读上下文数据)、Prompt(复用模板)。
  • 核心作用:给Model扩展Context,让LLM不仅能"说",还能"做"(Tool),还能"知道更多"(Resource)。

你可能会想:"这不就是API调用吗?" 不,API是接口数据交互,而MCP是上下文扩展,它把Tool和Resource当作LLM的"外挂大脑",让Agent在推理时能动态调用或参考。

架构概览图(Mermaid)

Agent可以同时连接多个MCP Server,每个Server可以暴露任意数量的Tool和Resource。


三、实战:手写一个MCP Server(Node.js版)

我们从最基础的开始,实现一个简单的MCP Server,提供用户查询工具静态资源

3.1 项目初始化

bash 复制代码
mkdir mcp-demo && cd mcp-demo
npm init -y
npm install @modelcontextprotocol/sdk zod

3.2 编写 Server:my-mcp-server.mjs

先看完整代码,再逐段解析:

javascript 复制代码
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import { z } from 'zod';

// 模拟数据库
const database = {
    users: {
        '001': { id: '001', name: 'zh', email: 'zh@qq.com', role: 'admin' },
        '002': { id: '002', name: 'gg', email: 'gg@qq.com', role: 'user' },
        '003': { id: '003', name: 'xh', email: 'xh@qq.com', role: 'user' },
    }
};

const server = new McpServer({
    name: 'my-mcp-server',
    version: '1.0.0'
});

// ---------- 注册 Tool ----------
server.registerTool('query_user', {
    description: '查询数据库中的用户信息,输入用户ID,返回该用户的详细信息(姓名、邮箱、角色)',
    inputSchema: {
        userId: z.string().describe('用户ID,例如:001,002,003'),
    }
}, async ({ userId }) => {
    const user = database.users[userId];
    if (!user) {
        return {
            content: [
                { type: 'text', text: `用户 ID ${userId} 不存在. 可用的ID: 001,002,003` }
            ]
        };
    }
    return {
        content: [
            {
                type: 'text',
                text: `用户 ID ${userId} 信息是:
                姓名:${user.name}
                邮箱:${user.email}
                角色:${user.role}`
            }
        ]
    };
});

// ---------- 注册 Resource ----------
server.registerResource(
    '使用指南',
    'docs://guide',  // URI 标识
    {
        description: 'MCP Server 使用指南',
        mimeType: 'text/plain',
    },
    async () => {
        return {
            contents: [
                {
                    uri: 'docs://guide',
                    mimeType: 'text/plain',
                    text: `
                    MCP Server 使用指南
                    功能:提供用户查询等工具。
                    使用:在 Cursor 等 MCP Client 中通过自然语言对话,Cursor 会自动调用相应工具。
                   `
                }
            ]
        };
    }
);

// ---------- 启动 stdio 传输 ----------
const transport = new StdioServerTransport();
await server.connect(transport);

关键点解读

  • StdioServerTransport :通过标准输入输出与父进程通信。当你的Agent以子进程方式启动这个Server时,双方通过stdin/stdout交换JSON-RPC消息。
  • Tool注册 :用registerTool定义名称、描述、参数Schema(zod校验),执行逻辑返回content数组,支持多种类型(如text、image)。
  • Resource注册registerResource定义URI(类似URL,但用于本地标识),提供只读数据。Resource可以当作静态文档、配置、知识库片段等,Client可以读取并注入到System Prompt中。

3.3 Server 核心执行流程


四、Agent集成:用LangChain MCP适配器调用Server

有了Server,我们还需要一个Agent(Client)来消费它。这里我们用LangChain + MCP适配器。

4.1 安装依赖

bash 复制代码
npm install @langchain/mcp-adapters @langchain/openai dotenv chalk

4.2 编写 Client:langchain-mcp-test.mjs

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

// 1. 创建 MCP Client,配置要连接的 Server
const mcpClient = new MultiServerMCPClient({
    mcpServers: {
        'my-mcp-server': {
            command: 'node',
            args: ['E:\workspace\lgl_ai\ai\agent_in_action\mcp-demo\src\my-mcp-server.mjs']
        }
    }
});

// 2. 初始化 LLM(DeepSeek为例)
const model = new ChatOpenAI({
    modelName: 'deepseek-v4-flash',
    apiKey: process.env.DEEPSEEK_API_KEY,
    configuration: {
        baseURL: 'https://api.deepseek.com/v1',
    }
});

// 3. 从 MCP Server 获取工具和资源
const tools = await mcpClient.getTools();
const resourcesMap = await mcpClient.listResources();

// 4. 读取所有资源内容,拼成 System Prompt
let resourceContent = '';
for (const [serverName, resources] of Object.entries(resourcesMap)) {
    for (const resource of resources) {
        const content = await mcpClient.readResource(serverName, resource.uri);
        resourceContent += content[0].text;
    }
}
console.log('资源内容:\n', resourceContent);

// 5. 绑定工具到模型
const modelWithTools = model.bindTools(tools);

// 6. Agent 循环
async function runAgentWithTools(query, maxIterations = 30) {
    const messages = [
        new SystemMessage(resourceContent), // 资源作为系统消息
        new HumanMessage(query)
    ];

    for (let i = 0; i < maxIterations; i++) {
        console.log(chalk.bgGreen(`正在等待AI思考, 第 ${i + 1} 轮....`));
        const response = await modelWithTools.invoke(messages);
        messages.push(response);

        if (!response.tool_calls || response.tool_calls.length === 0) {
            console.log(`\n AI 最终回复: ${response.content}`);
            return response.content;
        }

        console.log(chalk.bgBlue(`检测到 ${response.tool_calls.length} 个工具调用: ${response.tool_calls.map(t => t.name).join(', ')}`));

        for (const toolcall of response.tool_calls) {
            const foundTool = tools.find(t => t.name === toolcall.name);
            if (foundTool) {
                const toolResult = await foundTool.invoke(toolcall.args);
                messages.push(new ToolMessage({
                    content: toolResult,
                    tool_call_id: toolcall.id
                }));
            }
        }
    }
    return messages[messages.length - 1].content;
}

// 执行测试
// await runAgentWithTools('查一下用户002的信息');
await runAgentWithTools('MCP Server使用指南是什么?');

// 7. 关闭所有连接,释放子进程
await mcpClient.close();

4.3 代码要点剖析

  • MultiServerMCPClient :可以管理多个MCP Server的连接,每个Server通过command + args启动子进程,基于stdio通信。
  • getTools() :自动将Server注册的Tool转换为LangChain兼容的StructuredTool,可直接调用。
  • listResources() + readResource() :读取所有Resource的内容,我们将其拼成SystemMessage,作为LLM的固定上下文。这是除RAG之外另一种丰富上下文的手段。
  • Agent循环:标准ReAct风格,模型自主决策是否调用工具,直到不再调用工具为止。
  • 释放资源mcpClient.close()会终止子进程并清理通信通道,避免脚本一直挂起。

4.4 Client 核心执行流程

4.5 stdio通信时序图


五、Resource的妙用:不只是静态文档

细心的读者会发现,我们把Resource内容直接塞进了SystemMessage。这有什么好处?

  • 轻量上下文增强:对于不常变化的知识(如使用指南、API文档、业务规则),没必要每次都走RAG检索,直接作为System Prompt的一部分,既省时又省钱。
  • 扩展性:Resource可以是本地文件、数据库查询结果、甚至远程API返回的只读数据,只要Server注册了对应URI,Client就能读取。

金句:Tool让Agent能"动手",Resource让Agent能"懂行"。两者结合,才能真正扩展LLM的认知边界。


六、踩坑与进阶思考

6.1 stdio通信注意事项

  • 子进程必须通过stdio传输,确保stdout只输出MCP协议消息,避免夹杂console.log等调试信息,否则解析会失败。
  • 若Server启动失败,Client可能卡住,建议加超时机制。

6.2 多语言支持

MCP协议不限制语言。你可以用Python、Rust、Java等实现Server,只要遵循JSON-RPC消息规范,Agent都能通过stdio或HTTP调用。这正是MCP最大的魅力------工具生态不再受技术栈约束

6.3 远程Server

transport替换为SSEServerTransportWebSocketServerTransport,即可支持HTTP远程调用,配合身份认证,企业级分布式Agent架构就搭建起来了。


七、总结:MCP让Agent开发进入"乐高时代"

我们从一个痛点出发,理解了MCP如何通过标准化协议解耦LLM和工具/资源。通过实战代码,你学会了:

  1. 用Node.js实现一个MCP Server,注册Tool和Resource。
  2. 用LangChain的MCP适配器作为Client,集成到Agent中。
  3. 利用Resource注入System Prompt,丰富上下文。
  4. 通过流程图和时序图,深入理解跨进程通信和Agent循环机制。

MCP的本质,是给AI Agent打造了一个"万能工具箱"的接口标准。从此,不同语言、不同团队开发的工具可以像积木一样自由组合,极大提升了Agent的可扩展性和复用性。

未来,随着MCP生态的成熟,我们或许会看到大量公共MCP Server出现,就像今天的NPM或PyPI一样,让Agent开发真正进入"乐高时代"。

相关推荐
武子康1 小时前
🔥 GPT-5.6 有限预览全拆解:Sol/Terra/Luna 三档定价 + max/ultra 双推理 + 缓存 1.00×/1.25×/0.10× 三倍
人工智能·chatgpt·openai
CTA终结者1 小时前
近期AI量化工具推荐,围绕最难推进的环节选择
人工智能·python
无糖可可果1 小时前
MCP(Model Context Protocol)入门与实践:让 AI Agent 跨进程调用工具
人工智能
无糖可可果1 小时前
远程 MCP 实战:让 AI 成为「千里眼」和「魔术手」
人工智能
wuhanzhanhui1 小时前
从芯片到精密制造:2026武汉电子元器件、材料及生产设备展会见证微观世界的跃迁
大数据·人工智能
冬奇Lab1 小时前
每日一个开源项目(第156篇):OpenDataLoader PDF - 基准测试第一名的开源 PDF 解析器,专为 RAG 设计
人工智能·开源·资讯
冬奇Lab1 小时前
MCP 系列(03):生态导航——官方 Server 清单与社区精选
人工智能·资讯·mcp
百胜软件@百胜软件1 小时前
百胜软件推出RT业务:零售技术服务全链路飞轮如何助力品牌商“降本+增收”?
大数据·人工智能·零售
AGI_Eval1 小时前
姚顺雨的“半年考”:Hy3用21B激活参数,交出了一份怎样的答卷?
人工智能