← 返回文章列表

一文读懂MCP理论:进程通信与协议规范全解析

在后端开发和进程交互中,MCP(Model Context Protocol)是一套关键的通信标准,它定义了应用程序之间如何高效、规范地传递数据。今天我们就从基础的进程、stdio通信入手,逐步拆解MCP协议的核心内容,搭配代码和图示,让抽象的技术知识变得直观易懂。
MCP Service 2025-11-26 07:01:37 评论 1

一、基础铺垫:进程与进程通信

首先我们要明确一个核心概念——进程:执行一个应用程序,就会启动一个进程,操作系统会为其分配独立的内存空间和系统资源。当应用程序执行完毕,系统分配的资源会被自动回收。

关键问题:如何让进程持续运行?

进程之间要实现通信,有一个最基本的前提:进程不能结束。就像我们常用的微信、QQ,启动后不会自动关闭,核心原因就是它们一直在“监听”用户操作和消息。

对应到代码中,我们可以通过监听输入让进程保持运行状态,以Node.js为例:

// 监听输入,让进程持续运行
process.stdin.on("data", () => {});

父子进程模型

除了让单个进程持续运行,一个进程还可以启动另一个进程,这就是操作系统中常用的「父子进程模型」。

比如我们在控制台输入以下命令启动Node程序时:

node index.js

此时,控制台就是「父进程」,启动的Node程序就是「子进程」,两者可以进行通信。

二、进程通信的核心:stdio 标准输入输出

当我们解决了进程持续运行的问题,下一步就是实现进程间的通信。其中最基础、最常用的方式就是 stdio(standard input and output,标准输入输出)。

每一个进程启动后,都会默认留出两个对外通信的接口:

  • 标准输入接口(standard in):用于接收外部数据(比如用户输入、其他进程传递的数据)

  • 标准输出接口(standard output):用于向外部输出数据(比如程序运行结果、向其他进程传递消息)

结合前面的父子进程模型,进程间的stdio通信可以用下图直观表示:

课堂实践:终端与Node进程通信

我们通过一个实际案例,看看终端(父进程)和Node程序(子进程)如何通过stdio通信。首先创建两个文件:server.js(服务端子进程)和client.js(客户端父进程)。

先看client.js的代码,它的作用是启动server.js子进程,并与子进程进行数据交互:

const { spawn } = require("child_process");

// 启动 server.js 子进程(相当于在终端执行 node server.js)
const serverProcess = spawn("node", ["server.js"]);

// 监听服务端子进程的输出,并将其输出到当前进程(终端)
serverProcess.stdout.on("data", (data) => {
    process.stdin.write(data.toString()); // 将子进程的输出写入当前进程的输入(终端显示)
});

// 向子进程发送3条测试消息,每秒发送一条
const messages = ["生命有意义吗?", "宇宙有尽头吗?", "再见!"];

messages.forEach((msg, index) => {
  setTimeout(() => {
    console.log(`-->${msg}`); // 终端打印发送的消息
    serverProcess.stdin.write(msg); // 向子进程发送消息
  }, index * 1000);
});

运行client.js后,终端与Node子进程的通信效果如下:

这里需要注意:stdio通信高效、简洁,但仅适用于本地进程间通信。如果需要实现远程进程通信,就需要用到HTTP等其他方式。

三、进程通信的通用格式:JSON-RPC2.0

进程间传递数据时,需要约定统一的格式,否则会出现数据混乱。常用的通信格式有XML、JSON、普通字符串等,其中最常用、最规范的是 JSON-RPC2.0。

JSON-RPC2.0 是一种远程函数调用协议,通过JSON格式传递请求和响应,核心分为「请求(request)」和「响应(response)」两部分。

1. 请求(request)格式

客户端向服务端发送请求时,需要包含以下核心字段:

  • jsonrpc:固定为 "2.0",表示使用JSON-RPC2.0协议

  • method:要调用的函数/方法名

  • params:调用函数时需要传递的参数

  • id:请求的唯一标识,用于匹配响应和请求

{
  "jsonrpc": "2.0",
  "method": "sum", // 要调用的方法(求和)
  "params": {
    "a": 5,
    "b": 6
  },
  "id": 1 // 唯一标识
}

2. 响应(response)格式

服务端收到请求后,会返回响应,核心字段包括:

  • jsonrpc:固定为 "2.0"

  • result:函数调用的结果(如果调用成功)

  • id:与请求的id一致,确保请求和响应对应

{
  "jsonrpc": "2.0",
  "result": 11, // 求和结果:5+6=11
  "id": 1 // 与请求id一致
}

四、核心重点:MCP Server 协议规范

了解了进程通信的基础(stdio)和格式(JSON-RPC2.0)后,我们正式进入MCP协议的核心。MCP是一套标准协议,它在JSON-RPC2.0的基础上,进一步规范了应用程序之间的通信方式和格式。

MCP协议规定的通信方式主要有两种:

  • stdio:推荐使用,高效、简洁,适用于本地进程通信

  • HTTP:支持远程通信,包括StreamHTTP、SSE两种方式

通信格式:基于JSON-RPC2.0的进一步规范,下面我们重点讲解MCP协议的3个核心操作。

1. 初始化(initialize):建立通信连接

两个应用程序要开始通信,首先需要完成初始化操作——客户端向服务端发送初始化请求,告知服务端自身信息和支持的能力,服务端返回自身信息和可提供的能力。

客户端请求(request):

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "initialize", // 固定方法名:initialize
  "params": {
    "protocolVersion": "2024-11-05", // MCP协议版本
    "capabilities": { // 客户端支持的能力
      "roots": {
        "listChanged": true
      },
      "sampling": {},
      "elicitation": {}
    },
    "clientInfo": { // 客户端信息
      "name": "ExampleClient",
      "title": "Example Client Display Name",
      "version": "1.0.0"
    }
  }
}

服务端响应(response):

{
  "jsonrpc": "2.0",
  "id": 1, 
  "result": {
    "protocolVersion": "2024-11-05", // 与客户端协议版本一致
    "capabilities": { // 服务端支持的能力
      "logging": {},
      "prompts": {
        "listChanged": true
      },
      "resources": {
        "subscribe": true,
        "listChanged": true
      },
      "tools": {
        "listChanged": true
      }
    },
    "serverInfo": { // 服务端信息
      "name": "ExampleServer",
      "title": "Example Server Display Name",
      "version": "1.0.0"
    },
    "instructions": "Optional instructions for the client" // 可选的客户端提示
  }
}

2. 发现工具(tools/list):查询服务端可调用工具

初始化完成后,客户端需要知道服务端有哪些工具函数可以调用,此时可以发送 tools/list 请求,服务端会返回所有可用工具的详细信息(名称、描述、参数格式等)。

客户端请求(request):

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/list" // 固定方法名:tools/list
}

服务端响应(response):

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "tools": [
      {
        "name": "get_weather", // 工具名(调用时需使用)
        "title": "Weather Information Provider", // 工具标题
        "description": "Get current weather information for a location", // 工具描述
        "inputSchema": { // 工具的参数格式要求
          "type": "object",
          "properties": {
            "location": {
              "type": "string",
              "description": "City name or zip code" // 参数说明
            }
          },
          "required": ["location"] // 必传参数
        }
      }
    ]
  }
}

3. 工具调用(tools/call):调用服务端工具

知道了服务端的可用工具后,客户端就可以通过 tools/call 请求调用具体的工具,传递对应的参数,服务端返回工具调用结果。

客户端请求(request):

{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "tools/call", // 固定方法名:tools/call
  "params": {
    "name": "get_weather", // 要调用的工具名(与tools/list返回的name一致)
    "arguments": { // 工具参数(与inputSchema格式一致)
      "location": "New York"
    }
  }
}

服务端响应(response):

{
  "jsonrpc": "2.0",
  "id": 2,
  "result": {
    "content": [ // 工具结果必须放在content字段中,多结果用数组
      {
        "type": "text", // 结果类型(支持多种类型,参考官方文档)
        "text": "72°F" // 工具调用结果
      }
    ]
  }
}

补充说明:工具返回的结果类型有多种(如text、image、table等),具体可参考 MCP官方文档。

思考:MCP服务端的兼容性

既然MCP是一套标准协议,那么只要是遵循MCP协议的应用程序,都可以与MCP服务端进行通信——这也是MCP协议的核心价值:统一通信标准,实现跨应用、跨进程的互联互通。

五、MCP调试工具:快速排查问题

开发MCP服务端时,我们可以使用官方提供的调试工具,快速查看通信过程、排查问题。操作非常简单:

在MCP服务端所在目录,直接在终端运行以下命令:

npx @modelcontextprotocol/inspector

运行后,工具会自动监听MCP服务端的通信过程,帮助我们直观看到请求和响应数据,大幅提升调试效率。

总结

今天我们从进程基础入手,逐步拆解了MCP协议的核心内容:

  • 进程是应用程序的运行实例,通过监听可以保持持续运行,父子进程模型是进程通信的基础;

  • stdio是本地进程通信的首选方式,高效简洁,适用于近距离进程交互;

  • JSON-RPC2.0是进程通信的通用格式,通过请求和响应实现规范的数据传递;

  • MCP协议在JSON-RPC2.0基础上,规范了初始化、工具发现、工具调用三大核心操作,支持本地和远程通信;

  • 官方调试工具可以快速排查MCP通信问题,提升开发效率。

评论: