30款热门AI模型一站整合DeepSeek/GLM/Qwen 随心用限时 5 折。 点击领海量免费额度最近在尝试将 AI 助手如 Claude、Cursor深度集成到我的本地开发工作流中时遇到了一个核心痛点如何让 AI 安全、可控地访问我本地的代码库、数据库、API 文档等私有资源直接上传文件有泄露风险手动复制粘贴又太低效。直到我发现了Model Context Protocol (MCP)这个新兴标准以及围绕它构建的MCP Server生态才找到了一个优雅的解决方案。本文将以一个实战项目为例手把手带你从零构建一个能够流式传输数据的 MCP Server。我们将深入 MCP 的核心概念利用现成的Boot Starters快速搭建并实现一个名为Streamable-HT的服务器让 AI 助手能够实时、安全地读取你指定的本地文件内容。无论你是想提升开发效率还是对 AI 智能体Agent的底层交互协议感兴趣这篇文章都能为你提供一套完整、可落地的实操指南。1. MCP 核心概念为什么它是 AI 开发工作流的关键拼图在深入代码之前我们必须先理解 MCP 解决了什么问题。你可以把它想象成 AI 世界的USB 协议或驱动程序框架。Model Context Protocol (MCP)是一个开放协议它定义了大型语言模型LLM或 AI 助手我们称之为“客户端”与外部工具、数据源我们称之为“服务器”之间进行通信的标准方式。其核心目标是让 AI 能够安全、结构化地访问和使用外部资源和功能而无需将敏感数据上传到云端。在没有 MCP 之前我们通常有两种方式让 AI 处理本地数据复制粘贴将代码或日志片段粘贴到聊天窗口。这种方式琐碎、容易遗漏上下文且无法处理动态数据。使用特定插件的 API某些 IDE 插件或工具提供了与 AI 交互的接口但它们往往是封闭的、绑定特定编辑器的缺乏通用性。MCP 的出现改变了这一局面。它通过标准化的 JSON-RPC over stdio/SSE 协议实现了解耦与通用性任何实现了 MCP 协议的 AI 客户端如 Claude Desktop、Cursor、Windsurf都可以连接任何 MCP Server反之亦然。安全性数据留在本地通信过程可控你可以精确配置 Server 允许访问哪些资源如特定目录的文件、数据库的只读视图。能力扩展Server 不仅可以提供数据“工具”还可以提供可执行的操作“资源”比如运行脚本、查询数据库、调用 API极大地扩展了 AI 的能力边界。在这个生态中MCP Server就是我们要编写的程序它扮演着“数据提供者”和“能力提供者”的角色。而Boot Starters则是帮助我们快速创建 MCP Server 的项目模板或脚手架工具。2. 环境准备构建你的第一个 MCP Server 需要什么为了完成本次实战我们需要准备以下环境。请注意本文示例将使用Node.js环境因为其生态中有成熟的 MCP SDK 和工具链。操作系统Windows 10/11, macOS, 或 Linux 均可。本文命令以 macOS/Linux 的 bash 为例Windows 用户可在 Git Bash 或 WSL 中运行。Node.js版本 18 或更高。这是运行 MCP Server 的基石。你可以通过node --version检查。包管理工具npm 或 yarn。本文使用 npm。代码编辑器VS Code、Cursor 或任何你熟悉的 IDE。AI 客户端可选用于测试Claude Desktop 是体验 MCP 最便捷的方式之一。我们将用它来测试我们构建的 Server。首先确保你的 Node.js 环境就绪# 检查 Node.js 和 npm 版本 node --version npm --version # 如果未安装请前往 Node.js 官网下载 LTS 版本安装接下来我们创建一个项目目录并初始化mkdir my-streamable-mcp-server cd my-streamable-mcp-server npm init -y这会生成一个package.json文件记录我们的项目依赖。3. 利用 Boot Starters 快速初始化项目“从头开始”编写一个符合 MCP 协议的 Server 涉及不少样板代码。幸运的是社区提供了Boot Starters——即预先配置好的项目模板。我们将使用官方推荐的modelcontextprotocol/sdk来创建我们的 Server。安装 MCP SDKnpm install modelcontextprotocol/sdk虽然 SDK 没有提供像create-mcp-server这样的完整 CLI但我们可以参考其官方示例和结构来构建。核心是理解一个 MCP Server 需要实现哪些接口。为了更贴近实战我们直接开始构建一个具有流式传输能力的 Server。4. 核心实现构建 Streamable-HT MCP Server我们的目标是构建一个名为Streamable-HT的 ServerHT 可理解为Hello, Text或Handy Tool。它的核心功能是将本地指定文本文件的内容以流式Chunk by Chunk的方式提供给 AI 客户端。这对于让 AI 分析大型日志文件、配置文件或代码文件非常有用。4.1 项目结构与核心依赖首先安装必要的依赖npm install modelcontextprotocol/sdk npm install --save-dev typescript ts-node types/node然后创建我们的项目结构my-streamable-mcp-server/ ├── package.json ├── tsconfig.json ├── src/ │ ├── index.ts # Server 主入口文件 │ └── resources/ # 资源定义可选 └── README.md创建tsconfig.json用于 TypeScript 编译{ compilerOptions: { target: ES2022, module: commonjs, lib: [ES2022], outDir: ./dist, rootDir: ./src, strict: true, esModuleInterop: true, skipLibCheck: true, forceConsistentCasingInFileNames: true, resolveJsonModule: true }, include: [src/**/*], exclude: [node_modules] }4.2 编写 MCP Server 主逻辑 (src/index.ts)这是整个 Server 的核心。我们将实现一个 Server它公布一个read_file工具该工具可以读取文件并以流式响应返回内容。// src/index.ts import { Server } from modelcontextprotocol/sdk/server/index.js; import { StdioServerTransport } from modelcontextprotocol/sdk/server/stdio.js; import { CallToolRequestSchema, ListToolsRequestSchema, Tool, } from modelcontextprotocol/sdk/types.js; import * as fs from fs; import * as path from path; import { createReadStream } from fs; // 1. 定义 Server 能力我们提供 Tools const CAPABABILITIES { tools: {}, // 启用工具功能 }; // 2. 定义我们的工具read_file const READ_FILE_TOOL: Tool { name: read_file, description: Read the contents of a text file from a specified absolute path on the local filesystem. Returns the content in chunks via streaming., inputSchema: { type: object, properties: { filepath: { type: string, description: The absolute path to the text file to read., }, }, required: [filepath], }, }; class StreamableHTServer { private server: Server; constructor() { // 3. 创建 Server 实例 this.server new Server( { name: streamable-ht-server, version: 0.1.0, }, CAPABABILITIES ); // 4. 设置请求处理器 this.setupHandlers(); // 5. 错误处理 this.server.onerror (error) console.error([MCP Server Error], error); process.on(SIGINT, async () { await this.server.close(); process.exit(0); }); } private setupHandlers() { // 处理客户端查询可用工具的请求 this.server.setRequestHandler(ListToolsRequestSchema, async () ({ tools: [READ_FILE_TOOL], })); // 处理客户端调用工具的请求 this.server.setRequestHandler(CallToolRequestSchema, async (request) { if (request.params.name ! READ_FILE_TOOL.name) { throw new Error(Unknown tool: ${request.params.name}); } const filepath request.params.arguments?.filepath; if (typeof filepath ! string) { throw new Error(filepath argument is required and must be a string.); } // 安全检查防止路径遍历攻击 const resolvedPath path.resolve(filepath); // 这里可以添加更复杂的路径白名单校验 if (!resolvedPath.startsWith(process.cwd())) { // 示例只允许读取当前工作目录下的文件 throw new Error(Access to path ${resolvedPath} is not allowed.); } // 返回一个包含流式内容的响应 return await this.handleReadFile(resolvedPath); }); } private async handleReadFile(filepath: string): Promise{ content: Array{ type: text; text: string; }; } { return new Promise((resolve, reject) { const chunks: string[] []; const stream createReadStream(filepath, { encoding: utf8, highWaterMark: 1024 }); // 每次读取 1KB stream.on(data, (chunk: string) { chunks.push(chunk); // 在实际的 MCP 流式响应中这里应该通过 Server 的 sendNotification 发送增量内容 // 但为简化示例我们先收集所有 chunk最后一次性返回。 // 真正的流式实现需要用到 ToolResult 的 content 和 isDelta 等属性。 }); stream.on(end, () { resolve({ content: [ { type: text, text: chunks.join(), }, ], }); }); stream.on(error, (err) { reject(new Error(Failed to read file ${filepath}: ${err.message})); }); }); } // 启动 Server使用 stdio 传输层 async run() { const transport new StdioServerTransport(); await this.server.connect(transport); console.error(Streamable-HT MCP Server is running on stdio...); } } // 启动服务器 const server new StreamableHTServer(); server.run().catch(console.error);4.3 完善 Package.json 脚本修改package.json添加启动脚本和构建脚本{ name: streamable-ht-mcp-server, version: 0.1.0, description: A MCP server that streams content of local text files., main: dist/index.js, scripts: { build: tsc, start: node dist/index.js, dev: ts-node src/index.ts }, keywords: [mcp, model-context-protocol, server, streaming], author: Your Name, license: MIT, dependencies: { modelcontextprotocol/sdk: ^0.5.0 }, devDependencies: { types/node: ^20.0.0, typescript: ^5.0.0, ts-node: ^10.9.0 }, mcp: { name: streamable-ht, version: 0.1.0, description: Stream local file contents to AI clients. } }4.4 构建与运行现在我们可以构建并运行这个 Server 了# 编译 TypeScript npm run build # 运行服务器 (会在 stdio 上等待连接) npm start运行后你会看到Streamable-HT MCP Server is running on stdio...的输出表示 Server 已在标准输入输出上就绪等待 MCP 客户端连接。5. 连接与测试在 Claude Desktop 中使用你的 Server这是最激动人心的部分——让我们亲手创造的 Server 被 AI 使用。配置 Claude Desktop打开 Claude Desktop 应用。找到其配置目录。通常位于macOS:~/Library/Application Support/Claude/claude_desktop_config.jsonWindows:%APPDATA%\Claude\claude_desktop_config.jsonLinux:~/.config/Claude/claude_desktop_config.json如果文件不存在则创建它。编辑配置文件 在claude_desktop_config.json中添加以下配置告诉 Claude 如何找到并运行我们的 MCP Server{ mcpServers: { streamable-ht: { command: node, args: [ /ABSOLUTE/PATH/TO/your/project/my-streamable-mcp-server/dist/index.js ], env: { ALLOWED_BASE_DIR: /ABSOLUTE/PATH/TO/your/project } } } }请务必将/ABSOLUTE/PATH/TO/your/project替换为你项目dist/index.js文件所在的绝对路径。ALLOWED_BASE_DIR环境变量可以在我们的 Server 代码中读取用于实现更安全的白名单校验下文最佳实践会完善。重启 Claude Desktop完全退出并重新启动 Claude Desktop 应用使其加载新的配置。开始对话在 Claude 的聊天窗口中你现在可以直接要求它使用你的工具了例如“请使用read_file工具读取我项目根目录下的README.md文件内容。”Claude 会识别到可用的read_file工具并调用它。如果一切正常Claude 将能够展示出README.md文件的内容。你可以在你的 Server 运行终端看到相关的调用日志。6. 常见问题与排查思路 (FAQ)在搭建和运行过程中你可能会遇到以下问题问题现象可能原因排查思路与解决方案Claude 提示“没有可用工具”或“未知工具”。1. MCP Server 配置路径错误。2. Claude Desktop 未正确重启。3. Server 启动失败或立即退出。1. 检查claude_desktop_config.json中的command和args路径是否正确、可执行。2. 彻底退出并重启 Claude Desktop。3. 在终端单独运行node /path/to/your/server.js查看是否有错误输出如模块找不到。Server 启动时报错Cannot find module ...。项目依赖未安装或 TypeScript 未编译。1. 运行npm install安装依赖。2. 运行npm run build编译 TypeScript 代码。Claude 调用工具时报“权限错误”或“路径不允许”。Server 代码中的路径安全检查阻止了访问。1. 检查请求的文件路径是否在process.cwd()目录下。2. 修改 Server 代码中的安全检查逻辑或调整ALLOWED_BASE_DIR环境变量。工具调用成功但返回内容为空或乱码。1. 文件编码问题。2. 文件路径不存在或不可读。1. 确保读取的是 UTF-8 编码的文本文件。2. 在handleReadFile函数中添加更详细的错误日志。如何实现真正的流式传输示例代码是“伪流式”一次性返回。需要深入研究 MCP SDK 的ToolResult类型使用isDelta: true和sendNotification来分片发送内容。这属于进阶实现。基础排查命令# 检查 Node 和 Server 是否能直接运行 cd /path/to/your/project node dist/index.js # 此时程序应挂起等待输入没有报错。 # 检查配置文件语法 cat ~/Library/Application\ Support/Claude/claude_desktop_config.json | python -m json.tool7. 最佳实践与工程化建议将一个简单的 MCP Server 用于生产环境或团队共享需要考虑更多因素安全性是第一要务路径白名单绝对不要允许任意路径访问。应在 Server 启动时通过环境变量如ALLOWED_BASE_DIR配置一个或多个允许访问的根目录并在path.resolve后检查解析路径是否以白名单目录开头。输入验证对filepath参数进行严格的验证和规范化防止../../../etc/passwd这类路径遍历攻击。环境隔离考虑在 Docker 容器或沙箱环境中运行 MCP Server以限制其系统权限。增强健壮性错误处理为文件不存在、无读取权限、磁盘 IO 错误等场景提供清晰、友好的错误信息并通过 MCP 协议返回给客户端。心跳与超时实现心跳机制防止僵死进程。为长时间的文件读取操作设置超时。日志记录在 Server 侧记录重要的操作日志如工具调用、错误便于调试和审计。注意不要记录敏感文件内容。实现真正的流式传输我们的示例是“缓冲式”的。真正的流式传输对于大文件至关重要。你需要修改handleReadFile方法使其返回一个AsyncIterable或利用 SDK 的增量更新机制分批次将内容push给客户端避免内存溢出和长时间等待。扩展更多工具一个成熟的 MCP Server 可以提供多种工具。例如list_directory列出目录内容。search_in_files在文件中搜索文本。execute_safe_command在严格限制下执行安全的系统命令如git status。 每增加一个工具都要仔细评估其安全风险。配置管理将服务器配置如白名单、端口、超时时间外部化使用config.json或环境变量管理。为不同的开发环境开发、测试、生产准备不同的配置。发布与共享将你的 Server 发布到 npm方便他人通过npx安装。编写清晰的README.md说明功能、配置方法和安全注意事项。考虑提供 Docker 镜像简化部署。通过构建这个Streamable-HTMCP Server你不仅掌握了一个让 AI 安全访问本地数据的强大工具更深入理解了 AI 智能体与外部世界交互的标准化协议——MCP。你可以以此为基础探索更复杂的 Server例如连接数据库、管理 Kubernetes 集群、操作内部 API 等从而极大地扩展 AI 在你日常工作流中的能力和边界。动手尝试定制属于你自己的 AI 增强工作流吧。 30款热门AI模型一站整合DeepSeek/GLM/Qwen 随心用限时 5 折。 点击领海量免费额度