从零构建 MCP 文件服务:50 行代码让 AI 读懂你的文件

手把手教你写一个 MCP Server:从零构建文件读取服务

前言

上篇我们聊了 MCP(Model Context Protocol)是什么,这次直接动手,用 Node.js 手写一个文件读取 MCP Server,并在 Trae 中实际跑起来。

目标:让 AI 能通过 MCP 协议安全地读取你指定的本地文件。

整体架构

MCP Server 的通信链路一句话概括:

c 复制代码
用户输入 → LLM 分析 → 匹配 MCP 工具 → StdioServerTransport → stdin → Server 执行 → stdout → 返回结果给 LLM

核心流程:AI 不直接操作文件系统,而是通过标准输入输出(stdio)把请求发给 Server,Server 执行后返回结果。这就是 MCP 的 "USB-C 协议" 本质。

项目初始化

bash 复制代码
mkdir simple-read-mcp && cd simple-read-mcp
pnpm init
pnpm i zod @modelcontextprotocol/sdk

两个核心依赖:

作用
@modelcontextprotocol/sdk MCP 协议通信层,提供 Server 和 Transport
zod 运行时 Schema 校验,定义工具的入参格式

编写 Server 代码

创建 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";

const server = new McpServer({
  name: "simple-read-mcp",
  version: "1.0.0",
});

server.tool(
  "read_file",
  "读取指定路径的本地文件内容",
  {
    path: z.string().describe("文件的绝对或相对路径"),
  },
  async ({ path }) => {
    try {
      const content = await fs.readFile(path, "utf-8");
      return {
        content: [{ type: "text", text: content }],
      };
    } catch (err) {
      return {
        isError: true,
        content: [{ type: "text", text: `读取文件失败:${err.message}` }],
      };
    }
  },
);

async function main() {
  const transport = new StdioServerTransport();
  await server.connect(transport);
  console.error("MCP read_file 服务已启动(stdio模式)");
}

main().catch(console.error);

代码解读

第一步:实例化 Server

javascript 复制代码
const server = new McpServer({
  name: "simple-read-mcp",
  version: "1.0.0",
});

给 Server 起个名字和版本号,方便调试和区分。

第二步:注册 Tool

javascript 复制代码
server.tool(
  "read_file",                              // 工具名
  "读取指定路径的本地文件内容",               // 描述(LLM 靠这个判断何时调用)
  { path: z.string().describe("...") },     // 参数 Schema
  async ({ path }) => { ... }               // 执行逻辑
);

新版 SDK 的 server.tool() 用 zod 定义参数 Schema,不再需要手写 JSON Schema,非常简洁。LLM 会阅读工具描述和参数说明,自行判断何时调用这个工具。

第三步:启动 stdio 通信

javascript 复制代码
const transport = new StdioServerTransport();
await server.connect(transport);

StdioServerTransport 通过标准输入输出与客户端通信------客户端通过 stdin 发请求,Server 通过 stdout 返回结果。这是 MCP 最常用的本地通信方式。

配置 Trae 客户端

在 Trae 的 mcp.json(路径:C:\Users\你的用户名\AppData\Roaming\Trae CN\User\mcp.json)中添加:

json 复制代码
{
  "mcpServers": {
    "simple-read-mcp": {
      "command": "node",
      "args": ["文件路径名"]
    }
  }
}
  • "simple-read-mcp":给这个 Server 起一个在 Trae 中使用的名字
  • "command": "node":用 Node.js 运行
  • "args":Server 文件的绝对路径

重启 Trae 后,就可以在对话中直接调用这个工具了。

实际效果

配置生效后,在 Trae 中说:

"请使用 simple-read-mcp 读取 server.js 的内容"

AI 会自动:

  1. 分析你的意图
  2. 匹配到 read_file 工具
  3. 通过 stdio 把 { path: "d:/workspace/.../server.js" } 发给 Server
  4. Server 读取文件并返回内容
  5. AI 展示给你看

整个过程对用户完全透明,就像 AI 自己会读文件一样。

为什么不用 fs 直接读?

你可能会想:Node.js 本身就能 fs.readFile,为什么要通过 MCP?

关键在于安全边界

  • 直接调用:AI 可以访问任何路径,风险不可控
  • MCP 方式:Server 可以加上路径白名单、权限校验等逻辑,把文件访问限制在安全范围内

在生产环境中,你还可以在 Server 里加入日志记录、限流、加密等能力,这正是 MCP 作为"中间层"的价值。

总结

一个完整的 MCP Server 只需要三步:

步骤 做的事情 关键 API
实例化 创建 Server new McpServer()
注册工具 声明功能 + Schema + 逻辑 server.tool()
启动通信 通过 stdio 连接客户端 StdioServerTransport + server.connect()

加上客户端的 mcp.json 配置,总共不到 50 行代码,就让 AI 获得了安全的文件读取能力。

掌握了这个模式,你可以轻松扩展出更多能力:写文件、搜索文件、调用 API、操作数据库......MCP 的想象空间才刚刚打开。

相关推荐
DogDaoDao6 小时前
AI 编程 IDE 全景解析 2026:Agent 全面接管开发链路
ide·人工智能·程序员·ai编程·claude·cursor·ai agent
AskHarries9 小时前
用 OpenClaw 写邮件:草稿、润色、回复、跟进和批量邮件
程序员
不焦躁的程序员9 小时前
程序员该补获客能力了
人工智能·程序员
陈随易1 天前
Rust、Golang、MoonBit 编译成 WASM,体积和速度差距有多大?
前端·后端·程序员
阿里嘎多学长1 天前
2026-07-03 GitHub 热点项目精选
开发语言·程序员·github·代码托管
只会写代码1 天前
一套开箱即用实体反射Lambda链式工具,彻底告别原生反射样板代码
java·程序员·源码
AskHarries1 天前
用 OpenClaw 做数据分析报告:CSV / Excel 到可视化结果
程序员
两万五千个小时1 天前
Claude Code 上下文管理(二):零 Token 消耗的压缩三板斧
人工智能·程序员·开源
陈随易2 天前
编程语言级别的Skill市场,AI Agent 的未来形态
前端·后端·程序员