1. 项目背景:为什么我会一口气把91个工具做成MCP
先说结论:2025年做AI Agent开发,手里没有一套趁手的MCP工具集,效率至少打折一半。前阵子我在做智能体项目,频繁在“让模型调用工具”这件事上折返跑——每次写一个新的工具调用,都要重新定义接口、调试参数、处理异常,代码堆了一大堆,真正能复用的却没多少。后来接触了MCP协议,我第一反应是“这不就是把工具API统一成一套标准嘛”,但真正上手之后才发现,从设计到发布、再到托管,每一步都有不少隐性成本。
这个项目的目标很直接:把手头高频使用的91个工具全部做成MCP Server,统一通过npm发布,同时把核心包托管到魔搭平台,方便团队内部分发和后续集成。工具范围覆盖了日常开发中用到的文件处理、目录遍历、时间日期、网络请求、数据格式化等常见场景——说白了我就是想拥有一个“开箱即用”的通用工具集,让任何支持MCP的客户端都能直接调用,不用再重复造轮子。
如果你现在正在做Claude、Cursor、或其他支持MCP的AI编程工具的插件开发,或者你维护着一套内部工具库,想把它们暴露给大模型使用,那这篇文章应该能帮你省下不少时间。我会把从零搭建MCP Server、npm发布过程中遇到的各种报错、以及魔搭托管时踩过的坑全部记录下来,包括那些网上搜不到明确答案的诡异问题。
2. 整体方案设计:MCP Server架构怎么拆
2.1 MCP协议的核心逻辑
在动手写代码之前,我觉得有必要把MCP的底层逻辑捋一遍。MCP(Model Context Protocol)本质上是在“大模型应用”和“外部工具”之间定义了一层标准通信协议。它规定了三件事:工具怎么描述自己(名称、参数schema)、工具怎么被调用(请求/响应格式)、以及结果怎么返回给模型(结构化数据)。
这就好比你把一堆不同的电器插座全部改成了统一的国家标准接口——不管后面接的是电视还是冰箱,插头插上去就能用。MCP Server做的事情就是把每个工具包装成符合规范的接口,然后告诉客户端“我有哪些工具、每个工具需要什么参数、会返回什么结构”。
具体到技术实现上,MCP Server目前主要有两种传输方式:
- stdio方式:通过标准输入输出和客户端通信,适合本地运行,比如Claude Desktop调用本地MCP Server基本都是走这个。
- HTTP/SSE方式:通过HTTP协议暴露服务,适合远程调用,也是魔搭托管时主要采用的模式。
我的方案是两者都支持。本地调试用stdio,部署到魔搭之后对外暴露HTTP接口,这样既能本地快速验证,又能远程共享。
2.2 91个工具的分组策略
91个工具听起来很多,但如果全堆在一个Server里,无论是启动速度、内存占用、还是后续维护,都是灾难。我的做法是按领域分组成几个模块,每个模块独立实现、独立测试,最后在一个入口文件中统一注册。
整体分组如下:
| 模块 | 包含工具数量 | 典型工具 |
|---|---|---|
| 文件操作 | 18 | 读取文件、写入文件、追加内容、文件复制、移动重命名 |
| 目录管理 | 12 | 列出目录、递归遍历、创建目录、计算目录大小 |
| 数据处理 | 22 | JSON解析、JSON转字符串、Base64编解码、URL编码解码 |
| 网络请求 | 10 | HTTP GET/POST、下载文件、请求头处理 |
| 时间日期 | 9 | 当前时间、时间戳转换、格式化日期、时区换算 |
| 文本处理 | 12 | 字符串替换、正则匹配、大小写转换、MD5哈希 |
| 系统信息 | 8 | 系统平台、CPU架构、Node版本、内存信息 |
每个工具都实现为独立的函数,函数签名统一为(params) => result,其中params是JSON对象、result也是JSON对象,这样MCP协议封装起来非常干净——不需要为每个工具写适配层,只需要做一个通用的调用分发即可。
2.3 为什么选择TypeScript + npm组合
工具集本身用JavaScript写完全没问题,但我最终选了TypeScript,原因有三:
第一,类型安全。91个工具的参数要暴露给大模型去生成调用,如果参数类型不清晰,模型经常会产生莫名其妙的值。用TS定义好每个工具的inputSchema,可以让模型在生成调用时“有据可循”。
第二,生成d.ts声明文件。发布到npm后,其他开发者安装包时能获得完整的类型提示,这对一个面向开发者生态的包非常重要。
第三,编译后可以同时输出CJS和ESM格式。MCP Server要兼容各种不同环境的调用方,有的项目是CommonJS、有的已经切到ES Module,两种格式都输出可以避免“格式不支持”这种低级问题。
npm是Node生态最成熟的包分发渠道,几乎所有的MCP客户端都支持通过npm安装MCP Server依赖,这也是我选择npm作为分发介质的关键原因。
3. 核心实现:MCP Server构建全过程
3.1 环境准备与依赖安装
开发环境我建议直接用较新的Node LTS版本,我这边用的是Node 18.18.0,npm对应版本是9.8.1。如果你还在用Node 14或者更老的版本,建议先升级,否则后续很多依赖会报引擎不兼容。
创建项目目录并初始化:
mkdir mcp-toolkit cd mcp-toolkit npm init -y然后安装核心依赖:
npm install @modelcontextprotocol/sdk@latest npm install zod@^3.22.0 npm install typescript@^5.0.0 --save-dev npm install @types/node@^18.0.0 --save-dev这里重点说一下@modelcontextprotocol/sdk这个包,它就是MCP官方提供的TypeScript SDK,里面封装了MCP Server的所有底层逻辑——包括协议握手、消息路由、工具注册、请求响应分发。你不用自己实现协议细节,只需要调用它的接口把工具注册进去就行。
如果你安装时遇到npm err! code cert_has_expired这个报错,大概率是npm镜像的HTTPS证书过期了。解决办法是把镜像切回官方源,或者换一个证书正常的镜像,具体我放到后面的“常见问题”章节详细说。
3.2 用MCP SDK创建Server实例
接下来看核心代码。创建一个src/server.ts文件,用来创建MCP Server实例:
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; const server = new McpServer({ name: "mcp-toolkit", version: "1.0.0" }); // 注册工具的方法后面补充 export { server };这里McpServer是SDK提供的高层封装,它内部做了很多协议层的事情。比如客户端连接时会先发初始化请求,SDK会自动响应;客户端发tools/list会返回当前注册的所有工具列表;客户端发tools/call会路由到具体的工具执行函数。
如果你想要更底层的控制,也可以用Server类手动处理请求,但我觉得对于大多数工具集场景,直接用McpServer高层封装就够了,省心且不容易出错。
3.3 工具的注册与参数Schema定义
每个工具注册时,核心是告诉MCP框架三件事:工具名称、参数描述、执行函数。其中参数描述用的JSON Schema格式,它是让大模型“知道怎么调用工具”的关键。
我举个例子,注册一个“读取文件”工具:
import { z } from "zod"; server.registerTool( "read_file", { title: "读取文件内容", description: "读取指定路径的文本文件内容并返回,支持UTF-8编码", inputSchema: z.object({ filePath: z.string().describe("要读取的文件完整路径"), encoding: z.string().optional().default("utf-8").describe("文件编码格式,默认utf-8") }) }, async ({ filePath, encoding }) => { const content = await readFile(filePath, encoding); return { content: [{ type: "text", text: content }] }; } );这里有个细节值得注意:inputSchema用了zod来定义,SDK内部会把Zod的schema转换成标准的JSON Schema格式。每个字段一定要写describe()描述,因为这些描述会直接暴露给大模型,模型会根据描述来理解参数的含义。描述越清晰,模型生成的参数就越准确。
返回格式方面,MCP要求返回一个content数组,数组里的每一项可以是text类型(纯文本)、image类型(图片)、或resource类型(资源链接)。我绝大多数工具都返回text类型,这是最通用的形式,所有客户端都支持。
3.4 批量化注册91个工具的实现技巧
如果91个工具都像上面那样一个个registerTool,代码会非常冗余。我采用了一个“注册表”模式:先用一个数组把所有工具的定义集中管理,然后循环注册。
工具定义的结构统一为:
interface ToolDefinition { name: string; description: string; handler: (params: any) => Promise<any>; inputSchema: z.ZodObject<any>; }然后在src/tools/目录下按模块组织文件,每个文件导出一个工具定义数组:
// src/tools/fileTools.ts export const fileTools: ToolDefinition[] = [ { name: "read_file", description: "读取文件内容", handler: async ({ filePath, encoding }) => {...}, inputSchema: z.object({...}) }, // 其他17个文件相关工具 ];最后在入口文件里统一导入注册:
import { fileTools } from "./tools/fileTools.js"; import { dirTools } from "./tools/dirTools.js"; import { dataTools } from "./tools/dataTools.js"; // ... const allTools = [...fileTools, ...dirTools, ...dataTools, ...networkTools, ...timeTools, ...textTools, ...systemTools]; for (const tool of allTools) { server.registerTool( tool.name, { title: tool.name, description: tool.description, inputSchema: tool.inputSchema }, async (params) => { const result = await tool.handler(params); return { content: [{ type: "text", text: JSON.stringify(result) }] }; } ); }这样做的另一个好处是方便测试——每个工具模块可以独立导入进行单元测试,不需要启动整个MCP Server。
3.5 本地验证:用MCP Inspector调试
代码写完之后,本地调试是必须的步骤。MCP SDK官方提供了一个调试工具叫MCP Inspector,用它可以直观地看到Server注册了哪些工具、每个工具的输入输出结构。
先全局安装Inspector:
npm install -g @modelcontextprotocol/inspector然后在项目目录启动Inspector并连接我们的Server:
npx @modelcontextprotocol/inspector node dist/server.js浏览器会自动打开一个调试页面。在Inspector里,你可以:
- 查看
Tools List确认91个工具全部注册成功 - 点击每个工具,输入测试参数,直接调用执行
- 查看调用返回的数据结构是否符合预期
我第一次调试时发现有几个工具的注册顺序不对,导致工具ID重复覆盖,在Inspector里立刻就能发现,比写单测查问题快得多。
4. npm发布实战:从本地到全球分发的踩坑记录
4.1 npm包发布前的准备清单
发布npm包之前,有几个准备工作不能跳过,否则后面会各种报错。
第一步:检查npm账号并登录
npm login如果之前没注册过npm账号,需要先去 npmjs.com 注册。登录成功后,npm会把这个凭证保存在本地配置文件里,后续所有发布操作都基于这个凭证。
第二步:设置正确的package.json字段
{ "name": "mcp-toolkit", "version": "1.0.0", "description": "91个常用工具的MCP Server封装,支持stdio和HTTP两种传输方式", "main": "dist/index.js", "types": "dist/index.d.ts", "bin": { "mcp-toolkit": "dist/cli.js" }, "files": ["dist"], "scripts": { "build": "tsc", "start": "node dist/index.js", "prepublishOnly": "npm run build" }, "keywords": ["mcp", "mcp-server", "ai", "llm", "model-context-protocol"], "license": "MIT" }有几个字段需要特别解释:
files字段很关键,它决定哪些文件会被打包上传到npm。这里只放dist目录,源码、测试文件、配置文件都不会被上传,能大幅减小包体积。bin字段用来暴露命令行入口,这样用户安装后可以直接在终端执行mcp-toolkit命令启动Server。前提是你需要有一个src/cli.ts文件,里面调用stdio传输启动服务。prepublishOnly脚本会在发布前自动执行构建,确保你发布出去的永远是编译后的最新代码。
第三步:创建.npmignore或利用files字段排除无用文件
我建议直接用files白名单模式,比.npmignore黑名单模式更可控,不容易出现“忘记排除某种文件”的问题。
4.2 构建TypeScript并生成声明文件
TypeScript编译配置也有讲究。我的tsconfig.json关键配置如下:
{ "compilerOptions": { "target": "ES2020", "module": "NodeNext", "moduleResolution": "NodeNext", "outDir": "./dist", "rootDir": "./src", "strict": true, "declaration": true, "declarationMap": true, "sourceMap": true, "esModuleInterop": true, "skipLibCheck": true, "forceConsistentCasingInFileNames": true }, "include": ["src/**/*"], "exclude": ["node_modules", "dist", "**/*.test.ts"] }这里declaration: true是必须的,它会生成.d.ts类型声明文件,用户安装你的包后能获得完整的类型提示。module和moduleResolution设成NodeNext是为了兼容后续可能需要的ESM/CJS双格式输出。
执行构建:
npm run build构建完成后,检查一下dist目录内容:
ls dist # index.js index.d.ts cli.js tools/ ...确认产物正常后,就可以打本地包测试了:
npm packnpm pack会在本地生成一个mcp-toolkit-1.0.0.tgz文件,你可以把它安装到其他项目里做验证,确认没有问题再真正发布。这一步强烈建议做,因为发布到npm上是不可撤回的(即使删包,已经被别人引用的版本也无法移除)。
4.3 发布到npm:第一次遇到的证书过期问题
发布命令本身很简单:
npm publish但是我很确定,如果你使用默认的官方registry,大概率会遇到一个坑——证书过期问题。
报错信息长这样:
npm ERR! code cert_has_expired npm ERR! errno cert_has_expired npm ERR! request to https://registry.npm.taobao.org/mcp-toolkit failed, reason: certificate has expired这个报错的原因很直白:你本地的npm镜像地址指向了某个已停止维护的镜像源,而这个源现在依然在用早期版本的CA证书,证书过期后,npm的HTTPS请求就完全没法建立连接。
解决方式很简单:
# 查看当前镜像配置 npm config get registry # 如果输出的是 http://registry.npm.taobao.org 或者类似的镜像地址,改成官方源 npm config set registry https://registry.npmjs.org改完之后再重新登录并发布,这个问题就没了。
顺带说一句,如果你长期依赖镜像源加速,建议关注镜像源的维护状态,别等报错了才处理。现在很多镜像站点已经不再提供npm代理服务了,与其用各种不稳定的第三方镜像,不如直接用官方源,配合本地缓存,速度其实不差。
4.4 实际发布流程与版本迭代策略
发布成功后,接下来就是版本迭代了。我的迭代策略遵循semver语义化版本规范:主版本号(major)在大功能重构时+1,次版本号(minor)在新增工具时+1,补丁号(patch)在修复bug时+1。
每次发版前执行:
npm version minor # 自动升级次版本号并打tag npm publish这里有个建议:npm version命令会自动修改package.json并创建git tag,但如果你不想要git tag,可以加--no-git-tag-version参数:
npm version minor --no-git-tag-version另外,npm发布是“不可覆盖”的。同一个版本号只能发布一次,再补充代码就需要升级版本号。如果发现发布的包有严重bug,可以使用npm unpublish撤销,但有时间限制——发布后72小时内可以撤销,超过72小时就只能发布新版本修复。所以发版前务必在本地自测充分。
4.5 从零到上线:发布MCP Server到npm的完整流程
整理一下发布MCP Server到npm的完整流程,方便你照着做:
- 确认node/npm版本可用:
node -v && npm -v npm login登录npm账号- 修改package.json中name、version、files、bin等字段
- 执行
npm run build编译TypeScript - 执行
npm pack本地打包检查内容 - 在临时目录安装tgz包,写一个简单测试脚本验证可运行
- 执行
npm publish发布 - 发布完成后,在另一台机器上执行
npm install mcp-toolkit验证安装
每一步看起来简单,但漏掉任何一步都可能在用户侧产生问题。尤其是第6步——本地包验证,很多人跳过它直接发布,结果用户安装后才发现bin路径写错、入口文件引用错误等低级问题,非常尴尬。
5. 魔搭托管实践:把MCP Server部署到云端的经验
5.1 为什么选择魔搭托管
既然MCP Server已经通过npm发布了,为什么还要做魔搭托管?
原因很直接:npm包适合开发者本地安装使用,但如果你想要一个随时可访问、无需安装、跨设备共享的MCP服务端点,就需要云端托管。魔搭平台(ModelScope)提供了模型和应用的托管能力,你可以把MCP Server作为一个AI应用托管到魔搭上,它会分配一个公开的HTTP地址,任何支持远程MCP的客户端(比如Claude Desktop、Cursor等)都可以直接通过URL连接使用。
从架构上看,这解决了“我用npm包方式只能本机自己调试”的局限——团队里其他人想用你的工具集,不需要装Node环境,不需要npm install,直接在客户端配置里填一个URL就能连上。
5.2 魔搭托管的MCP Server改造
要让MCP Server跑在魔搭的HTTP环境里,需要做一个关键的改造:从stdio传输切换到HTTP/SSE传输。
本地调试时我们用StdioServerTransport,它通过标准输入输出通信。但在云端,客户端无法直接访问Server的stdin/stdout,必须通过HTTP来通信。MCP SDK提供了StreamableHTTPServerTransport和SSEServerTransport两种HTTP传输方式。
我的方案是写一个Express服务器,用SSE方式暴露MCP接口:
import express from "express"; import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js"; import { server } from "./server.js"; const app = express(); app.get("/sse", async (req, res) => { const transport = new SSEServerTransport("/messages", res); await server.connect(transport); }); app.post("/messages", express.json(), async (req, res) => { // SSE传输模式下的消息接收端点 }); app.listen(3000, () => { console.log("MCP Server listening on port 3000"); });在魔搭上托管时,应用的端口不是自己决定的,而是平台会注入一个环境变量PORT,你需要监听这个端口:
const port = process.env.PORT || 3000; app.listen(port, () => { console.log(`MCP Server listening on port ${port}`); });5.3 魔搭托管的实际部署坑点
这块是我踩坑最密集的地方,整理几个典型的:
坑点一:SSE连接超时问题
HTTP远程连接和本地stdio连接最大的不同在于:本地进程的持久性有保障,而HTTP服务可能会在没有请求时被平台回收空闲连接。如果客户端长时间没有调用工具,SSE连接可能会断开,需要客户端自动重连。
这在魔搭的免费托管环境里特别明显——空闲一定时间后应用会被挂起,第一次请求需要等恢复,延迟会比较高。解决方法是在客户端配置里减少心跳间隔,或者在服务端增加Keep-Alive心跳。
坑点二:环境变量与配置文件
本地调试时你可能在.env文件里配置了各种密钥和参数,魔搭托管时这些配置文件不会自动带上去。你需要把环境变量手动配置到魔搭应用的环境变量设置中,或者把配置直接写到代码里(不推荐,容易泄露)。
坑点三:构建流程的差异
魔搭的托管平台一般支持从源码构建和部署,你需要提供明确的启动命令。比如:
npm run build && npm start同时要注意,平台可能不会执行npm install的devDependencies安装——如果构建脚本依赖TypeScript编译器,你得确认安装阶段会同时安装devDependencies,否则构建会失败。
坑点四:CORS跨域限制
如果你的MCP Server要接Web前端,或者某些客户端是在浏览器环境跑的,CORS跨域问题就躲不开。需要在Express中间件里统一处理CORS头:
app.use((req, res, next) => { res.setHeader("Access-Control-Allow-Origin", "*"); res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS"); res.setHeader("Access-Control-Allow-Headers", "Content-Type"); if (req.method === "OPTIONS") return res.sendStatus(200); next(); });5.4 魔搭托管的MCP服务验证
部署成功后,怎么验证云端MCP Server能正常被客户端调用?
我建议用两种方式验证:
第一种:用MCP Inspector连接远程地址
在Inspector的配置界面,输入魔搭分配的应用URL(SSE端点),选择远程连接模式,确认能加载到工具列表,然后调用一个简单工具测试。
第二种:直接写一个Node脚本调用
import { Client } from "@modelcontextprotocol/sdk/client/index.js"; import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js"; const transport = new SSEClientTransport(new URL("https://your-app.modelscope.cn/sse")); const client = new Client({ name: "test-client", version: "1.0.0" }); await client.connect(transport); const tools = await client.listTools(); console.log(`工具数量: ${tools.tools.length}`); const result = await client.callTool({ name: "get_current_time", arguments: {} }); console.log(result);如果这段脚本能正常输出工具列表和调用结果,说明云端托管完全可用。
6. 高频报错排查与避坑指南
6.1 Windows环境npm不可用的经典报错及解法
无论你是做MCP Server开发,还是单纯想在Windows上安装npm包,大概率会遇到这个经典报错:
npm : 无法加载文件 C:\Program Files\nodejs\npm.ps1,因为在此系统上禁止运行脚本这个问题根因是PowerShell的执行策略默认不允许运行脚本文件,而npm.ps1恰恰是一个PowerShell脚本。npm本身是Node自带的,并没有问题。
最快的解决方案有两种:
# 方案一:以管理员身份打开PowerShell,修改当前用户的执行策略 Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser # 方案二:只对当前会话临时放开 Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass方案一会永久修改当前用户的PowerShell策略,比较方便;方案二只对当前终端窗口有效,安全一些但每次要重设。我个人建议用方案一,RemoteSigned只允许运行本机创建的脚本和互联网上下载但已签名的脚本,安全性已经足够。
6.2 npm镜像、证书过期、网络连接异常相关报错汇总
开发过程中,npm安装和发布相关的报错有一大部分是网络和源配置引起的。我整理了一个速查表:
| 报错信息 | 根本原因 | 解决方案 |
|---|---|---|
npm ERR! code cert_has_expired | 镜像源证书过期 | npm config set registry https://registry.npmjs.org |
npm WARN deprecated node-domexception@1.0.0 | 依赖了废弃包,但仅是警告 | 无需处理,等待依赖方更新 |
npm ERR! code EUNSUPPORTEDPROTOCOL | package.json中依赖的git协议不支持 | 将git://改成https:// |
npm : 无法将“npm”项识别为 cmdlet... | npm不在PATH环境变量中 | 重装Node并勾选添加到PATH,或手动配置环境变量 |
npm ERR! request to https://registry.npm.taobao.org/... failed | 镜像源本身不可用 | 切换官方源或其他可用镜像 |
npm WARN using --force recommended protections disabled | 使用了--force参数 | 正常发布不用加force,确认无冲突 |
其中EUNSUPPORTEDPROTOCOL这个错误比较隐晦,它一般出现在你安装某个依赖包时,该包的package.json里声明了git://协议的依赖地址。新版npm出于安全考虑不支持这种协议,解决办法是全局配置git协议替代:
git config --global url."https://github.com/".insteadOf "git://github.com/"6.3 NPM环境变量配置的正确姿势
很多新人会在Windows上遇到“npm不是内部或外部命令”的报错,这是环境变量配置问题。
正常安装Node.js时,安装器会把C:\Program Files\nodejs\添加到系统PATH。如果你之前安装过不同版本的Node导致PATH混乱,或者手动解压了Node压缩包而没有配置环境变量,就会触发这个问题。
手动配置环境变量的步骤:
- 右键“此电脑” → 属性 → 高级系统设置 → 环境变量
- 在“系统变量”中找到
Path,点击编辑 - 新增一行,内容为Node的实际安装路径,比如
D:\nodejs\ - 确定保存,重新打开终端窗口
配置完后执行npm -v能正常输出版本号就说明配置成功了。
不过我的建议是,如果条件允许,直接用官方安装包安装Node,别用手动解压的方式,能少踩很多环境变量相关的坑。
6.4 MCP Server运行时的常见问题
工具集运行过程中也遇到过一些值得记录的问题:
问题一:工具返回内容过大导致传输失败
MCP协议对返回内容大小没有统一的硬性限制,但客户端和服务端的实现可能有实际限制。读取大文件时,一次性返回整个内容会把消息体积撑爆。
我的解决方案是对大文件读取工具做截断处理,增加一个maxLength参数,默认只返回前100KB内容,并提供偏移量参数让调用方分批次读取。
问题二:异步处理未等待导致返回空结果
写工具时,如果异步处理回调没有正确await,很容易返回一个未解析的Promise对象,MCP客户端接到的就是个空壳。
排查方法是统一在工具执行函数外面包一层异常捕获和Promise等待处理:
async function safeExecute(handler: Function, params: any) { try { const result = await Promise.resolve(handler(params)); return { success: true, data: result }; } catch (error: any) { return { success: false, error: error.message || String(error) }; } }问题三:工具名冲突
MCP协议中工具名是全局唯一的标识,如果两个工具注册了相同的名字,后者会覆盖前者,导致调用行为异常。批量注册时一定要加一个名称去重校验逻辑,确保没有重复项。
问题四:SDK版本不一致
如果你的Client和Server用的MCP SDK版本跨度太大,协议版本协商可能出问题。比如某些旧版SDK的实现不支持新版协议特性。遇到连接失败或tools/list响应为空时,先检查两端SDK版本是否兼容。
7. 扩展思路:这个项目还能怎么玩
91个工具做完,MCP Server发布到npm,也托管到云端了,项目到这里已经是一个完整可用的状态。但回头看,这个项目的扩展空间还很大。
方向一:接入更多垂类工具
91个工具覆盖的是通用基础操作,后续可以针对特定领域扩展。比如数据库工具集(MySQL/PostgreSQL查询)、浏览器自动化工具集、代码分析工具集、甚至Git操作工具集——每个方向做一套独立的MCP包,按需安装,比一个大而全的包更灵活。
方向二:支持多语言客户端
我目前的实现是基于Node/TypeScript的,但MCP协议是语言无关的。官方SDK除了TypeScript,还有Python、Java、Kotlin、C#等语言的版本。如果团队里有Python开发者,可以考虑用Python重写一套,或者通过HTTP桥接方式让Python客户端也能调用Node实现的Server。
方向三:工具调用上增加缓存和限流
云端托管的MCP Server如果被多人使用,无差别的调用可能导致资源竞争。可以给一些耗资源的工具加上Redis缓存,相同参数短时间内的重复调用直接走缓存;同时给单客户端做速率限制,防止少数客户端占用大量资源。
方向四:把工具集接入到自定义Agent框架
最后我觉得这个项目最有价值的地方在于:当你有一套标准化的MCP工具集之后,任何支持MCP的Agent框架都能直接使用它,不需要为不同框架写不同的插件。这是一个标准协议带来的生态红利,也是我当初决定投入时间做这个项目的最重要原因。