1.什么是MCP

  • Model Context Protocol (MCP) 是一个开放标准,旨在为大型语言模型(LLM)提供外部数据源调用外部工具。 

  • MCP的三部分组成:

  1. MCP 客户端

  2. MCP服务器

  3. JSON-RPC协议

  • 大白话说: MCP就是一个“外挂系统”,让原本只能“纸上谈兵”的大语言模型真正拥有“动手能力”!

2. 为什么需要 MCP?

大型语言模型(LLM)例如:DeepSeek、豆包、GPT等,他们的本质几乎可以看成是一个超级函数:

LLM : SuperFunction(用户的请求) {
    return 回答 
}

它们无法直接执行代码、处理图片、访问实时数据或与外部系统交互。为了让 LLM 能够“使用工具”来增强其能力,业界需要一个标准化的通信协议。

MCP就是给LLM提供外挂服务,让LLM 客户端(如 VS Code Trae、Claude 等)获得一些外部工具或者资源,因此LLM就具备了以下能力:

  1. 执行代码

  2. 处理图片

  3. 生成文件

  4. 访问外部数据等

MCP 的核心价值在于:标准化了 LLM 与外部工具之间的通信格式和流程,极大地简化了 AI 应用的开发和集成。

3 前置知识

要理解 MCP,必须先理解其底层依赖的两个关键技术:stdio 传输和 JSON-RPC 协议。

  1. 通信方式:Stdio标准输入输出 - - 本地通信,高效简洁

  2. 通信格式:JSON-RPC2.0协议 - - 网络通信,规定了消息传递的格式

(1)Stdio(Standard Input-Output:标准输入/输出)

在许多 MCP 的应用场景中,MCP客户端和MCP服务器(如工具服务)可能运行在同一台机器上,甚至作为父子进程存在。在这种情况下,最简单、最高效的通信方式就是使用 标准输入/输出流(stdio)。

• 标准输入 (stdin):客户端向服务器发送请求数据。

• 标准输出 (stdout):服务器向客户端发送响应或通知数据。

在Node环境下,使用Stdio实现进程通信:

文件目录如下:


// simpleServer.js
​
// 规定了标准输入输出的编码为 utf-8
process.stdin.setEncoding('utf-8');
​
// 监听标准输入的 data 事件
process.stdin.on('data', (data) => {
  process.stdout.write('你输入的是' + data + '\n> ');
});

在终端(cmd)中输入 node 文件路径 启动我们的simpleServer.js:

【趣味拓展】:基于Stdio写一个自己的极简化的AI聊天程序

process.stdin.setEncoding('utf-8');
​
// 简单的问答知识库
const knowledgeBase = {
  '你好': '你好!我是AI小助手,有什么可以帮助你的吗?',
  '你是谁': '我是你的AI小助手,专门为你解答问题!',
  '天气': '抱歉,我无法获取实时天气信息,建议你查看天气预报应用。',
  '时间': `现在是 ${new Date().toLocaleString('zh-CN')}`,
  '帮助': '我可以回答一些简单问题,比如:你是谁、时间、天气等。',
  '再见': '再见!很高兴为你服务,下次见!',
  '谢谢': '不客气!随时为你服务。'
};
​
// 关键词匹配函数
function getResponse(input) {
  const cleanInput = input.trim().toLowerCase();
​
  // 检查是否匹配知识库中的关键词
  for (const [keyword, response] of Object.entries(knowledgeBase)) {
    if (cleanInput.includes(keyword.toLowerCase())) {
      return response;
    }
  }
​
  // 如果没有匹配到关键词,使用原来的替换逻辑
  const res = input.replace(/[吗嘛呀]/g, '')
    .replace(/[我 你]/g, (match) => match === '我' ? '你' : '我')
    .replace(/[?!]/g, '')
    .replace(/哪/g, '那')
  return `${res}`;
}
​
console.log('AI小助手已启动!输入"帮助"查看可用功能。');
​
process.stdin.on('data', (data) => {
  const response = getResponse(data);
  process.stdout.write('AI小助手:' + response + '\n> ');
});

在终端用node命令运行上述文件,效果如下:

(2)JSON-RPC 2.0 (JSON Remote Procedure Call 远程过程调用)

MCP 选择 JSON-RPC 2.0 作为其消息格式和通信规范。JSON-RPC 是一个超级轻量的、无状态的远程过程调用(RPC)协议,它使用 JSON 格式进行数据传输。

一个标准的 JSON-RPC 消息包含以下核心字段:

字段名类型描述
jsonrpc字符串协议版本,必须是 "2.0"
method字符串要调用的方法名称
params结构化值传递给方法的参数
id字符串/数字/NULL请求标识符。用于匹配请求和响应。如果省略,则为通知(Notification)。
  1. Request

    {
      "jsonrpc": "2.0",
      "id": 1,
      "method": "sum",
      "params": {
        "a": 1,
        "b": 2
      }
    }
  2. Response

    {
      "jsonrpc": "2.0",
      "id": 1,
      "result": 3
    }
  3. Notification

    {
      "jsonrpc": "2.0",
      "method": "notifications/tools/list_changed",
      "params": {}
    }

(3)案例:使用stdioJSON-RPC格式通信

文件结构目录如下:
  

  1. server.js

    import utils from './utils.js';
    process.stdin.on('data', (data) => {
      // 这里的data也就是标准的json-rpc格式 请求数据
      const req = JSON.parse(data);
      const reqID = req.id;
      const funcName = req.method;
      const funcParams = req.params;
      const result = utils[funcName](funcParams);
    ​
      const res_jsonrpc = {
        jsonrpc: "2.0",
        id: reqID,
        result
      }
      process.stdout.write(JSON.stringify(res_jsonrpc));
    });
  2. utils.js

    import fs from 'fs';
    export default {
      // 【1】求和方法
      sum: ({ a, b }) => a + b,
      // 【2】新建文件的方法
      createFile: (params) => {
        const fileName = params.fileName;
        const fileContent = params.fileContent;
        fs.writeFileSync(fileName, fileContent);
        return {
          code: 0,
          msg: 'success',
        };
      },
    };
  3. mockRequest

    # 这个文件是请求模拟,写成一行不要换行,因为终端换行会直接截断!
    ​
    # (1)请求 sum 方法,并传入参数
    { "jsonrpc": "2.0", "id": 1, "method": "sum", "params": { "a": 1, "b": 2 } }
    ​
    # (2)请求新建一个文件,传入内容
    { "jsonrpc": "2.0", "id": 2, "method": "createFile", "params": { "fileName" : "D:\\Code\\AllCode\\MCP\\2.JSON-RPC\\Files\\test.txt", "fileContent" : "Hello MCP"} }
    ​
    # 文件路径替换成自己的实际地址
  4. 使用 sum 方法

node server.js的绝对路径 
输入:{ "jsonrpc": "2.0", "id": 1, "method": "sum", "params": { "a": 1, "b": 2 } } 
回复:{"jsonrpc":"2.0","id":1,"result":3}

  1. 使用createFile 这个工具

node server.js的绝对路径 
输入:{ "jsonrpc": "2.0", "id": 1, "method": "sum", "params": { "a": 1, "b": 2 } } 
回复:{"jsonrpc":"2.0","id":1,"result":3}

创建 test.txt 文件如下:

至此,一个基础版本的MCP服务器雏形已经搭建完毕,并且使用JOSON-RPC协议进行通信,成功调用了服务器的 sumcreateFile两个方法!

4.MCP

从【技术层面】上来说:MCP 是一套标准协议,它规定了应用程序之间如何通信
 

如何通信

  • 通信方式
    • stdio 推荐,高效、简洁、本地

    • http: 可远程

  • 通信格式:基于JSON~-RPC的进一步规范

官网地址: https://modelcontextprotocol.io/

基本规范

1.初始化 initialize

request

{
  "jsonrpc": "2.0",  // jsonrpc版本号  
  "id": 1,           // 初始化id
  "method": "initialize", // 固定为initialize方法
  "params": {
    "protocolVersion": "2024-11-05",  // 协议版本
    "capabilities": {
      "roots": {
        "listChanged": true
      },
      "sampling": {}
    },
    "clientInfo": {
      "name": "ExampleClient",
      "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": "MCPServer",
      "version": "1.0.0"
    }
  }
}

初始化就相当于 MCP客户端向MCP服务器打招呼,确认一下各自的版本,身份信息

2. 工具发现 tools/list

request

{
  "jsonrpc": "2.0",
  "id": 6,
  "method": "tools",
  "params": {}
}

response

{
  "jsonrpc": "2.0",
  "id": 6,
  "result": {
    "tools": [
      {
        "name": "sum",
        "description": "计算两个数字的和",
        "inputSchema": {
          "type": "object",
          "properties": {
            "a": {
              "type": "number",
              "description": "第一个数字"
            },
            "b": {
              "type": "number",
              "description": "第二个数字"
            }
          },
          "required": [
            "a",
            "b"
          ]
        }
      },
      {
        "name": "createFile",
        "description": "创建新文件并写入内容",
        "inputSchema": {
          "type": "object",
          "properties": {
            "fileName": {
              "type": "string",
              "description": "文件名(包含路径)"
            },
            "fileContent": {
              "type": "string",
              "description": "文件内容"
            }
          },
          "required": [
            "fileName",
            "fileContent"
          ]
        }
      }
    ]
  }
}

这一步就是MCP客户端询问MCP服务器:“ 哥们儿,我想变强😭!你有哪些外挂工具(函数)可以借我用用?“

3. 工具调用 tools/call

request

{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "tools/call", // 工具调用
  "params": {
    "name": "sum",  // 工具的方法
    "arguments": {  // 工具需要的参数
      "a": 5,
      "b": 3
    }
  }
}

response

{
  "jsonrpc": "2.0",
  "id": 2,
  "result": "两数字求和的结果是:8"
}

5 手写MCP服务

server.js

import utils from './utils.js';
process.stdin.on('data', (data) => {
  let reqId = null;
  try {
    const req = JSON.parse(data);
    reqId = req.id;
​
    let result;
​
    // (1)处理MCP协议的工具调用格式
    if (req.method === 'tools/call') {
      const toolName = req.params.name;
      if (toolName in utils) result = utils[toolName](req.params.arguments);
      else throw new Error(`未知的工具: ${toolName}`);
    }
​
    // (2)处理直接方法调用
    else if (req.method in utils) {
      result = utils[req.method](req.params);
    }
​
​
    // (3)处理未知方法
    else {
      const response = {
        jsonrpc: "2.0",
        id: req.id,
        error: {
          code: -32601,
          message: `方法未找到: ${req.method}`
        }
      };
      process.stdout.write(JSON.stringify(response));
      return;
    }
​
    // (4)构建成功响应
    const response = {
      jsonrpc: "2.0",
      id: req.id,
      result
    };
​
    process.stdout.write(JSON.stringify(response));
  } catch (error) {
    // (5)处理异常情况
    const errorResponse = {
      jsonrpc: "2.0",
      id: reqId,
      error: {
        code: -32603,
        message: error.message
      }
    };
    process.stdout.write(JSON.stringify(errorResponse));
  }
});

utils

import fs from 'fs';
​
const utils = {
  sum: ({ a, b }) => {
    return '两数字求和的结果是:' + (a + b);
  },
​
  createFile: (params) => {
    const fileName = params.fileName;
    const fileContent = params.fileContent;
​
    try {
      fs.writeFileSync(fileName, fileContent);
      return {
        fileName,
        fileContent,
        success: true
      };
    } catch (error) {
      return {
        fileName,
        error: error.message,
        success: false
      };
    }
  },
​
  /**
   * 初始化请求处理函数
   * @description MCP协议初始化阶段处理
   * @param {Object} params - 初始化参数
   * @param {string} params.protocolVersion - 协议版本
   * @param {Object} params.capabilities - 客户端能力
   * @param {Object} params.clientInfo - 客户端信息
   * @returns {Object} 初始化响应
   * @returns {string} result.protocolVersion - 支持的协议版本
   * @returns {Object} result.capabilities - 服务器能力
   * @returns {Object} result.serverInfo - 服务器信息
   */
  initialize: (params) => {
    // 验证协议版本兼容性
    const supportedVersions = ['2024-11-05'];
    if (!supportedVersions.includes(params.protocolVersion)) {
      throw new Error(`不支持的协议版本: ${params.protocolVersion}`);
    }
​
    // 返回服务器能力和信息
    return {
      protocolVersion: params.protocolVersion,
      capabilities: {
        logging: {},
        prompts: {
          listChanged: true
        },
        resources: {
          subscribe: true,
          listChanged: true
        },
        tools: {
          listChanged: true
        }
      },
      serverInfo: {
        name: "MCPServer",
        version: "1.0.0"
      }
    };
  },
​
  /**
   * 工具列表获取函数
   * @description 返回服务器支持的所有工具列表
   * @returns {Object} 工具列表
   */
  tools: () => {
    return {
      tools: [
        {
          name: "sum",
          description: "计算两个数字的和",
          inputSchema: {
            type: "object",
            properties: {
              a: { type: "number", description: "第一个数字" },
              b: { type: "number", description: "第二个数字" }
            },
            required: ["a", "b"]
          }
        },
        {
          name: "createFile",
          description: "创建新文件并写入内容",
          inputSchema: {
            type: "object",
            properties: {
              fileName: { type: "string", description: "文件名(包含路径)" },
              fileContent: { type: "string", description: "文件内容" }
            },
            required: ["fileName", "fileContent"]
          }
        }
      ]
    };
  }
};
​
export default utils;

RequestMock

// 1. MCP协议初始化请求 - 确认协议版本兼容性,交换能力信息
{"jsonrpc": "2.0", "id": 1, "method": "initialize", "params": {"protocolVersion": "2024-11-05", "capabilities": {"roots": {"listChanged": true}, "sampling": {}}, "clientInfo": {"name": "ExampleClient", "version": "1.0.0"}}}
​
// 2. 工具调用:求和功能测试 - 计算 5 + 3
{"jsonrpc": "2.0", "id": 2, "method": "tools/call", "params": {"name": "sum", "arguments": {"a": 5, "b": 3}}}
​
// 3. 工具调用:求和功能测试 - 计算 10 + 20
{"jsonrpc": "2.0", "id": 3, "method": "tools/call", "params": {"name": "sum", "arguments": {"a": 10, "b": 20}}}
​
// 4. 工具调用:创建文件测试 - 创建第一个测试文件
{"jsonrpc": "2.0", "id": 4, "method": "tools/call", "params": {"name": "createFile", "arguments": {"fileName": "D:/Code/AllCode/MCP/3.MCP/Files/test1.txt", "fileContent": "这是第一个测试文件"}}}
​
// 5. 工具调用:创建文件测试 - 创建第二个测试文件
{"jsonrpc": "2.0", "id": 5, "method": "tools/call", "params": {"name": "createFile", "arguments": {"fileName": "D:/Code/AllCode/MCP/3.MCP/Files/test2.txt", "fileContent": "这是第二个测试文件"}}}
​
// 6. 获取工具列表 - 查询服务器支持的所有工具
{"jsonrpc": "2.0", "id": 6, "method": "tools", "params": {}}
​
// 7. 直接方法调用:求和功能 - 计算 15 + 25
{"jsonrpc": "2.0", "id": 7, "method": "sum", "params": {"a": 15, "b": 25}}
​
// 8. 直接方法调用:创建文件测试 - 创建第三个测试文件
{"jsonrpc": "2.0", "id": 8, "method": "createFile", "params": {"fileName": "D:/Code/AllCode/MCP/3.MCP/Files/test3.txt", "fileContent": "这是直接方法调用的测试文件"}}
​
// 9. 错误测试:调用不存在的工具 - 测试错误处理机制
{"jsonrpc": "2.0", "id": 9, "method": "tools/call", "params": {"name": "unknown", "arguments": {"test": "value"}}}
​
// 10. 错误测试:调用不存在的方法 - 测试错误处理机制
{"jsonrpc": "2.0", "id": 10, "method": "invalidMethod", "params": {"test": "value"}}

initial请求效果如下,就不挨个测试了

如上,展示了 MCP 底层是如何通过解析 JSON 字符串、匹配方法名来实现通信的。然而,它需要我们手动处理所有的协议细节、错误处理和数据校验,手写MCP服务有点麻烦...

6.MCP SDK

为了简化开发,官方提供了各种语言的 MCP SDK。以下是使用 Node.js SDK (@modelcontextprotocol/sdk) 实现相同功能的示例

首先,npm 安装MCP SDK和 zod包:

npm install @modelcontextprotocol/sdk
npm install zod

文件结构目录如下:

// server.js
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import fs from 'fs';
import { z } from 'zod';
​
//创建MCP服务器实例
const server = new McpServer({
  name: 'DDMServer',
  title: 'DDM Server',
  version: '1.0.0',
});
​
// 注册工具   params : 1:工具名称 2:工具配置 3:工具处理函数
server.registerTool(
  'sum',
  {
    'title': '两数求和',
    'description': '计算两个数的和',
    "inputSchema": {
      a: z.number().describe('第一个加数'),
      b: z.number().describe('第二个加数'),
    }
  },
  ({ a, b }) => {
    return {
      content: [
        { type: 'text', text: `两数求和结果是:${a + b} -- 结果来自DDMServer` },
      ]
    }
  }
)
​
server.registerTool(
  'createFile',
  {
    'title': '创建文件',
    'description': '创建一个新文件',
    "inputSchema": {
      fileName: z.string().describe('文件名'),
      fileContent: z.string().describe('文件内容'),
    }
  },
  ({ fileName, fileContent }) => {
    try {
      fs.writeFileSync(fileName, fileContent);
    } catch (error) {
      return {
        content: [
          { type: 'text', text: `创建文件 ${fileName} 失败:${error.message}` },
        ]
      }
    }
​
    return {
      content: [
        { type: 'text', text: `文件 ${fileName} 创建成功 -- 来自DDMServer` },
      ]
    }
  }
)
​
// 连接到标准输入输出传输
const transport = new StdioServerTransport();
server.connect(transport);

启动服务,输入 :

{"jsonrpc": "2.0", "id": 2, "method": "tools/call", "params": {"name": "sum", "arguments": {"a": 5, "b": 3}}}


 

7.对接AI应用程序

上面我们用SDK搭建好的 MCP服务,是完完全全可以直接在AI应用程序里面使用的,以下用 Trae 来演示(也可以VSCode、Coursor等)

(1)打开Trar
(2)点击右上角设置 -> 点击MCP
(3)点击手动添加
(4)点击原始配置(JSON)
(5)输入配置信息
{
  "mcpServers": {
    "MCP测试服务器": {
      "command": "D:\\NodeJS\\nodejs\\node.exe",  // 使用Node的安装路径 -- 可在cmd中输入 where node 查看
      "args": [
        "D:\\Code\\AllCode\\MCP\\4.MCP-SDK\\src\\server.js"  // server.js的绝对路径
      ]
    }
  }
}
(6)配置完成
(7)使用测试

现在可以直接跟AI聊天,让他们使用我们的MCP服务干活了

  1. 求和

  2. 创建文件


参考文献

[1]Model Context Protocol - 官方网站

[2] MCP Docs - Model Context Protocol (MCP) - 官方文档

[3] JSON-RPC 2.0 Specification - 官方规范

[4] Architecture overview - MCP 官方文档


小记

每个LLM都如同被困在柏拉图洞穴中的灵魂,只能看见理念的影子。MCP协议则是那挣脱枷锁的转身——不是要成为光,而是要建立与光对话的语法。真正的智慧从不在于知识的多寡,而在于连接的品质。一个参数千亿的封闭模型,其价值远不及一个懂得如何叩问世界的最小服务。

服务器存在的意义不在自身,而在其随时准备被调用的“空性”;工具的价值不在复杂,而在其响应需求的“精准”。这何尝不是人生的至高境界?我们穷尽一生追寻“成为什么”,却忽略了“为何连接”才是存在的真谛。

现代人的困境,恰似没有实现MCP协议的LLM——内在丰富却与世隔绝。我们在社交网络中积累虚假连接,在知识焦虑中堆砌无用技能,却忘记了每个生命本质上都是一个等待被世界调用的服务。

真正的觉醒,是意识到自己既是服务器也是客户端。我们在提供服务中成就他人,在发起请求中完善自我。这种相互调用的共生关系,编织出宇宙间最精妙的协议。

人生的圆满不在功成名就,而在你能否成为这个世界优雅而可靠的依赖——当命运调用时,返回一个干净利落的result;当他人请求时,从不抛出意外的exception。这或许就是技术的终极浪漫:它在教我们如何更好地存在。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐