前言:本地AI工具最大痛点
用Cursor、Claude Desktop这类支持MCP的AI工具时,有个很扎心的问题:
默认AI无法读取本地项目文件,只能手动复制粘贴代码丢给大模型。
文件一多、目录层级深,复制粘贴半小时起步,效率极低。
MCP(Model Context Protocol)就是用来解决这个问题的标准协议。
只需要写一个极简MCP服务,AI就能自主读取项目任意文件,不用人工复制代码。

读完这篇你能收获:
- 搞懂MCP完整通信流程,Stdio传输底层逻辑
- 30行完整可运行MCP文件读取服务代码
- Zod实现参数自动校验,不用手写JSON Schema
- 完整通信链路拆解,看懂AI怎么调用本地工具
- 避坑指南,快速接入Claude/Cursor等客户端
一、先搞懂:什么是MCP?完整通信链路
1.1 MCP核心作用
MCP 模型上下文协议,打通LLM和本地电脑、外部工具的桥梁。
允许AI自主调用本地能力:读文件、执行命令、访问接口、操作数据库。
1.2 完整数据流转流程
AI客户端(Claude/Cursor) → LLM大模型
→ LLM识别需要读取本地文件 → 下发工具调用指令
→ Stdio标准输入(stdin)传输指令到我们写的MCP服务
→ MCP服务执行fs读取本地文件
→ 文件内容通过标准输出(stdout)传回客户端
→ LLM结合本地文件内容完成回答
简单说:stdio作为通信管道,双向传输指令与数据。
1.3 项目依赖说明
两个核心包:
@modelcontextprotocol/sdk:MCP官方SDK,封装协议、传输通道、工具注册zod:参数校验库,自动生成工具入参校验规则,替代手写JSON Schema
二、项目初始化与完整代码实战
2.1 安装依赖
bash
npm install @modelcontextprotocol/sdk zod
2.2 项目目录
mcp-file-server/
├── server.js # MCP服务主文件
└── package.json
2.3 完整可运行代码 server.js
javascript
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
import fs from 'fs/promises';
// 1. 初始化MCP服务实例
const server = new McpServer({
name: 'simple-read-mcp',
version: '1.0.0'
});
// 2. 注册工具:读取本地文件
server.tool(
"read_file",
"读取指定路径的本地文件内容,支持相对/绝对路径",
{
// Zod自动做参数校验,自动生成协议所需schema
path: z.string().describe("文件绝对路径或项目相对路径")
},
// 工具执行逻辑
async ({ path }) => {
try {
// Node原生fs读取文件
const content = await fs.readFile(path, 'utf-8');
// MCP标准返回格式
return {
content: [{ type: "text", text: content }]
};
} catch (err) {
// 文件不存在/权限不足统一捕获错误
return {
isError: true,
content: [{ type: "text", text: `读取文件失败:${err.message}` }]
};
}
}
);
// 3. 启动服务,绑定stdio通信通道
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
// 日志输出到stderr,不干扰stdout协议通信
console.error("MCP 文件读取服务已启动(Stdio模式)");
}
main().catch(console.error);
2.4 启动服务命令
bash
node server.js
看到日志 MCP 文件读取服务已启动(Stdio模式) 代表服务就绪。
三、核心代码分段讲解
3.1 McpServer 服务实例
javascript
const server = new McpServer({
name: 'simple-read-mcp',
version: '1.0.0'
});
定义服务名称与版本,客户端识别工具服务的标识。
3.2 server.tool 工具注册(重点)
server.tool 是新版SDK极简注册方式,三层参数:
- 工具名称:
read_file,LLM识别调用的函数名 - 工具描述:告诉AI这个工具能做什么
- Zod参数Schema:自动校验入参,不用手动写JSON协议定义
- 回调函数:工具真正执行的业务逻辑
3.3 StdioServerTransport 通信通道
javascript
const transport = new StdioServerTransport();
await server.connect(transport);
MCP默认标准传输方式,依靠进程标准输入输出通信:
- stdin:接收AI客户端下发的调用指令
- stdout:向客户端返回文件内容结果
关键:日志必须用
console.error,console.log会污染stdout协议数据,导致通信崩溃。
3.4 文件读取异常捕获
统一捕获文件不存在、无读取权限、路径错误等异常,通过 isError 标记错误状态,客户端能正常识别报错信息。
四、接入客户端使用演示
以Claude Desktop为例:
- 打开Claude配置文件
claude_desktop_config.json - 在mcpServers中新增配置
json
{
"mcpServers": {
"file-reader": {
"command": "node",
"args": ["/你的项目路径/server.js"]
}
}
}
- 重启Claude客户端,AI自动识别
read_file工具 - 对话直接提问:
读取当前目录server.js完整代码
AI会自动调用MCP服务读取文件,无需手动复制粘贴。
五、开发高频踩坑提醒(必看避坑)
坑1:用console.log打印日志,MCP通信直接失效
stdout是协议专用传输通道,普通打印会打乱JSON消息流。
解决方案 :所有调试日志使用 console.error。
坑2:不做参数校验,AI传入非法路径报错
AI可能传入空路径、文件夹路径、不存在地址,直接读取会崩溃。
解决方案:使用z.string()强制校验path为字符串,提前拦截非法参数。
坑3:混淆相对路径与绝对路径,文件读取失败
不同客户端工作目录不一致,相对路径容易匹配不到文件。
解决方案:工具描述提示用户优先使用绝对路径读取文件。
坑4:忘记捕获fs读取异常,服务直接崩溃
文件删除、权限不足、路径错误都会抛出异步错误,无try-catch会让整个MCP服务终止。
解决方案:所有文件IO操作包裹try/catch,标准化错误返回。
坑5:旧版SDK手写JSON Schema,冗余难维护
老版本MCP需要手动写复杂JSON参数定义,新版直接用zod自动生成。
解决方案:全程使用zod做参数声明,大幅减少代码量。
六、扩展优化方向
- 新增批量读取工具 :新增
read_dir读取文件夹目录,AI可以遍历整个项目结构 - 新增文件写入工具 :拓展
write_file,支持AI自动修改、新建本地代码文件 - 路径白名单限制:增加目录白名单,禁止读取系统敏感文件,提升安全
- 缓存优化:缓存高频读取文件,减少重复磁盘IO
- 多工具集成:拓展命令执行、Git查询、接口请求等更多本地能力
七、全文总结
- MCP是打通AI与本地电脑的标准协议,Stdio是最通用的通信方式,零额外端口占用;
- 整套文件读取服务仅30行代码,依赖极少,Node环境开箱即用;
- Zod替代手写Schema,自动完成参数校验,降低开发成本;
- 通信核心逻辑:客户端指令→stdin→MCP服务执行文件操作→stdout返回内容给LLM;
- 适配Claude、Cursor等主流AI客户端,彻底告别手动复制本地文件代码。