从零构建流式MCP Server:让AI安全访问本地数据的实战指南
2026/7/10 7:59:43 网站建设 项目流程

🚀 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 处理本地数据:

  1. 复制粘贴:将代码或日志片段粘贴到聊天窗口。这种方式琐碎、容易遗漏上下文,且无法处理动态数据。
  2. 使用特定插件的 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 SDK:

npm install @modelcontextprotocol/sdk

虽然 SDK 没有提供像create-mcp-server这样的完整 CLI,但我们可以参考其官方示例和结构来构建。核心是理解一个 MCP Server 需要实现哪些接口。为了更贴近实战,我们直接开始构建一个具有流式传输能力的 Server。

4. 核心实现:构建 Streamable-HT MCP Server

我们的目标是构建一个名为Streamable-HT的 Server(HT 可理解为Hello, TextHandy 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 使用。

  1. 配置 Claude Desktop

    • 打开 Claude Desktop 应用。
    • 找到其配置目录。通常位于:
      • macOS:~/Library/Application Support/Claude/claude_desktop_config.json
      • Windows:%APPDATA%\Claude\claude_desktop_config.json
      • Linux:~/.config/Claude/claude_desktop_config.json
    • 如果文件不存在,则创建它。
  2. 编辑配置文件: 在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 代码中读取,用于实现更安全的白名单校验(下文最佳实践会完善)。

  3. 重启 Claude Desktop:完全退出并重新启动 Claude Desktop 应用,使其加载新的配置。

  4. 开始对话:在 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中的commandargs路径是否正确、可执行。
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: truesendNotification来分片发送内容。这属于进阶实现。

基础排查命令

# 检查 Node 和 Server 是否能直接运行 cd /path/to/your/project node dist/index.js # 此时程序应挂起,等待输入,没有报错。 # 检查配置文件语法 cat ~/Library/Application\ Support/Claude/claude_desktop_config.json | python -m json.tool

7. 最佳实践与工程化建议

将一个简单的 MCP Server 用于生产环境或团队共享,需要考虑更多因素:

  1. 安全性是第一要务

    • 路径白名单:绝对不要允许任意路径访问。应在 Server 启动时通过环境变量(如ALLOWED_BASE_DIR)配置一个或多个允许访问的根目录,并在path.resolve后检查解析路径是否以白名单目录开头。
    • 输入验证:对filepath参数进行严格的验证和规范化,防止../../../etc/passwd这类路径遍历攻击。
    • 环境隔离:考虑在 Docker 容器或沙箱环境中运行 MCP Server,以限制其系统权限。
  2. 增强健壮性

    • 错误处理:为文件不存在、无读取权限、磁盘 IO 错误等场景提供清晰、友好的错误信息,并通过 MCP 协议返回给客户端。
    • 心跳与超时:实现心跳机制,防止僵死进程。为长时间的文件读取操作设置超时。
    • 日志记录:在 Server 侧记录重要的操作日志(如工具调用、错误),便于调试和审计。注意不要记录敏感文件内容。
  3. 实现真正的流式传输我们的示例是“缓冲式”的。真正的流式传输对于大文件至关重要。你需要修改handleReadFile方法,使其返回一个AsyncIterable或利用 SDK 的增量更新机制,分批次将内容push给客户端,避免内存溢出和长时间等待。

  4. 扩展更多工具一个成熟的 MCP Server 可以提供多种工具。例如:

    • list_directory:列出目录内容。
    • search_in_files:在文件中搜索文本。
    • execute_safe_command:在严格限制下执行安全的系统命令(如git status)。 每增加一个工具,都要仔细评估其安全风险。
  5. 配置管理

    • 将服务器配置(如白名单、端口、超时时间)外部化,使用config.json或环境变量管理。
    • 为不同的开发环境(开发、测试、生产)准备不同的配置。
  6. 发布与共享

    • 将你的 Server 发布到 npm,方便他人通过npx安装。
    • 编写清晰的README.md,说明功能、配置方法和安全注意事项。
    • 考虑提供 Docker 镜像,简化部署。

通过构建这个Streamable-HTMCP Server,你不仅掌握了一个让 AI 安全访问本地数据的强大工具,更深入理解了 AI 智能体与外部世界交互的标准化协议——MCP。你可以以此为基础,探索更复杂的 Server,例如连接数据库、管理 Kubernetes 集群、操作内部 API 等,从而极大地扩展 AI 在你日常工作流中的能力和边界。动手尝试,定制属于你自己的 AI 增强工作流吧。

🚀 30+款热门AI模型一站整合,DeepSeek/GLM/Qwen 随心用,限时 5 折。 👉 点击领海量免费额度

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询