尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

91个工具统一接入MCP:从本地封装到npm发布全程实践

发布时间:2026/9/9 0:09:56

资讯中心
01
ARTICLE

91个工具统一接入MCP:从本地封装到npm发布全程实践

91个工具统一接入MCP:从本地封装到npm发布全程实践
说真的在没有集中整理之前我完全没想到自己手边会凑出 91 个高频工具。它们的形态很乱有 Python 小脚本、有命令行工具、有封装好的 REST 接口甚至还有几段常年挂在笔记软件里的「复制即用」代码。每次想把这些能力交给 AI 客户端我都得单独写一段工具描述、定义一套参数规则再把结果格式折腾成模型能看懂的样子。91 个工具这么做下来光是胶水代码就几千行根本维护不动。所以当我开始认真研究 MCP 协议又因为要做成远程可调用的服务开始折腾 npm 发布和魔搭社区托管时我知道这次必须把整套流程走通、走透。这篇文章就是这轮实践的完整记录从工具怎么归类设计、MCP Server 怎么封装到 npm 包发布时那些让人血压升高的报错再到魔搭 Notebook 里跑服务遇到的保活问题全部摊开讲。不管你是想把现有工具交给 AI 使用还是单纯想了解 MCP 项目从本地到托管发布的完整链路应该都能找到可以直接抄作业的部分。1. 为什么要把 91 个工具统一做成 MCP1.1 工具多到一定程度接口混乱就是最大的成本如果你只有三五个工具那无所谓每个工具单独接一遍也不费事。但工具到 91 个真正的痛点已经不是「某个工具有没有 bug」而是「这堆工具怎么被 AI 发现、怎么被统一调用」。先说场景。我这边涉及的工作流很杂有人要处理 JSON/XML/CSV 这类结构化数据有人要查日期、做时间戳换算有人要读文件、校验 URL 状态、跑正则测试还有人要让我帮忙整理 Git 提交信息。以前这些能力分散在各处AI 客户端想用它的时候要么我重新描述要么让模型自己猜参数格式结果就是经常出现工具没被调用或者参数传错。MCP 解决的是这个核心问题它做了一层标准的「工具发现 工具调用」协议。客户端向 Server 发一条tools/list就能拿到全部工具的名字、描述、参数结构真正执行时发tools/callServer 把结果以统一结构返回。这样 AI 就不再依赖开发者手写什么「使用说明」它自己就能读懂每个工具怎么用。91 个工具接一遍 MCP等于只接了一遍后面所有支持 MCP 的客户端都能直接复用。1.2 MCP 到底是什么模型端口的「万能插座」我一直觉得官方那个类比很到位如果说大语言模型是一个只会聊天的大脑那 MCP 就是给大脑配备的一套标准化接口。没有这个标准的时候你想给模型接一个计算器得单独造线想接一个数据库又得单独造一种线。但大家统一采用 MCP 之后任何支持 MCP 的模型客户端都能像 USB-C 一样直接插上任何 MCP Server。在协议层面你只需要关心三个角色MCP Server 是提供工具的服务端MCP Client 是宿主程序比如 Claude Code、Codex、Cherry Studio 这类工具两者之间走 JSON-RPC 2.0 消息。传输方式常见的就两种本地用 stdio也就是客户端直接拉起一个子进程远程用 Streamable HTTP通过网络访问。这也解释了为什么最近「XX MCP」会突然变多Figma、蓝湖、Unity、Cocos Creator 甚至一些安全测试工具都在做官方接入因为它们都希望自己的功能能被 AI 直接调用。MCP 不限制你是什么生态的产品只要实现一套协议整个 AI 工具链都能成为你的入口。1.3 MCP、Agent Skill、Computer Use 到底是什么关系顺着这个话题我把几个容易混的概念也理清一下。插件和 Function Calling 属于「单机时代的方案」每个模型厂商有自己的一套工具定义方式你在 ChatGPT 里写的工具描述拿到 Claude 里往往不通用。MCP 是跨厂商的中间协议所有客户端用同一套对话方式。Agent Skill 更靠近「流程编排」。一个 Skill 可以包含多步骤的提示词、内部工具处理逻辑甚至能把多个 MCP 工具的调用串起来变成一个技能。所以更准确的理解是MCP 是一个个能被调用的标准操作Skill 是叠加在这些操作之上的使用策略。Computer Use 则是另一个极端。它让模型像人一样看屏幕、动鼠标键盘适合没有 API 的系统但速度慢、误操作率高、也不容易审计。我这次做 91 个工具优先考虑的是可靠和可追踪所以全部走 MCP 的 API 式调用让模型精确拿到结构化数据而不是让它靠截图去猜。2. 整体设计如何给 91 个工具做一张统一的「工具清单」2.1 先给 91 个工具分类没有边界的工具集跑不了多远动手封装前我先把所有工具摊在桌面上分了一次类。这不是为了好看而是为了后续几件事哪些工具要默认加载、哪些工具要加安全确认、哪些模块适合单独拆包都是以分类为基础的。我最终的分类结构大概是这样的分类数量代表性工具文件与编码相关16文件读取、路径解析、base64 编码、哈希计算HTTP 与网络请求12请求 JSON 接口、URL 状态检测、响应头查看结构化数据转换20JSON/XML/CSV/YAML 互转、格式校验、字段提取时间与日历8时间戳换算、时区换算、日期计算开发辅助与 Git 信息15Git 状态、提交信息规范、语义化版本比较系统环境与进程查询10CPU/内存占用、端口检测、进程列表文本生成与格式化10正则测试、文本截断、diff 生成、代码格式化91 这个数字看起来吓人但每个工具落到实处平均就是几十行业务代码。真正的难度在于维护边界你不能让一个「文本截断工具」顺手去删文件也不能让一个「读取文件工具」变成任意文件读取漏洞。分类就是第一道边界后面安全策略也跟着分类走。2.2 用统一基类把 91 个工具的注册代码压到最少规划完分类后我没有给每个工具单独写一套 MCP 注册逻辑而是把每个工具定义成一个结构化的ToolDefinition对象让注册器统一处理。一个工具的核心信息包括名字、描述、参数 Schema、执行函数。这样 91 个工具就是数组中 91 个对象注册器遍历数组后自动在 MCP Server 上注册。我给个简化示意配合现在官方的modelcontextprotocol/sdk写import { McpServer } from modelcontextprotocol/sdk/server/mcp.js; import { randomUUID } from node:crypto; export interface ToolDefinition { name: string; title: string; description: string; inputSchema: { type: object; properties: Recordstring, unknown; required?: string[]; }; handler: (args: any) Promise{ ok: boolean; data?: unknown; error?: string }; } const tools: ToolDefinition[] [ { name: uuid_generate, title: 生成 UUID, description: 生成一个随机 UUID v4 字符串。当用户需要唯一标识时调用。, inputSchema: { type: object, properties: {}, required: [], }, handler: async () { return { ok: true, data: randomUUID() }; }, }, // 这里实际一共有 91 个工具定义按分类放在不同目录导入 ]; const server new McpServer({ name: mcp-91-tools, version: 1.4.0 }); for (const tool of tools) { server.registerTool(tool.name, { title: tool.title, description: tool.description, inputSchema: tool.inputSchema, }, async (args) tool.handler(args)); }采用这种结构新增一个工具时我只需要关注业务函数本身不用关心 MCP 注册细节。后面做发布前检测也方便遍历数组就能自动检查有没有重复名字、有没有空描述、Schema 里是不是每个必填参数都做了说明。2.3 工具描述和参数 Schema 的写作规范在 MCP 场景下工具描述不是写给用户看的说明书而是写给模型看的「路由指标」。我从这轮踩坑中学到的经验是描述里不能只写功能更要写清楚「什么时候该调用它」。举个例子与其写「把 JSON 转成 YAML」不如写「当用户提供 JSON 内容并要求转换为 YAML 格式时调用。输入必须是合法 JSON 字符串输出为缩进 2 空格的 YAML。」模型在判断调用哪个工具时靠的就是这段话和用户请求的语义匹配度。描述写得精确一点误调用的概率会明显下降。参数 Schema 我坚持一个原则能少就给少。一个工具超过五个参数模型就很容易漏传或传错。那些可选的参数全给默认值实在没法给默认值的就把可选范围写死在描述里。比如端口号你可以写清楚有效范围是 1~65535比如编码格式直接列出 UTF-8/GBK/UTF-16 供模型选择别让它自由发挥。2.4 安全开关与工具分级这是 91 个工具里最容易被低估的部分。工具接上 MCP 后模型在用户授权下是可能主动调用工具的所以「只读工具」和「危险操作工具」必须分开。我这里的做法是把工具分为两类默认加载的绝大多数是只读或低风险工具比如读文件、查时间、做格式转换另一类涉及写文件、执行命令或者删除资源的工具默认不会注册进 MCP Server需要显式设置环境变量MCP_ENABLE_DANGEROUS1才会加载。启动命令就是MCP_ENABLE_DANGEROUS1 npx -y mcp-91-tools这个开关很重要。你平时在本地用关闭危险工具省心真要把服务暴露到公网或者放到共享环境至少能保证模型默认情况下没有删除类权限。别嫌麻烦这比事后补救便宜得多。3. npm 发布全过程与环节排错3.1 先确定分发粒度一个主包还是按域拆包91 个工具的包怎么发布我犹豫过一阵。方案一是一个主包全部塞进去简单粗暴方案二是按分类拆成 7 到 10 个小包用户按需安装。拆包的好处是用户只需要装自己用得到的模块版本管理和包体体积都更可控。但对 91 个工具来说拆包的代价很高包与包之间要共享底层代码用户配置客户端时要写 7 个启动命令版本同步也容易乱。我最终的结论是先用一个主包发布内部按目录组织等工具数量超过 200 或出现明显的领域隔离需求再拆。给客户端配置时入口统一是npx -y mcp-91-tools这样用户在 Claude Desktop、Cherry Studio、Codex 这些客户端里只需要写一次启动命令就行体验是最好的。3.2 package.json 与构建产物配置npm 包能不能被别人顺利安装使用package.json 里的字段决定了一大半。我这次发布前重点检查了几个字段name、version、type、bin、exports、files、engines、publishConfig。基础配置我给个参考{ name: mcp-91-tools, version: 1.0.0, type: module, bin: { mcp-91-tools: ./dist/cli.js }, exports: { .: { import: ./dist/index.js, require: ./dist/index.cjs } }, files: [ dist, README.md, LICENSE ], engines: { node: 18 }, publishConfig: { access: public } }这里最容易踩坑的是两点。第一files字段一定要配。不配的话npm 会把项目里几乎所有文件都打进包里连node_modules里那些依赖也可能被卷进去包体直接变大几十倍而且可能泄露一些不该公开的文件。第二type: module配合exports时如果同时想兼容 ESM 和 CommonJS需要构建时打出两套产物。我用 tsup 配置了双格式输出确保import和require都有对应文件。以前我只发 ESM 版本结果遇到老项目用require加载时直接报ERR_REQUIRE_ESM折腾了很久才补上 CJS 产物。3.3 发布前一定先做本地模拟安装我这次的教训是npm publish之前别只在项目目录里跑一遍就以为万事大吉。最可靠的方式是先执行npm pack生成本地 tgz 包然后在另外一个全新目录里安装这个 tgz模拟用户从 npm 拉包的完整效果。具体的验证流程我建议这么做先npm run build检查构建产物有没有生成完整。跑npm pack --dry-run看打包清单里有没有多余文件或漏掉的目录。正式npm pack得到类似mcp-91-tools-1.0.0.tgz的文件。新建一个空目录执行npm init -y后安装本地 tgznpm install /路径/mcp-91-tools-1.0.0.tgz。在这个新目录里执行npx mcp-91-tools --help看能不能正常启动。用测试客户端连接本地启动的 Server执行一次 initialize、一次 tools/list确认能看到完整工具列表。这套流程走完基本能排除 90% 的「在我电脑上是好的」问题。很多 npm 包发布后别人装不上正是因为作者只在本项目里测过本地依赖和运行时路径早就被 node_modules 掩盖了。3.4 npm 环境高频报错与解决记录如果你也常折腾 npm下面这几个报错应该都不陌生。第一个是 Windows PowerShell 下的执行策略问题。错误提示会出现「无法加载文件...npm.ps1因为在此系统上禁止运行脚本」这类内容。原因是 PowerShell 默认执行策略是 Restricted不允许直接跑 .ps1 脚本。解决办法是在 PowerShell 里执行Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser修改后会允许运行本地脚本远程下载的未签名脚本仍然受限比直接设成 Unrestricted 要安全一些。如果只想临时用也可以切到 CMD 里执行 npmCMD 不会走 PowerShell 执行策略。第二个是「npm 不是内部或外部命令」。这基本上就是 Node.js 安装时没有把安装目录加入系统的 PATH或者你改过环境变量后没有重新打开终端。Windows 下检查路径是否包含C:\Program Files\nodejs\配置好后重启终端再试。第三个是证书过期类报错比如npm ERR! code CERT_HAS_EXPIRED npm ERR! request to https://registry.npm.taobao.org/... failed, reason: certificate has expired这个报错典型场景是 registry 还指向老的淘宝镜像源那个源的证书已经失效。新版淘宝源地址已经变成了https://registry.npmmirror.com执行下面的命令改回来就好npm config set registry https://registry.npmmirror.com如果不想用国内源也可以直接切回官方源npm config set registry https://registry.npmjs.org/第四个是EUNSUPPORTEDPROTOCOL。这个报错通常是因为 registry 配置成了git://、gitssh://这类非 HTTP(S) 协议npm 不认。检查.npmrc里的 registry 值确保是完整的https://地址。第五个是npm WARN deprecated和npm WARN using --force recommended protections disabled。前者只是提示某个依赖包已经废弃升级或替换即可后者表示你用了--force强行安装跳过了 npm 的一些保护检查不建议作为常规操作。3.5 发布后立刻用真实客户端实测包发到 npm 之后真正的测试才刚开始。我这边用了
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。