前言:本地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 安装依赖
npminstall@modelcontextprotocol/sdk zod2.2 项目目录
mcp-file-server/ ├── server.js # MCP服务主文件 └── package.json2.3 完整可运行代码 server.js
import{McpServer}from"@modelcontextprotocol/sdk/server/mcp.js";import{StdioServerTransport}from"@modelcontextprotocol/sdk/server/stdio.js";import{z}from"zod";importfsfrom'fs/promises';// 1. 初始化MCP服务实例constserver=newMcpServer({name:'simple-read-mcp',version:'1.0.0'});// 2. 注册工具:读取本地文件server.tool("read_file","读取指定路径的本地文件内容,支持相对/绝对路径",{// Zod自动做参数校验,自动生成协议所需schemapath:z.string().describe("文件绝对路径或项目相对路径")},// 工具执行逻辑async({path})=>{try{// Node原生fs读取文件constcontent=awaitfs.readFile(path,'utf-8');// MCP标准返回格式return{content:[{type:"text",text:content}]};}catch(err){// 文件不存在/权限不足统一捕获错误return{isError:true,content:[{type:"text",text:`读取文件失败:${err.message}`}]};}});// 3. 启动服务,绑定stdio通信通道asyncfunctionmain(){consttransport=newStdioServerTransport();awaitserver.connect(transport);// 日志输出到stderr,不干扰stdout协议通信console.error("MCP 文件读取服务已启动(Stdio模式)");}main().catch(console.error);2.4 启动服务命令
nodeserver.js看到日志MCP 文件读取服务已启动(Stdio模式)代表服务就绪。
三、核心代码分段讲解
3.1 McpServer 服务实例
constserver=newMcpServer({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 通信通道
consttransport=newStdioServerTransport();awaitserver.connect(transport);MCP默认标准传输方式,依靠进程标准输入输出通信:
- stdin:接收AI客户端下发的调用指令
- stdout:向客户端返回文件内容结果
关键:日志必须用
console.error,console.log会污染stdout协议数据,导致通信崩溃。
3.4 文件读取异常捕获
统一捕获文件不存在、无读取权限、路径错误等异常,通过isError标记错误状态,客户端能正常识别报错信息。
四、接入客户端使用演示
以Claude Desktop为例:
- 打开Claude配置文件
claude_desktop_config.json - 在mcpServers中新增配置
{"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客户端,彻底告别手动复制本地文件代码。