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

news2026/5/16 8:14:50
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网关、内部系统集成你会发现一个充满可能性的新世界正在打开。这个框架提供的类型安全和协议抽象让你能专注于创造价值而非陷入协议的泥潭。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2617610.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…

网络编程(Modbus进阶)

思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…

UE5 学习系列(二)用户操作界面及介绍

这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…

利用最小二乘法找圆心和半径

#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造&#xff0c;完美适配AGV和无人叉车。同时&#xff0c;集成以太网与语音合成技术&#xff0c;为各类高级系统&#xff08;如MES、调度系统、库位管理、立库等&#xff09;提供高效便捷的语音交互体验。 L…

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…

接口测试中缓存处理策略

在接口测试中&#xff0c;缓存处理策略是一个关键环节&#xff0c;直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性&#xff0c;避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明&#xff1a; 一、缓存处理的核…

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑&#xff1a;陈萍萍的公主一点人工一点智能 未来机器人的大脑&#xff1a;如何用神经网络模拟器实现更智能的决策&#xff1f;RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战&#xff0c;在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…

Linux应用开发之网络套接字编程(实例篇)

服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…