MCP从零开始
1.什么是MCP
-
Model Context Protocol (MCP) 是一个开放标准,旨在为大型语言模型(LLM)提供外部数据源和调用外部工具。
-
MCP的三部分组成:
MCP 客户端
MCP服务器
JSON-RPC协议
-
大白话说: MCP就是一个“外挂系统”,让原本只能“纸上谈兵”的大语言模型真正拥有“动手能力”!
2. 为什么需要 MCP?
大型语言模型(LLM)例如:DeepSeek、豆包、GPT等,他们的本质几乎可以看成是一个超级函数:
LLM : SuperFunction(用户的请求) {
return 回答
}
它们无法直接执行代码、处理图片、访问实时数据或与外部系统交互。为了让 LLM 能够“使用工具”来增强其能力,业界需要一个标准化的通信协议。
MCP就是给LLM提供外挂服务,让LLM 客户端(如 VS Code Trae、Claude 等)获得一些外部工具或者资源,因此LLM就具备了以下能力:
执行代码
处理图片
生成文件
访问外部数据等
MCP 的核心价值在于:标准化了 LLM 与外部工具之间的通信格式和流程,极大地简化了 AI 应用的开发和集成。
3 前置知识
要理解 MCP,必须先理解其底层依赖的两个关键技术:stdio 传输和 JSON-RPC 协议。
通信方式:Stdio标准输入输出 - - 本地通信,高效简洁
通信格式: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)。 |
-
Request
{ "jsonrpc": "2.0", "id": 1, "method": "sum", "params": { "a": 1, "b": 2 } } -
Response
{ "jsonrpc": "2.0", "id": 1, "result": 3 } -
Notification
{ "jsonrpc": "2.0", "method": "notifications/tools/list_changed", "params": {} }
(3)案例:使用stdio以JSON-RPC格式通信
文件结构目录如下:
-
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)); }); -
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', }; }, }; -
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"} } # 文件路径替换成自己的实际地址 -
使用
sum方法
node server.js的绝对路径
输入:{ "jsonrpc": "2.0", "id": 1, "method": "sum", "params": { "a": 1, "b": 2 } }
回复:{"jsonrpc":"2.0","id":1,"result":3}

-
使用
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协议进行通信,成功调用了服务器的 sum、createFile两个方法!
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]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。这或许就是技术的终极浪漫:它在教我们如何更好地存在。
更多推荐





所有评论(0)