当前位置: 首页 > article >正文

基于TypeScript的MCP服务器开发指南:为AI助手构建安全工具调用能力

1. 项目概述一个为TypeScript开发者打造的MCP服务器最近在折腾AI应用开发特别是想给Claude、Cursor这类智能助手扩展更强大的工具调用能力时不可避免地接触到了Model Context Protocol。如果你也在研究如何让AI助手安全、可控地访问文件系统、数据库或者调用外部API那你很可能和我一样需要一个趁手的MCP服务器开发工具。这就是为什么当我发现AndyLiner13/ts-mcp-server这个项目时感觉像是找到了“开箱即用”的宝藏。简单来说这是一个基于TypeScript的、用于快速构建MCP模型上下文协议服务器的开发框架。MCP本身是一个新兴的开放协议旨在标准化AI模型如Claude与外部工具、数据源之间的安全交互方式。你可以把它想象成AI世界的“USB协议”——它定义了一套标准接口让不同的“设备”工具服务器可以即插即用地被AI模型识别和使用。而这个ts-mcp-server项目就是帮你快速制作这样一个“USB设备”的脚手架和工具箱。它解决了什么问题直接手写一个符合MCP规范的服务器你需要处理协议序列化/反序列化、资源Resources和工具Tools的声明与注册、Stdio或SSE传输层的实现、错误处理等一系列繁琐且容易出错的底层细节。这个项目把这些通用部分抽象出来封装成清晰的类和方法。作为开发者你只需要专注于定义你的工具具体能做什么比如“读取指定目录文件列表”、“查询数据库”然后几行代码就能把它变成一个标准的MCP服务器轻松集成到Claude Desktop、Cursor等支持MCP的客户端中。无论你是想为自己打造一个私人AI开发助手还是为企业构建内部AI工具平台这个项目都提供了一个坚实、类型安全的起点。它特别适合熟悉Node.js/TypeScript生态的开发者让你能用最熟悉的语言和工具链快速进入AI智能体扩展开发的世界。2. 核心架构与设计思路拆解要理解ts-mcp-server的价值我们得先拆解MCP服务器的核心构成以及这个框架是如何优雅地封装这些复杂性的。2.1 MCP协议的核心抽象资源与工具MCP协议的核心思想是将外部能力抽象为两种主要类型资源Resources和工具Tools。资源代表可供AI模型读取的静态或动态数据源。例如一个文件系统中的目录可以作为一个资源file:///path/to/dir一个数据库的查询结果视图也可以是一个资源。资源有唯一的URI标识并且包含内容和元数据如MIME类型。AI模型可以“读取”资源来获取上下文信息。工具代表可供AI模型调用的函数或操作。这是交互的重点。例如“执行Shell命令”、“发送HTTP请求”、“写入文件”都是工具。每个工具都有输入参数的定义符合JSON SchemaAI模型在需要时会调用工具并传入参数服务器执行后返回结果。一个MCP服务器的工作就是向客户端AI模型宣告“我这里有这些资源URIs和这些工具名称和参数你可以按需使用。”ts-mcp-server框架的核心任务就是让你用最直观的方式定义这些资源和工具并自动处理宣告、调用路由和结果返回的整个协议流程。2.2 框架的模块化设计浏览项目的源代码结构能清晰看到其模块化设计思路这大大降低了开发者的心智负担传输层抽象框架内部实现了Stdio标准输入输出和SSE服务器发送事件两种MCP标准传输方式。你通常不需要关心数据是如何被切成消息帧、如何被发送的框架已经处理好了与客户端的底层通信。你只需要在创建服务器实例时选择一种传输方式即可。协议消息路由器这是框架的大脑。它自动拦截客户端发来的所有JSON-RPC格式的消息根据消息方法如tools/callresources/read将其路由到你注册的对应工具函数或资源处理器上。你不需要手动解析stdin或处理原始的HTTP请求。类型安全的API这是TypeScript项目的最大优势。框架通过泛型提供了极佳的类型提示。当你定义一个工具时你需要明确指定其输入参数的JSON Schema。此后在实现该工具的函数中你收到的参数对象就是完全类型安全的IDE会自动补全编译阶段就能发现参数类型错误极大减少了运行时错误。生命周期与状态管理框架提供了清晰的服务器生命周期钩子如初始化、关闭并允许你方便地管理服务器级别的状态比如数据库连接池、配置对象。你可以将这些状态注入到每个工具的执行上下文中。这种设计意味着作为使用者你的关注点被极大地收窄和简化定义能力Schema - 实现逻辑Function - 启动服务。其他所有协议层面的复杂性都被框架默默地承担了。2.3 为何选择TypeScript这看似是一个技术栈选择实则背后有深刻的考量。MCP服务器作为AI与真实世界的桥梁稳定性和安全性至关重要。TypeScript的静态类型系统能在编码阶段就捕获大量潜在的错误比如参数类型不匹配、访问未定义的属性等这些错误在动态的JavaScript中可能要等到运行时、在AI调用工具失败时才会暴露调试成本极高。其次开发体验和效率。清晰的类型定义本身就是最好的文档。当你为工具定义输入输出Schema时后续的所有实现代码都能获得智能提示和自动补全这比查阅松散的文档要高效得多。对于需要与复杂数据结构如数据库记录、API响应体打交道的工具来说这一点尤其重要。最后生态与协作。Node.js/TypeScript生态拥有无比丰富的npm包几乎可以找到任何系统操作、网络请求、数据处理的库。使用ts-mcp-server你可以直接利用整个npm生态来快速实现工具功能无需重复造轮子。在团队协作中类型约束也能保证不同开发者编写的工具接口一致减少沟通成本。3. 从零开始构建你的第一个MCP工具服务器理论说得再多不如动手实践。让我们一步步创建一个简单的MCP服务器它提供一个工具获取指定目录的文件列表。这将帮助你透彻理解框架的使用流程。3.1 环境准备与项目初始化首先确保你的系统已安装Node.js建议版本18或以上和npm。然后创建一个新的项目目录并初始化。mkdir my-file-explorer-server cd my-file-explorer-server npm init -y接下来安装核心依赖。我们需要modelcontextprotocol/sdk这是Anthropic官方维护的MCP协议SDKts-mcp-server框架基于它构建。同时安装TypeScript和相关的类型定义。npm install modelcontextprotocol/sdk npm install --save-dev typescript types/node tsx注意这里我们使用tsx作为TypeScript的执行器它比传统的ts-node速度更快对ESM模块的支持也更好。你也可以选择其他运行器如ts-node或编译后运行。初始化TypeScript配置npx tsc --init根据项目需求你可能需要修改生成的tsconfig.json确保target设置为ES2022或更高module设置为NodeNext或CommonJS取决于你的包模块类型。一个适用于本项目的简单配置如下{ compilerOptions: { target: ES2022, module: NodeNext, moduleResolution: NodeNext, esModuleInterop: true, strict: true, skipLibCheck: true, forceConsistentCasingInFileNames: true, outDir: ./dist, rootDir: ./src }, include: [src/**/*], exclude: [node_modules] }3.2 创建服务器实例与定义工具在src目录下创建index.ts文件。首先我们需要导入必要的模块并创建一个服务器实例。ts-mcp-server框架通常以类似下面的方式导出其核心类这里以常见的抽象为例具体类名需参考项目最新文档。// src/index.ts import { Server } from modelcontextprotocol/sdk/server/index.js; import { StdioServerTransport } from modelcontextprotocol/sdk/server/stdio.js; // 注意AndyLiner13/ts-mcp-server 可能提供了一个更上层的封装类。 // 假设它导出了一个名为 McpServer 的类我们这样使用 import { McpServer } from ts-mcp-server; // 示例导入实际包名可能不同 // 1. 创建MCP服务器实例 // 通常需要传入服务器元数据如名称、版本 const server new McpServer({ name: file-explorer-server, version: 0.1.0, }); // 2. 定义一个工具list_directory // 首先定义工具的输入参数JSON Schema。这确保了AI调用时传入的数据结构是可控的。 const listDirectoryToolSchema { type: object, properties: { path: { type: string, description: 要列出文件的目录绝对路径, }, recursive: { type: boolean, description: 是否递归列出子目录, default: false, }, }, required: [path], // path是必填参数 additionalProperties: false, // 禁止传入未定义的参数增强安全性 } as const; // as const 断言让TypeScript推断出最精确的字面量类型 // 3. 注册工具到服务器 server.tool( list_directory, // 工具的唯一标识名 listDirectoryToolSchema, // 输入参数Schema async ({ path, recursive false }, extra) { // 这是工具的实现函数。参数args已根据上面的Schema进行了类型安全校验。 // extra 可能包含上下文信息如请求ID、客户端信息等。 // 引入Node.js内置的fs和path模块进行文件操作 const fs await import(fs/promises); const pathModule await import(path); try { // 安全检查防止路径遍历攻击确保请求的路径在允许的范围内。 // 这是一个非常重要的步骤在实际生产环境中你需要更严格的路径白名单机制。 const resolvedPath pathModule.resolve(path); // 示例简单检查是否在用户家目录下可根据需要调整 if (!resolvedPath.startsWith(process.env.HOME || /home/user)) { throw new Error(Access to the specified path is not allowed.); } const stats await fs.stat(resolvedPath); if (!stats.isDirectory()) { throw new Error(The path ${path} is not a directory.); } // 读取目录内容 const items await fs.readdir(resolvedPath, { withFileTypes: true }); let fileList: Array{name: string, type: file | directory, size?: number} []; for (const item of items) { const itemPath pathModule.join(resolvedPath, item.name); const itemStat await fs.stat(itemPath); const entry { name: item.name, type: item.isDirectory() ? directory : file, }; // 如果是文件可以附加大小信息 if (entry.type file) { (entry as any).size itemStat.size; } fileList.push(entry as any); // 如果要求递归且当前项是目录 if (recursive entry.type directory) { // 注意简单递归生产环境需考虑深度和性能 const subList await listDirectoryRecursive(itemPath); fileList fileList.concat(subList.map(subItem ({ ...subItem, name: pathModule.join(item.name, subItem.name) // 保持相对路径 }))); } } // 返回结果给AI模型。内容应该是结构化的、易于理解的文本。 return { content: [ { type: text, text: Directory listing for ${path}:\n\n fileList.map(item - [${item.type.toUpperCase()}] ${item.name} (item.type file ? (${formatBytes(item.size!)}) : )) .join(\n) } ] }; } catch (error: any) { // 错误处理返回清晰的错误信息给AI而不是让服务器崩溃。 return { content: [ { type: text, text: Error listing directory ${path}: ${error.message} } ], isError: true // 标记这是一个错误响应 }; } } ); // 一个简单的递归列出目录的辅助函数需实现 async function listDirectoryRecursive(dirPath: string): PromiseArray{name: string, type: file | directory, size?: number} { const fs await import(fs/promises); const pathModule await import(path); const items await fs.readdir(dirPath, { withFileTypes: true }); let results: Array{name: string, type: file | directory, size?: number} []; for (const item of items) { const fullPath pathModule.join(dirPath, item.name); if (item.isDirectory()) { results.push({ name: item.name, type: directory }); const subItems await listDirectoryRecursive(fullPath); results results.concat(subItems.map(sub ({ ...sub, name: pathModule.join(item.name, sub.name) }))); } else { const stat await fs.stat(fullPath); results.push({ name: item.name, type: file, size: stat.size }); } } return results; } function formatBytes(bytes: number): string { const units [B, KB, MB, GB]; let size bytes; let unitIndex 0; while (size 1024 unitIndex units.length - 1) { size / 1024; unitIndex; } return ${size.toFixed(2)} ${units[unitIndex]}; }3.3 连接传输层与启动服务定义好工具后我们需要告诉服务器如何与客户端通信。MCP最常见的开发调试方式是使用Stdio传输这意味着服务器通过标准输入stdin接收消息通过标准输出stdout发送消息。Claude Desktop等客户端通常以这种方式启动MCP服务器。// 接上面的 index.ts 文件 // 4. 设置传输层并启动服务器 async function main() { // 创建Stdio传输实例 const transport new StdioServerTransport(); // 将服务器与传输层连接 await server.connect(transport); console.error(File Explorer MCP Server is now running and listening via stdio...); // 注意日志输出到 stderr避免污染与客户端通信的 stdout 通道。 } main().catch((error) { console.error(Failed to start server:, error); process.exit(1); });现在一个最简单的MCP服务器就完成了。你可以使用tsx直接运行它进行测试虽然需要客户端配合才能看到效果。npx tsx src/index.ts3.4 配置Claude Desktop进行测试要让这个服务器真正工作我们需要在一个MCP客户端中配置它。以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文件添加你的服务器配置{ mcpServers: { file-explorer: { command: node, args: [ /absolute/path/to/your/project/dist/index.js // 如果是编译后的JS // 或者使用 tsx 直接运行TS: // /absolute/path/to/.bin/tsx, // /absolute/path/to/your/project/src/index.ts ], env: { // 可以在这里传递环境变量 } } } }重启Claude Desktop。如果配置正确在Claude的输入框里你应该能通过提及或直接描述来使用你定义的list_directory工具了。例如你可以尝试输入“请帮我列出~/Documents目录下的文件。”4. 进阶实践构建复杂且健壮的生产级工具上面的例子展示了基础流程但一个真正有用的MCP服务器需要考虑更多。下面我们深入探讨几个关键进阶主题。4.1 资源Resources的声明与提供除了工具资源是MCP的另一大支柱。资源更适合暴露那些“只读”的、URI可寻址的数据。例如我们可以暴露一个server-metrics资源来提供服务器的实时状态。// 在 server 实例上注册资源 server.resource( server-metrics, // 资源模板名 mcp://file-explorer-server/metrics, // 资源的URI模板 // 资源提供者函数当AI请求读取此资源时被调用 async (uri, extra) { // uri 是客户端请求的具体URI你可以从中解析参数如果模板有变量 // 例如模板是 mcp://file-explorer-server/logs/{date}uri可能就是 mcp://.../logs/2023-10-01 const metrics { uptime: process.uptime(), memoryUsage: process.memoryUsage(), activeConnections: (server as any).getConnectionCount?.() || 0, // 假设服务器有这个方法 timestamp: new Date().toISOString(), }; return { contents: [{ // 资源内容可以是文本、图片等 uri: uri.href, mimeType: application/json, text: JSON.stringify(metrics, null, 2), }] }; } );资源的一个强大之处在于动态发现。你可以实现一个resources/list处理器根据当前系统状态动态返回可用的资源URI列表这样AI就能“浏览”你的服务器提供了哪些数据。4.2 工具输入Schema的设计艺术设计一个好的工具Schema是确保AI能正确、安全调用工具的关键。这不仅仅是定义类型更是定义“交互契约”。描述要详尽description字段至关重要。AI模型如Claude会仔细阅读这些描述来理解工具的用途和每个参数的意义。描述应清晰、无歧义并说明参数的约束条件。例如对于path参数描述可以写“文件或目录的绝对路径。必须位于用户主目录(~)或其子目录下禁止使用..进行父目录遍历。”使用enum和pattern进行约束对于有明确选项的参数使用enum。对于需要特定格式的字符串如日期YYYY-MM-DD使用pattern进行正则校验。这能在协议层面就过滤掉非法输入。提供合理的默认值像上面例子中的recursive: { default: false }这简化了AI的调用它不需要每次都指定这个参数。利用additionalProperties: false这能防止客户端意外或恶意传入未定义的参数是重要的安全措施。4.3 错误处理与用户反馈在工具实现函数中健壮的错误处理必不可少。目标不是避免所有错误而是优雅地处理错误并将有意义的反馈传递给AI。预期内的错误如文件不存在、权限不足、参数无效等。这些应该通过返回{ content: [...], isError: true }来明确告知AI这是一个错误结果而不是抛出异常导致服务器进程崩溃。AI可以根据错误信息调整其后续行为或向用户解释。非预期的运行时错误如数据库连接突然中断、第三方API不可用。这些也应该被捕获并返回一个通用的错误信息避免泄露内部细节。同时可以在服务器端记录详细的错误日志用于排查。结构化错误信息除了文本可以考虑在错误内容中提供结构化的错误码或建议的解决步骤帮助AI更好地理解问题。async function safeToolImplementation(args: any, extra: any) { try { // ... 业务逻辑 return { content: [{ type: text, text: Success! }] }; } catch (error: any) { // 分类处理错误 if (error.code ENOENT) { return { content: [{ type: text, text: File not found: ${error.path} }], isError: true }; } else if (error.code EACCES) { return { content: [{ type: text, text: Permission denied for path: ${error.path} }], isError: true }; } else { // 未知错误记录日志返回友好提示 console.error(Internal tool error:, error); return { content: [{ type: text, text: An internal error occurred while processing your request. }], isError: true }; } } }4.4 状态管理与依赖注入复杂的工具可能需要共享状态比如一个数据库连接池、一个配置管理器或一个认证令牌缓存。ts-mcp-server框架通常允许你在创建服务器时或通过上下文extra来传递这些依赖。一种常见的模式是使用闭包或类来封装服务器和其状态class DatabaseExplorerServer { private dbClient: DatabaseClient; private server: McpServer; constructor(dbConnectionString: string) { this.dbClient new DatabaseClient(dbConnectionString); this.server new McpServer({ name: db-explorer, version: 1.0.0 }); this.setupTools(); } private setupTools() { this.server.tool(query_database, { /* schema */ }, async (args, extra) { // 在这里可以直接访问 this.dbClient const result await this.dbClient.query(args.sql); return { /* ... */ }; }); this.server.tool(list_tables, { /* schema */ }, async (args, extra) { const tables await this.dbClient.listTables(args.schema); return { /* ... */ }; }); } async start(transport: ServerTransport) { await this.server.connect(transport); } } // 使用 const dbServer new DatabaseExplorerServer(process.env.DB_URL); const transport new StdioServerTransport(); await dbServer.start(transport);这种方式使得代码组织更清晰状态管理更安全也便于单元测试。5. 调试、测试与性能优化实战开发MCP服务器尤其是与AI协同工作时调试和测试有其特殊性。5.1 调试技巧模拟客户端请求你不需要总是依赖Claude Desktop来测试。可以编写一个简单的Node.js脚本模拟MCP客户端通过Stdio与你的服务器交互。这能让你快速验证工具的逻辑和响应格式。// test-client.js import { spawn } from child_process; import { Writable, Readable } from stream; // 启动你的服务器进程 const serverProcess spawn(node, [dist/index.js], { stdio: [pipe, pipe, inherit] // 接管 stdin/stdout, stderr输出到控制台 }); // 封装发送JSON-RPC请求的函数 function sendRequest(method: string, params: any) { const request { jsonrpc: 2.0, id: Date.now(), method, params }; const message Content-Length: ${JSON.stringify(request).length}\r\n\r\n${JSON.stringify(request)}; serverProcess.stdin.write(message); } // 监听服务器的响应 let buffer ; serverProcess.stdout.on(data, (chunk) { buffer chunk.toString(); // 简单解析MCP消息边界这里简化处理实际协议更复杂 const lines buffer.split(\n); // ... 解析消息边界提取完整的JSON消息 ... // 找到以 Content-Length: 开头的行然后读取指定长度的body console.log(Received from server:, parsedMessage); }); // 发送一个测试请求初始化会话 sendRequest(initialize, { protocolVersion: 1.0, clientInfo: { name: test-client } }); // 稍后发送工具调用请求 setTimeout(() { sendRequest(tools/call, { name: list_directory, arguments: { path: process.env.HOME } }); }, 100);更高效的方式是使用MCP SDK自带的测试工具或编写基于内存传输MemoryTransport的单元测试直接调用服务器实例的方法进行测试。5.2 性能考量与最佳实践工具响应速度AI交互是同步的。如果工具调用需要很长时间如超过10秒会让用户感到卡顿。对于耗时操作如大数据量查询、复杂计算考虑异步与进度提示如果协议支持可以返回一个“任务已开始”的响应然后通过其他方式如资源更新通知AI任务进度和结果。优化工具逻辑缓存频繁访问的数据使用更高效的算法。设置超时在工具实现内部为依赖的外部调用网络请求、子进程设置合理的超时时间。资源占用一个MCP服务器通常是常驻进程。注意内存泄漏及时清理不再使用的缓存或连接。对于文件操作类工具使用fs.promises进行异步I/O避免阻塞事件循环。安全性加固这是重中之重。输入验证Schema是第一道防线但在工具实现内部必须进行二次验证特别是路径、命令、SQL语句等。权限最小化服务器进程应以最低必要权限运行。不要用root或管理员权限启动。沙箱化对于执行任意代码或命令的工具考虑在Docker容器或安全的子进程沙箱中运行。审计日志记录所有工具调用的元数据时间、工具名、调用者、关键参数哈希便于事后审计和问题排查。5.3 与AI协作的提示工程你的工具设计会直接影响AI的使用效果。除了清晰的Schema描述还可以提供示例在工具的description中或通过注释可以简短地给出AI应该如何调用此工具的示例。例如“使用此工具获取系统信息。示例调用get_system_info工具无需参数。”设计原子化工具一个工具最好只做一件事。比如将“读取文件”和“写入文件”分成两个工具而不是一个“文件操作”工具。这降低了AI的理解和使用难度。返回结构化的、简洁的结果AI处理结构化的文本如JSON、Markdown表格比处理大段无格式文本更高效。返回结果时尽量组织好内容使用清晰的标题、列表和分隔符。6. 部署与生态集成开发完成后你需要考虑如何分发和部署你的MCP服务器。6.1 打包与分发对于个人使用直接运行TypeScript源码或编译后的JavaScript即可。对于分享最佳实践是将其打包成一个npm包。编译TypeScript确保tsconfig.json配置正确输出到dist目录。定义入口点在package.json中设置main字段指向编译后的入口文件如./dist/index.js以及bin字段如果希望提供命令行入口。声明依赖明确列出dependencies和peerDependencies。modelcontextprotocol/sdk通常应作为peerDependency因为最终与客户端交互的版本需要兼容。发布到npm使用npm publish。这样其他用户只需npm install -g your-mcp-server即可安装并在Claude Desktop配置中直接使用包名或全局安装后的可执行文件路径。6.2 集成到其他AI客户端除了Claude Desktop越来越多的AI应用和平台开始支持MCP协议。Cursor IDECursor内置了MCP支持配置方式与Claude Desktop类似通常通过cursor.json配置文件添加。Windsurf、Codeium等AI编码助手这些工具也可能支持或计划支持MCP关注其官方文档。自建AI应用如果你在构建自己的AI应用可以直接集成MCP SDK的客户端部分来动态加载和调用这些MCP服务器从而无限扩展你的AI能力。6.3 监控与维护对于长期运行的生产服务器需要考虑监控健康检查可以暴露一个简单的工具或资源如/health来返回服务器状态。日志聚合将工具调用日志、错误日志发送到像ELK、Sentry这样的日志平台。指标收集使用Prometheus等工具收集调用次数、延迟、错误率等指标。7. 避坑指南与常见问题在我自己开发和使用的过程中踩过不少坑这里总结几个最常见的Stdio通信挂起或无响应现象服务器启动后客户端连接上但调用工具没反应或者服务器进程卡住。排查检查消息格式确保服务器发送的响应严格遵循MCP协议的消息格式特别是Content-Length头部必须准确后面必须跟两个\r\n。避免同步阻塞确保工具的实现函数是async的或者返回Promise。不要在工具函数中执行长时间同步阻塞操作如fs.readFileSync处理大文件。处理未捕获异常在工具函数最外层用try-catch包裹防止未处理的异常导致整个进程崩溃或状态异常。可以在async main()函数外再包一层全局的process.on(uncaughtException, ...)作为最后防线。技巧在开发初期可以启用MCP SDK的调试日志。通常可以通过设置环境变量NODE_DEBUGmcp*或DEBUGmodelcontextprotocol/sdk*来查看详细的通信报文。工具被AI忽略或调用不正确现象AI似乎不知道你的工具存在或者总是用错误的参数调用。排查检查初始化响应在initialize握手阶段服务器是否正确返回了capabilities其中是否包含了tools列表审视Schema描述AI严重依赖description字段。确保描述清晰、无歧义并说明了每个参数的用途、格式和约束。可以尝试用更口语化、更详细的语言重写描述。简化初始工具集如果一开始就注册了太多比如超过20个工具某些AI模型可能会感到困惑。先从最核心的2-3个工具开始验证它们能被正确识别和使用。技巧在Claude Desktop中你可以直接问它“你现在可以使用哪些工具” 它会列出已成功加载的工具列表。这是一个快速的验证方法。路径安全与权限问题现象工具试图访问超出预期的目录或在没有权限的路径上操作失败。解决绝对路径解析与白名单始终使用path.resolve()解析用户输入的路径并检查解析后的路径是否在一个预定义的安全目录白名单内。永远不要信任客户端传入的原始路径。用户上下文如果可能从MCP连接初始化信息中获取操作系统用户信息并将路径限制在该用户的家目录内。使用虚拟文件系统对于高度敏感的环境可以考虑实现一个虚拟文件系统层工具操作的不是真实路径而是映射后的安全路径。依赖管理与版本冲突现象本地运行正常打包或部署到其他环境后出错提示Cannot find module或协议版本不兼容。解决锁定依赖版本使用package-lock.json或yarn.lock并在生产部署时确保安装的是锁定的版本。将MCP SDK声明为peerDependency在package.json中将modelcontextprotocol/sdk放在peerDependencies中并指定一个宽松但兼容的版本范围如^1.0.0。这迫使使用者或上层应用明确安装SDK避免了多个不同版本SDK共存导致的冲突。构建可执行文件对于复杂的依赖可以使用pkg或nexe将Node.js项目打包成独立的可执行文件减少环境依赖。处理大型或流式响应挑战某些工具如读取超大日志文件可能产生远超模型上下文限制的响应。思路MCP协议本身支持分页和增量更新但需要客户端和服务器协同实现。一个更简单的折中方案是在工具内部对结果进行智能截断、摘要或分片。例如读取文件时只返回前N行和最后N行并注明总行数查询数据库时增加limit和offset参数让AI进行分页查询。构建ts-mcp-server项目的过程本质上是在为AI模型打造一套安全、可控的“手脚”和“感官”。它要求开发者不仅要有扎实的后端编程能力更要有产品思维和安全意识去思考AI会如何与这些工具交互。从简单的文件列表工具开始逐步扩展到数据库查询、API网关、内部系统集成你会发现一个充满可能性的新世界正在打开。这个框架提供的类型安全和协议抽象让你能专注于创造价值而非陷入协议的泥潭。

相关文章:

基于TypeScript的MCP服务器开发指南:为AI助手构建安全工具调用能力

1. 项目概述:一个为TypeScript开发者打造的MCP服务器最近在折腾AI应用开发,特别是想给Claude、Cursor这类智能助手扩展更强大的工具调用能力时,不可避免地接触到了Model Context Protocol。如果你也在研究如何让AI助手安全、可控地访问文件系…...

利用 STM32F407 BKPSRAM 实现运行时变量监控 —— 从方案到 Keil 调试实战

利用 STM32F407 BKPSRAM 实现运行时变量监控 —— 从方案到 Keil 调试实战 一、什么是 BKPSRAM 1.1 先看一张图 STM32F407 的存储系统里有一个很特别的区域叫备份域(Backup Domain)。备份域里住着几个东西: ┌───────────────…...

GPTPortal:基于模型抽象层的AI应用快速部署与统一管理平台

1. 项目概述:一个面向开发者的AI应用快速部署门户 最近在GitHub上看到一个挺有意思的项目,叫GPTPortal。乍一看名字,可能会让人联想到某个特定的AI模型服务,但深入了解一下就会发现,它的定位其实更偏向于一个“门户”或…...

RePKG终极指南:如何深度解析Wallpaper Engine资源包与TEX纹理转换

RePKG终极指南:如何深度解析Wallpaper Engine资源包与TEX纹理转换 【免费下载链接】repkg Wallpaper engine PKG extractor/TEX to image converter 项目地址: https://gitcode.com/gh_mirrors/re/repkg RePKG是一款专为Wallpaper Engine设计的专业级资源包解…...

跨境直播进入“下半场”:2026年值得关注的几个新方向

很多人提到跨境直播,第一反应还是“流量”和“带货”。但如果这两年持续关注行业变化,会发现一个明显趋势:跨境直播正在从“内容竞争”转向“技术能力竞争”。尤其从2025年开始,行业越来越卷的不只是主播,而是整个直播…...

基于RAG的Obsidian智能知识库:本地部署与优化实战

1. 项目概述:当知识管理遇上大语言模型 如果你和我一样,是 Obsidian 的深度用户,同时又对大语言模型(LLM)的智能涌现能力感到着迷,那么你肯定也想过一个问题:能不能让我的知识库“活”起来&…...

WinGet安装工具:PowerShell自动化部署的架构解析与实践指南

WinGet安装工具:PowerShell自动化部署的架构解析与实践指南 【免费下载链接】winget-install Install WinGet using PowerShell! Prerequisites automatically installed. Works on Windows 10/11 and Server 2019/2022. 项目地址: https://gitcode.com/gh_mirror…...

【数字孪生实战案例】三维场景中怎样点击飞线,唤起弹窗并加载匹配的关联数据?~山海鲸可视化

在三维数据可视化场景中,飞线常用于呈现跨区域业务关联与流转关系。为增强交互体验与数据可读性,需实现点击飞线触发弹窗,并精准加载匹配的关联数据,让用户可实时查看单条飞线对应的业务信息,提升三维场景的数据交互与…...

AI技能工程框架解析:从模块化设计到智能体构建实战

1. 项目概述:一个面向技能复现与创造的AI工具集最近在GitHub上看到一个挺有意思的项目,叫“skill-creator-pro”。光看这个名字,你可能会有点摸不着头脑,这到底是做什么的?是教人学技能的,还是生成技能的&a…...

RK3506开发板PWM输入捕获配置与调试实战指南

1. 项目概述:在RK3506上搞定PWM输入捕获最近在做一个工业网关项目,需要精确测量外部传感器发来的PWM信号频率和占空比,核心板选型正好落在了触觉智能的RK3506开发板上。这块板子接口丰富,性能也够用,但上手调试PWM输入…...

基于规则引擎的自动化文件管理工具smartcat实战指南

1. 项目概述:一个智能化的文件分类与归档工具最近在整理个人电脑和服务器上的文件时,我又一次陷入了混乱。下载文件夹里塞满了各种格式的文档、图片、压缩包,项目目录下混杂着不同版本的代码、设计稿和会议记录。手动分类不仅耗时&#xff0c…...

Kubernetes二进制文件管理器KBM:高效管理kubectl、helm等工具版本

1. 项目概述:为什么我们需要一个Kubernetes二进制文件管理器? 如果你和我一样,长期在多个Kubernetes集群、不同版本的环境之间切换,或者需要为CI/CD流水线、离线环境准备特定版本的 kubectl 、 helm 、 kustomize 等工具&am…...

工业级RS-485收发器自主设计:从电路原理到PCB布局的实战指南

1. 项目概述与核心价值 在工业自动化、楼宇控制、能源监控这些领域里,设备之间要“说话”,RS-485总线绝对是那个最可靠、最耐用的“方言”。你可能在PLC、变频器、智能电表或者一堆传感器上见过那两个标着A、B的端子,背后驱动它们的&#xff…...

Kubernetes二进制文件管理工具:自动化安装与多版本切换实践

1. 项目概述与核心价值在云原生和容器化技术成为主流的今天,Kubernetes 无疑是这个领域的基石。无论是开发、测试还是生产环境,我们都需要一套稳定、可靠的 Kubernetes 集群。然而,对于很多开发者、运维工程师,甚至是刚开始接触云…...

NotebookLM心理学研究辅助:为什么92%的心理学博士生漏用了“语义锚定”功能?

更多请点击: https://intelliparadigm.com 第一章:NotebookLM心理学研究辅助 NotebookLM 是 Google 推出的基于用户上传文档进行深度语义理解的 AI 助手,其“以你的资料为中心”的设计范式特别契合心理学研究中对原始文献、访谈转录稿、实验…...

LLM智能体开发指南:从Awesome List到项目实战

1. 项目概述:为什么我们需要一个“Awesome LLM Agents”清单? 如果你最近也在关注大语言模型(LLM)和智能体(Agent)领域,那你肯定和我有一样的感受:这个领域的发展速度,简…...

紧急通知:地质项目交付周期压缩迫在眉睫——用NotebookLM替代传统笔记整理,单项目节省22.6工时(附审计级日志)

更多请点击: https://intelliparadigm.com 第一章:NotebookLM地质学研究辅助的范式变革 NotebookLM 作为 Google 推出的基于用户上传文档进行语义理解与推理的 AI 工具,正悄然重塑地质学研究的知识处理流程。传统地质工作依赖大量野外笔记、…...

AI智能体技能库开发实战:从工具调用到系统集成

1. 项目概述:一个智能体技能库的诞生如果你正在研究或开发AI智能体,尤其是基于大型语言模型(LLM)的自主智能体,那么你一定遇到过这样的困境:智能体的核心能力,除了模型本身的理解和生成&#xf…...

普通人如何构建AI智能体?一篇文章搞定——快速搭建属于自己的智能体

构建一个属于自己的智能体,其核心流程围绕一个通用架构展开,该架构定义了智能体如何感知、决策和行动。 对于普通人(非专业开发者)而言,关键在于利用现有的、低代码或无代码的框架和平台,将复杂的架构组件…...

基于MCP协议与RAG技术构建智能聊天应用:架构解析与实战指南

1. 项目概述:一个基于MCP协议的RAG聊天应用最近在开源社区里,一个名为gogabrielordonez/mcp-ragchat的项目引起了我的注意。乍一看标题,它融合了当下两个非常热门的技术概念:MCP和RAG。对于从事AI应用开发,特别是希望构…...

基于知识图谱与NLP技术的小说文本结构化分析实战

1. 项目概述:当小说遇见知识图谱 如果你和我一样,既是个技术爱好者,又是个小说迷,那你肯定有过这样的体验:读完一本情节复杂、人物关系盘根错节的小说后,合上书页,脑子里却一团乱麻。谁是谁的盟…...

AgentGym:构建标准化AI智能体训练与评估平台的实践指南

1. 项目概述:当AI智能体走进“健身房”最近在开源社区里,一个名为“AgentGym”的项目引起了我的注意。它来自开发者WooooDyy,名字起得很有意思——“智能体健身房”。这可不是让AI去举铁跑步,而是为那些基于大语言模型的智能体提供…...

解密Java静态调用图:架构师的高效分析实战

解密Java静态调用图:架构师的高效分析实战 【免费下载链接】java-callgraph2 Programs for producing static call graphs for Java programs. 项目地址: https://gitcode.com/gh_mirrors/ja/java-callgraph2 你是否曾面对一个庞大的Java项目,想要…...

告别手动抢红包!用Kotlin写一个Android微信红包监听助手(附完整代码)

用Kotlin构建Android微信红包自动化工具:从原理到避坑指南 春节聚会时,你是否曾因低头抢红包错过亲友的精彩对话?工作群里的手气红包总在分神时一闪而过?作为一名Android开发者,其实可以用技术优雅解决这些烦恼。本文…...

Discord Bot自动分发+CSV任务编排+状态回写看板——Midjourney批量工作流工业级落地(仅限内部团队验证过)

更多请点击: https://intelliparadigm.com 第一章:Discord Bot自动分发CSV任务编排状态回写看板——Midjourney批量工作流工业级落地(仅限内部团队验证过) 该方案已在 3 个百人级创意协作团队中稳定运行超 180 天,日均…...

AI智能体安全沙箱agentguard:为LLM代码执行筑起防火墙

1. 项目概述与核心价值 最近在开源社区里,一个名为 A386official/agentguard 的项目引起了我的注意。乍一看这个标题,你可能会联想到网络安全、代理防护或者某种守护进程。没错,这个项目正是为了解决一个在AI应用开发,特别是基于…...

基于SSE的轻量级实时通信库Hermes:Web应用实时消息推送实践

1. 项目概述:一个为Web应用量身打造的“信使”最近在折腾一个前后端分离的项目,后端服务部署在云端,前端应用则直接跑在用户的浏览器里。一个老生常谈的问题又摆在了面前:如何让前端能实时、可靠地获取后端的数据变更通知&#xf…...

5分钟搞定Windows包管理器:winget-install终极配置指南

5分钟搞定Windows包管理器:winget-install终极配置指南 【免费下载链接】winget-install Install WinGet using PowerShell! Prerequisites automatically installed. Works on Windows 10/11 and Server 2019/2022. 项目地址: https://gitcode.com/gh_mirrors/wi…...

JSON格式强制输出失败,深度解析DeepSeek-R1/V3模型token级响应机制与schema约束绕过方案

更多请点击: https://intelliparadigm.com 第一章:JSON格式强制输出失败的现象与根本归因 典型失败现象 当后端服务(如 Go/Node.js/Python)尝试通过 HTTP 响应强制输出 JSON 数据时,常出现空响应、500 错误、或返回 …...

仅1月Accepted!恭喜北大学者独作发表Nature子刊(IF 10.1)!

源自风暴统计网:一键统计分析与绘图的AI网站 引言 非协作者且是独作,用GBD 2023发表顶刊Nature是什么概念?来看今天这篇由北大学者发表的硬核文章!GBD 2023发文依然很顶,郑老师团队的专属科研训练营帮你实现从0到1的…...