首页
看点啥
插画图片
首页 看点啥 MCP 跨进程工具调用深度解析:自 LangChain Tool 的局限至自定义数据库查询 Server 实战

MCP 跨进程工具调用深度解析:自 LangChain Tool 的局限至自定义数据库查询 Server 实战

2026-07-13 0

MCP 跨进程工具调用深度解析:从 LangChain Tool 的局限到自定义数据库查询 Server 实战


前言

在前面的文章中,我们用 LangChain 的 tool() 函数注册了 read_fileexecute_command 等工具。它们工作得很好,但有一个根本性局限——只能在同一个 Node.js 进程中运行

MCP 跨进程工具调用深度解析:从 LangChain Tool 的局限到自定义数据库查询 Server 实战

这意味着:

MCP(Model Context Protocol) 正是为了解决这个问题而诞生的。它让 AI Agent 能够跨进程、跨语言地调用任何工具。


一、LangChain Tool 的局限性

1.1 回顾:LangChain tool() 的工作方式

 复制代码import { tool } from '@langchain/core/tools';const readFileTool = tool(
    async ({ filePath }) => {
        const content = await fs.readFile(filePath, 'utf-8');
        return content;
    },
    {
        name: 'read_file',
        description: '读取文件内容',
        schema: z.object({ filePath: z.string() })
    }
);// 工具直接注册到模型
const modelWithTools = model.bindTools([readFileTool]);

1.2 三个核心问题

问题说明
项目绑定read_file 只能在当前 Node.js 项目中使用,换一个项目就得重写
语言绑定只能用 JavaScript/TypeScript 编写,无法调用 Java/Python/Rust 工具
进程绑定工具函数和 LLM 运行在同一个进程中,无法独立部署、独立扩展
 复制代码LangChain Tool 的局限:  Agent(Node.js 进程)
  ├── tool1: read_file       写死在代码里
  ├── tool2: write_file      写死在代码里
  └── tool3: exec_command     写死在代码里  想加一个 Java 工具?→ 不行,进程语言是 Node.js
  想在另一个项目复用?→ 不行,代码耦合在项目里

1.3 理想方案:工具独立于 LLM

 复制代码理想架构:  AI Agent(任意语言/框架)
       ↓ MCP 协议
  Tool A(Node.js)── 查询数据库
  Tool B(Python)─── 数据分析
  Tool C(Java)───── 调用内部 API
  Tool D(Rust)───── 高性能计算  工具独立开发、独立部署、独立运行
  Agent 通过统一协议调用,不关心工具用什么语言写的

二、MCP 协议:跨进程工具调用的标准化方案

2.1 MCP 的核心定义

 复制代码MCP = Model Context Protocol(模型上下文协议)目标:标准化 LLM 与 Tool / Resource 之间的通信
本质:让 LLM 和 Tool 解耦

MCP 不是工具、不是框架、不是 SDK——它是一个通信协议,就像 HTTP 是浏览器和服务器之间的通信协议一样。

2.2 MCP 的两种通信方式

通信方式适用场景底层技术
stdio本地跨进程调用标准输入输出流(stdin/stdout)
HTTP/SSE远程跨进程调用网络请求
stdio 本地通信
 复制代码AI Agent(父进程)
    ↓ spawn 启动子进程
MCP Server(子进程)
    ├── 通过 stdin 接收 Agent 的请求(JSON-RPC)
    └── 通过 stdout 返回结果(JSON-RPC)

底层原理:当 Agent 启动一个 MCP Server 子进程时(类似 child_process.spawn),两者通过标准输入输出流通信。Agent 向子进程的 stdin 写入 JSON-RPC 消息,子进程处理后将结果写入 stdout。

HTTP 远程通信
 复制代码AI Agent(客户端)
    ↓ HTTP 请求
远程 MCP Server(服务器)
    ├── 接收请求
    ├── 调用工具
    └── 返回结果

2.3 MCP 和 fetch 的区别

笔记中有一个精准的区分:

维度fetch / HTTP APIMCP
目的获取数据(接口调用)扩展 Context(工具 + 资源)
协议HTTP + RESTJSON-RPC over stdio/HTTP
通信方向单次请求-响应持续的双向通信
能力只能传数据可以注册工具、暴露资源、持续交互

MCP 不是"调接口拿数据",而是"给模型装上新的能力"——它扩展的是 Context(上下文),让 LLM 能做的更多(Tool)、知道的更多(Resource)。

2.4 MCP 的本质

 复制代码MCP 的本质 = 给 Model 扩展 Context  Tool(工具)  → 让 LLM 能做更多(读文件、查数据库、发邮件)
  Resource(资源)→ 让 LLM 知道更多(内部文档、数据、配置)

三、实战:自定义数据库查询 MCP Server

3.1 项目结构

 复制代码my-mcp-server/
├── my-mcp-server.mjs   # MCP Server 代码(45行)
├── package.json
└── .mcp.json           # Claude Code 接入配置

3.2 完整代码

my-mcp-server.mjs

 复制代码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: '祖豪', email: '[email protected]', role: 'admin' },
    '002': { id: '002', name: '光光', email: '[email protected]', role: 'user' },
    '003': { id: '003', name: '小红', email: '[email protected]', role: 'user' },
  }
};// 创建 MCP Server 实例
const server = new McpServer({
  name: 'my-mcp-server',
  version: '1.0.0'
});// 注册工具
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: `用户 ${user.id} 的信息是:
        姓名:${user.name}, 邮箱:${user.email}, 角色:${user.role}`
      }
    ]
  };
});// 启动 stdio 传输
const transport = new StdioServerTransport();
await server.connect(transport);

3.3 代码逐行解析

第一步:模拟数据库

 复制代码const database = {
  users: {
    '001': { id: '001', name: '祖豪', email: '[email protected]', role: 'admin' },
    // ...
  }
};

这里用内存对象模拟数据库。实际项目中,可以替换为 MySQL、PostgreSQL、MongoDB 等真实数据库连接。MCP Server 的魅力就在于此——底层实现可以随意替换,对 Agent 来说接口不变

第二步:注册工具(registerTool vs tool)

注意这里用的是 server.registerTool,不是 LangChain 的 tool()

对比项LangChain tool()MCP server.registerTool()
注册位置LangChain 模型绑定MCP Server 实例
调用方式同进程函数调用跨进程 JSON-RPC
语言限制JavaScript only任何语言(有 MCP SDK 即可)
复用性项目内跨项目

第三步:输入参数

 复制代码inputSchema: {
  userId: z.string().describe('用户ID, 例如:001, 002, 003')
}

Zod Schema 定义了工具接受的参数类型和描述。MCP SDK 会将其自动转换为 JSON Schema 发送给 LLM。

第四步:返回格式

 复制代码return {
  content: [
    { type: 'text', text: '...' }
  ]
};

MCP 标准返回格式:content 数组,每个元素包含 typetext(或 image)。

3.4 接入 Claude Code

.mcp.json

 复制代码{
  "mcpServers": {
    "my-db": {
      "type": "stdio",
      "command": "node",
      "args": ["/path/to/my-mcp-server.mjs"]
    }
  }
}

使用方式

 复制代码⟩ 使用 my-db 工具查询用户 001 的信息

Claude Code 会自动:

  1. 分析请求 → 选择 my-db MCP Client
  2. 生成调用参数 { "userId": "001" }
  3. 通过 stdin 发送给我们的 MCP Server
  4. Server 查询数据库 → 返回结果
  5. LLM 基于结果生成回答

四、LangChain Tool vs MCP Tool 对比

4.1 架构对比

 复制代码LangChain Tool(同进程):  ┌─────────────────────────────┐
  │  Node.js 进程               │
  │                             │
  │  LLM ←→ tool() ←→ 函数体    │
  │       全部在一个进程内        │
  └─────────────────────────────┘
MCP Tool(跨进程):  ┌─────────────────────┐      ┌─────────────────────┐
  │  Agent 进程(Host)    │      │  MCP Server 进程      │
  │                     │      │                     │
  │  LLM ←→ MCP Client │ ←──→ │  MCP Server ←→ 工具  │
  │                     │ stdio│                     │
  └─────────────────────┘      └─────────────────────┘

4.2 完整对比表

维度LangChain ToolMCP Tool
通信方式同进程函数调用跨进程 JSON-RPC
语言支持JavaScript onlyNode.js / Python / Java / Rust ...
复用性项目内绑定跨项目、跨 Agent 复用
部署随 Agent 一起部署独立部署、独立运行
数据源内存中的函数任意(数据库、API、文件)
适用场景快速原型、简单工具生产环境、复杂工具链

4.3 何时用哪种?

场景推荐
项目 Demo / 快速验证LangChain tool()
只需在本项目使用的简单工具LangChain tool()
需要跨项目复用的工具MCP Server
需要用其他语言编写的工具MCP Server
需要独立部署的数据库/API 工具MCP Server
多个 Agent 共享同一套工具MCP Server

五、从内存数据库到真实数据库

5.1 替换为 MySQL

 复制代码import mysql from 'mysql2/promise';const pool = mysql.createPool({
  host: 'localhost',
  user: 'root',
  password: 'password',
  database: 'my_app'
});server.registerTool('query_user', {
  description: '查询 MySQL 数据库中的用户信息',
  inputSchema: {
    userId: z.string().describe('用户ID')
  }
}, async (userId) => {
  const [rows] = await pool.execute(
    'SELECT id, name, email, role FROM users WHERE id = ?', [userId]
  );
  if (rows.length === 0) {
    return { content: [{ type: 'text', text: `用户 ${userId} 不存在` }] };
  }
  const user = rows[0];
  return {
    content: [{
      type: 'text',
      text: `姓名:${user.name}, 邮箱:${user.email}, 角色:${user.role}`
    }]
  };
});

关键点:MCP Server 的接口(注册工具、返回格式)不变,只是底层实现从内存对象换成了 MySQL 连接。Agent 完全感知不到这个变化——这就是协议解耦的威力。


知识树

 复制代码MCP 跨进程工具调用深度解析
├── LangChain Tool 的局限
│   ├── 项目绑定(只能在本项目用)
│   ├── 语言绑定(只能用 JS)
│   └── 进程绑定(和 LLM 在同一进程)
├── MCP 协议
│   ├── Model Context Protocol(模型上下文协议)
│   ├── 核心目标:LLM 与 Tool/Resource 解耦
│   ├── 两种通信方式
│   │   ├── stdio(本地跨进程:stdin/stdout)
│   │   └── HTTP/SSE(远程跨进程)
│   ├── MCP vs fetch(扩展 Context vs 获取数据)
│   └── MCP 本质:给 Model 扩展 Context
├── 实战:数据库查询 MCP Server
│   ├── 模拟数据库 → 可替换为 MySQL/PG
│   ├── server.registerTool() 注册工具
│   ├── Zod Schema 参数定义
│   ├── MCP 标准返回格式(content 数组)
│   └── .mcp.json 接入 Claude Code
├── LangChain Tool vs MCP Tool 对比
│   ├── 同进程 vs 跨进程
│   ├── JS only vs 多语言
│   └── 何时用哪种
└── 进阶方向
    ├── 替换为真实数据库(MySQL)
    ├── 添加更多工具(增删改查)
    └── 多 Agent 共享同一 MCP Server

结语

从 LangChain tool() 到 MCP server.registerTool(),表面上看只是换了一种注册方式,本质上是一次架构升级

理解了这个区别,你就理解了 MCP 的核心价值:让工具独立于 LLM,让能力可以被任何 Agent 复用


参考与拓展阅读:


#MCP #Node.js #跨进程通信 #AIAgent #ToolCalling #掘金技术社区

喜欢(0)

上一篇

MCP协议深度解析:从代码出发:理解AI工具的万能接口

MCP协议深度解析:从代码出发:理解AI工具的万能接口

下一篇

MCP 系列(01):MCP 是什么——为何 Function Calling 不够

MCP 系列(01):MCP 是什么——为何 Function Calling 不够
猜你喜欢