Doramagic 项目包 · 项目说明书
npm-run-mcp-server 项目
生成时间:2026-06-02 03:15:54 UTC
项目概述
npm-run-mcp-server 是一个基于 Model Context Protocol (MCP) 的服务器项目,它能够将项目中的 package.json 脚本自动暴露为可供 AI 代理使用的 MCP 工具。通过这种方式,AI 助手(如 Claude、Cursor、GitHub Copilot)可以直接调用项目定义的 npm 脚本进行构建、测试、部署等操作,无需人...
继续阅读本节完整说明和来源证据。
npm-run-mcp-server 是一个基于 Model Context Protocol (MCP) 的服务器项目,它能够将项目中的 package.json 脚本自动暴露为可供 AI 代理使用的 MCP 工具。通过这种方式,AI 助手(如 Claude、Cursor、GitHub Copilot)可以直接调用项目定义的 npm 脚本进行构建、测试、部署等操作,无需人工介入。
来源:https://github.com/fstubner/npm-run-mcp-server / 项目说明书
快速开始
npm-run-mcp-server 是一个基于 Model Context Protocol (MCP) 的服务器,它能够自动将项目的 package.json 中的脚本转换为 AI 助手可调用的工具。通过这种设计,AI 代理可以直接执行项目的构建、测试、部署等操作,无需人工介入。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
功能概述
该工具的核心价值在于消除 AI 代理与项目脚本之间的隔阂。传统的 AI 助手虽然能够理解代码,但在执行实际操作时往往需要手动复制粘贴命令或依赖用户手动操作。npm-run-mcp-server 通过将 package.json 中的脚本暴露为标准化的 MCP 工具,解决了这一痛点。
项目的关键特性包括:自动检测当前目录的 package.json 文件;智能识别并支持 npm、pnpm、yarn、bun 四种主流包管理器;通过配置文件实现脚本的白名单和黑名单控制;支持为每个脚本定义输入参数模式和描述,帮助 AI 准确理解何时以及如何调用这些脚本;最后,项目开箱即用,零配置即可工作,同时在需要时提供丰富的自定义选项。
环境要求
根据 package.json 中的定义,该项目要求 Node.js 版本不低于 18.18.0。这一版本要求主要是因为项目使用了 ES Modules 模块系统("type": "module")和 @modelcontextprotocol/sdk 依赖,这些都依赖于较新版本的 Node.js 运行时特性。
支持的 AI 客户端
npm-run-mcp-server 遵循 MCP 协议的 stdio 传输标准,可以与多种 AI 客户端集成。项目已在 README.md 中明确测试并支持以下客户端:
Claude Desktop 是首个官方支持的客户端。用户需要在 claude_desktop_config.json 配置文件中添加 MCP 服务器配置,配置内容包括服务器类型为 command、命令为 npx、参数为 ["-y", "npm-run-mcp-server"]。这种配置方式使得 Claude Desktop 能够在启动时自动加载并使用 npm-run-mcp-server。
Cursor 是另一个主要支持的客户端。用户可以通过 Settings > Features > MCP Servers 界面添加新服务器,或者使用项目提供的一键安装链接。配置文件位于 .vscode/settings.json,使用 github.copilot.chat.mcpServers 键进行配置。
VS Code (GitHub Copilot) 同样支持该 MCP 服务器,配置方式与 Cursor 类似,也需要在 .vscode/settings.json 中添加相应的配置项。
快速配置步骤
基本配置
对于大多数用户而言,无需任何配置即可开始使用。只需确保目标项目的 package.json 中定义了脚本,AI 客户端就能自动识别并暴露这些脚本作为可调用工具。
基本的集成配置取决于所使用的 AI 客户端。对于 Claude Desktop,需要编辑 claude_desktop_config.json 文件;对于 Cursor 和 VS Code,则需要编辑工作区的 .vscode/settings.json 文件。无论哪种情况,核心配置结构都保持一致。
配置文件
项目支持通过 npm-run-mcp.config.json 或 .npm-run-mcp.json 文件进行细粒度控制。配置文件应放置在项目根目录,与 package.json 同级。
配置文件的 JSON Schema 定义在 npm-run-mcp.config.schema.json 中,支持以下顶层字段:include 用于指定要暴露的脚本名称数组;exclude 用于指定要隐藏的脚本名称数组;scripts 用于为特定脚本提供详细的元数据覆盖。
{
"include": ["test", "lint", "build"],
"exclude": ["eject", "publish"],
"scripts": {
"test": {
"description": "运行测试套件",
"inputSchema": {
"properties": {
"watch": { "type": "boolean", "description": "监视文件变更" }
}
}
}
}
}
配置文件的解析支持 JSONC 格式,这意味着可以在文件中添加注释和尾随逗号,这与 TypeScript 的配置习惯保持一致。
CLI 参数
除了配置文件,还可以通过命令行参数进行控制。主要参数包括:--cwd <path> 用于手动设置工作目录;--pm <npm|pnpm|yarn|bun> 用于强制指定包管理器;--config <path> 用于指定配置文件路径;--verbose 用于启用详细日志输出。
使用 --verbose 参数时,服务器会向 stderr 输出诊断信息,包括当前工作目录、检测到的工作区文件夹、使用的 package.json 路径以及检测到的包管理器类型。这些信息对于调试配置问题非常有用。
工作流程
当 npm-run-mcp-server 启动时,它会按照特定的优先级顺序确定工作目录。优先级从高到低依次是:--cwd 命令行参数、WORKSPACE_FOLDER_PATHS 环境变量(Cursor 设置)、VSCODE_WORKSPACE_FOLDER 环境变量、CURSOR_WORKSPACE_FOLDER 环境变量。如果以上都没有设置,服务器会尝试在当前目录及上级目录中查找 package.json 文件。
找到 package.json 后,服务器会调用 detectPackageManager 函数确定使用哪个包管理器。检测逻辑首先检查配置文件中是否有 --pm 参数覆盖,然后检查 package.json 中的 packageManager 字段,最后根据 lockfile 文件的存在与否进行推断。pnpm 使用 pnpm-lock.yaml,Yarn 使用 yarn.lock,Bun 使用 bun.lockb 或 bun.lock,如果都不存在则默认使用 npm。
脚本名称会经过 sanitizeScriptName 函数处理,转换为有效的工具名称。该函数将所有字符转换为小写,并将非字母数字字符替换为下划线,确保生成的工具名称符合 MCP 协议的要求。
工具调用机制
每个暴露的脚本都会创建一个 MCP 工具,工具的定义包括名称、描述和输入模式。输入模式默认包含两个字段:_ 用于传递额外的字符串参数数组,args 用于传递自由格式的参数字符串。
如果脚本在配置文件中定义了 inputSchema,服务器会使用 jsonSchemaToZod 函数将其转换为 Zod 验证模式。该函数支持多种 JSON Schema 类型,包括 string、boolean、number、integer、array、object 以及 enum 类型。转换后的 schema 会用于验证 AI 传递的参数,确保参数类型正确。
当 AI 调用工具时,服务器会执行以下流程:首先从参数中提取配置定义的选项和 args 字段;然后使用 buildCliFlags 函数将参数转换为命令行标志;接着调用 buildRunCommand 生成最终的命令和参数;最后通过 runProcess 函数执行脚本。
runProcess 函数使用 Node.js 的 spawn 函数创建子进程,支持的最大输出捕获量为 120000 字符。如果输出超过限制,会自动截断并添加提示信息。脚本执行的默认超时时间为 5 分钟,如果超时则会被终止。
包管理器检测
包管理器检测逻辑的实现位于 src/index.ts 中的 detectPackageManager 函数。函数首先检查是否有显式的参数覆盖,然后检查 package.json 中的 packageManager 字段(该字段通常在 Corepack 启用的项目中出现),最后根据 lockfile 文件进行推测。
function detectPackageManager(projectDir: string, pkg: PackageJson, override?: PackageManager): PackageManager {
if (override) return override;
if (pkg.packageManager) {
const pm = pkg.packageManager.split('@')[0] as PackageManager;
if (pm === 'npm' || pm === 'pnpm' || pm === 'yarn' || pm === 'bun') return pm;
}
if (existsSync(resolve(projectDir, 'pnpm-lock.yaml'))) return 'pnpm';
if (existsSync(resolve(projectDir, 'yarn.lock'))) return 'yarn';
if (existsSync(resolve(projectDir, 'bun.lockb')) || existsSync(resolve(projectDir, 'bun.lock'))) return 'bun';
return 'npm';
}
命令执行则由 buildRunCommand 函数处理,该函数根据选定的包管理器生成对应的命令格式。例如,对于 npm 执行 npm run <script>,对于 pnpm 执行 pnpm run <script>,以此类推。
常见问题排查
如果 AI 助手无法看到脚本,首先检查项目根目录是否存在有效的 package.json 文件,且其中包含 scripts 字段。可以使用 --list-scripts 参数直接列出所有可用的脚本进行验证。
如果脚本执行失败,检查 AI 传递的参数是否符合配置的 inputSchema 要求。可以通过 --verbose 参数启用详细日志,查看服务器接收到的具体参数值和执行命令。
如果服务器启动后没有任何工具注册,可能是工作目录设置不正确。在 verbose 模式下,服务器会输出检测到的工作目录信息,确保该目录包含有效的 package.json 文件。
关于包管理器选择,如果服务器选择了错误的包管理器,可以通过 --pm 参数显式指定正确的包管理器,或者在配置文件中使用 packageManager 字段声明项目使用的包管理器。
下一步
完成基本配置后,可以进一步探索高级配置选项,例如为特定脚本定义详细的描述和输入模式。也可以查看项目的 GitHub 仓库获取最新版本和更新日志。版本 v0.2.13 是当前的稳定版本,包含了对 qs 和 express 依赖的安全更新。
来源:https://github.com/fstubner/npm-run-mcp-server / 项目说明书
安装与环境
npm-run-mcp-server 是一个基于 Model Context Protocol (MCP) 的服务器,用于将项目 package.json 中的脚本暴露给 AI 助手。该工具的核心价值在于零配置开箱即用,同时支持高度定制化的安装和环境配置方案。
继续阅读本节完整说明和来源证据。
概述
npm-run-mcp-server 是一个基于 Model Context Protocol (MCP) 的服务器,用于将项目 package.json 中的脚本暴露给 AI 助手。该工具的核心价值在于零配置开箱即用,同时支持高度定制化的安装和环境配置方案。
本页面详细介绍该工具的系统要求、安装方式、CLI 参数配置以及各种 AI 客户端(Claude Desktop、Cursor、VS Code)的集成方法。
来源:https://github.com/fstubner/npm-run-mcp-server / 项目说明书
配置文件指南
npm-run-mcp-server 提供灵活的配置系统,允许你控制哪些 package.json 脚本暴露给 AI 助手,以及如何呈现这些脚本。通过配置文件,你可以实现脚本白名单/黑名单管理、自定义工具名称、详细描述和参数模式定义。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
快速入门
配置文件位置
服务器按以下优先级查找配置文件:
- CLI 参数指定:
--config <path> - 项目根目录:
npm-run-mcp.config.json - 项目根目录(备选):
.npm-run-mcp.json
graph TD
A[启动服务器] --> B{指定 --config 参数?}
B -->|是| C[使用指定路径]
B -->|否| D{查找 npm-run-mcp.config.json}
D -->|存在| E[使用该文件]
D -->|不存在| F{查找 .npm-run-mcp.json}
F -->|存在| G[使用该文件]
F -->|不存在| H[使用默认配置<br/>暴露所有脚本]
C --> I[解析配置并注册工具]
E --> I
G --> I
H --> I基础示例
在项目根目录创建 npm-run-mcp.config.json:
{
"include": ["test", "lint", "build", "start"],
"exclude": ["eject", "publish"],
"scripts": {
"test": {
"description": "运行测试套件。使用 --watch 启用监视模式。",
"inputSchema": {
"properties": {
"watch": {
"type": "boolean",
"description": "监视文件变化"
}
}
}
}
}
}
配置选项详解
顶层配置项
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
include | string[] | 否 | 白名单脚本名称数组,仅暴露列表中的脚本 |
exclude | string[] | 否 | 黑名单脚本名称数组,隐藏列表中的脚本 |
scripts | object | 否 | 针对特定脚本的详细配置 |
配置生效逻辑:
graph LR
A[所有 package.json<br/>脚本] --> B{在 include 中?}
B -->|否且有include| C[排除]
B -->|是| D{在 exclude 中?}
D -->|是| C
D -->|否| E[暴露为MCP工具]include 和 exclude 规则
- 当
include未指定时,默认暴露所有脚本(受exclude限制) - 当
exclude未指定时,默认不排除任何脚本 include和exclude可同时使用:include优先筛选,再由exclude排除
{
"include": ["dev", "build", "test"],
"exclude": ["build:prod"]
}
此配置仅暴露 dev、build 和 test 脚本,即使 package.json 中存在 build:prod 也会被排除。
脚本级配置 (scripts)
每个脚本名称可映射到一个配置对象:
{
"scripts": {
"<脚本名称>": {
"toolName": "自定义工具名",
"description": "自定义描述文本",
"argsDescription": "args 参数的描述",
"inputSchema": { /* JSON Schema 对象 */ }
}
}
}
| 字段 | 类型 | 说明 |
|---|---|---|
toolName | string | 覆盖 AI 看到的工具名称(默认由脚本名 sanitize 而来) |
description | string | 自定义工具描述,帮助 AI 理解何时使用 |
argsDescription | string | args 输入字段的描述文本 |
inputSchema | object | JSON Schema 定义的额外参数,会转换为 CLI 标志 |
inputSchema 高级用法
概念
inputSchema 使用 JSON Schema 定义工具输入参数。配置中的 keys 会被转换为 CLI 标志传递给脚本。
{
"scripts": {
"build": {
"description": "构建生产版本",
"inputSchema": {
"type": "object",
"properties": {
"watch": {
"type": "boolean",
"description": "启用监视模式"
},
"target": {
"type": "string",
"description": "构建目标环境"
},
"analyze": {
"type": "boolean",
"description": "生成打包分析报告"
}
}
}
}
}
}
支持的 JSON Schema 类型
| Schema type | Zod 类型 | 说明 |
|---|---|---|
string | z.string() | 字符串参数 |
boolean | z.boolean() | 布尔标志(--flag) |
number | z.number() | 数字参数 |
integer | z.number().int() | 整数参数 |
array | z.array() | 数组参数 |
object | z.object() | 嵌套对象 |
enum | z.union([z.literal(...)]) | 枚举值 |
布尔类型自动处理
布尔参数会智能转换为 CLI 标志:
{
"properties": {
"watch": {
"type": "boolean",
"description": "Watch mode"
}
}
}
watch: true→--watchwatch: false→ 不传递任何参数
对象和数组类型
{
"properties": {
"tags": {
"type": "array",
"items": { "type": "string" },
"description": "过滤标签"
},
"options": {
"type": "object",
"description": "额外选项",
"properties": {
"verbose": { "type": "boolean" },
"level": { "type": "string" }
}
}
}
}
必填字段
使用 required 数组指定必填字段:
{
"inputSchema": {
"type": "object",
"properties": {
"env": { "type": "string", "description": "环境名称" }
},
"required": ["env"]
}
}
JSONC 支持
配置文件支持 JSONC 格式,即带有注释和尾随逗号的 JSON:
{
// 开发环境相关脚本
"include": ["dev", "build", "test"],
"scripts": {
"dev": {
"description": "启动开发服务器"
// 可添加更多注释
},
}
}
服务器使用 jsonc-parser 库解析配置,支持:
- 单行注释:
// comment - 多行注释:
/* comment */ - 尾随逗号:列表最后一项后的逗号
资料来源:src/index.ts:parseJsonOrJsonc 函数
CLI 配置覆盖
使用 --config 参数指定配置文件路径:
npx npm-run-mcp-server --config ./configs/mcp-dev.json
npx npm-run-mcp-server --config /absolute/path/to/config.json
如果指定的文件不存在,服务器会报错并退出:
npm-run-mcp-server: Config file not found: /path/to/config.json
完整配置示例
{
"include": [
"dev",
"build",
"test",
"lint",
"typecheck"
],
"exclude": [
"postinstall",
"prepublishOnly",
"deploy"
],
"scripts": {
"dev": {
"toolName": "start_development_server",
"description": "启动 Vite 开发服务器,带热模块替换",
"inputSchema": {
"type": "object",
"properties": {
"port": {
"type": "number",
"description": "开发服务器端口"
},
"open": {
"type": "boolean",
"description": "启动后自动打开浏览器"
}
}
}
},
"build": {
"description": "构建生产环境资源",
"argsDescription": "传递给构建命令的额外参数",
"inputSchema": {
"type": "object",
"properties": {
"watch": {
"type": "boolean",
"description": "监视文件变化"
},
"analyze": {
"type": "boolean",
"description": "生成打包分析"
}
}
}
},
"test": {
"description": "运行 Vitest 测试",
"inputSchema": {
"type": "object",
"properties": {
"watch": {
"type": "boolean",
"description": "监视模式"
},
"coverage": {
"type": "boolean",
"description": "生成覆盖率报告"
},
"grep": {
"type": "string",
"description": "只运行匹配测试"
}
}
}
}
}
}
JSON Schema 验证
项目发布了正式的 JSON Schema 用于配置验证:npm-run-mcp.config.schema.json
获取 Schema
# 从项目获取
curl -O https://raw.githubusercontent.com/fstubner/npm-run-mcp-server/main/npm-run-mcp.config.schema.json
# 或在编辑器中引用
# VS Code、JetBrains 等支持 $schema 引用自动补全
在配置文件中引用 Schema
{
"$schema": "./node_modules/npm-run-mcp-server/npm-run-mcp.config.schema.json",
"include": ["test", "lint"]
}
Schema 字段一览
| 字段 | 类型 | 描述 |
|---|---|---|
include | string[] | 要包含的脚本名称 |
exclude | string[] | 要排除的脚本名称 |
scripts | object | 脚本配置映射 |
scripts[].toolName | string | 工具名称覆盖 |
scripts[].description | string | 工具描述覆盖 |
scripts[].argsDescription | string | args 字段描述 |
scripts[].inputSchema | object | JSON Schema 格式的参数定义 |
常见使用场景
场景一:限制危险命令
防止 AI 执行发布或部署命令:
{
"exclude": ["publish", "deploy", "release", "eject"]
}
场景二:限制特定环境构建
{
"include": ["dev", "build", "test", "lint"],
"exclude": ["build:docker", "deploy:staging", "deploy:production"]
}
场景三:标准化开发工作流
{
"include": ["dev", "build", "test", "lint", "typecheck"],
"scripts": {
"dev": {
"description": "启动本地开发服务器",
"inputSchema": {
"properties": {
"port": { "type": "number", "description": "服务器端口" }
}
}
},
"test": {
"description": "运行测试(可选:watch 模式)",
"inputSchema": {
"properties": {
"watch": { "type": "boolean", "description": "监视模式" },
"coverage": { "type": "boolean", "description": "生成覆盖率" }
}
}
}
}
}
场景四:多环境配置
在不同目录放置不同配置文件:
project/
├── npm-run-mcp.config.json # 基础配置
├── configs/
│ ├── mcp-dev.json # 开发配置
│ ├── mcp-ci.json # CI 配置
│ └── mcp-limited.json # 受限配置
通过 CLI 参数切换:
# 开发环境
npm-run-mcp-server --config configs/mcp-dev.json
# CI 环境
npm-run-mcp-server --config configs/mcp-ci.json
调试配置
启用详细日志查看配置加载过程:
npm-run-mcp-server --verbose
输出示例:
[mcp] server starting: cwd=/path/to/project
[mcp] using package.json: /path/to/project/package.json
[mcp] loaded server info: [email protected]
[mcp] detected package manager: npm
[mcp] using config file: /path/to/project/npm-run-mcp.config.json
[mcp] include list references missing scripts: old_script, deprecated_build
版本历史
| 版本 | 更新内容 |
|---|---|
| v0.2.10 | 新增配置文件支持、--config 参数、JSONC 解析、发布 JSON Schema |
| v0.2.13 | 依赖版本更新(qs, express) |
相关资源
资料来源:src/index.ts:parseJsonOrJsonc 函数
输入模式与脚本参数
npm-run-mcp-server 提供了灵活且强大的输入模式(Input Schema)系统,允许 AI 代理通过类型安全的接口向 package.json 脚本传递参数。该系统基于 JSON Schema 标准构建,通过 Zod 库实现运行时验证,确保 AI 生成的参数符合脚本预期的格式要求。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
概述
npm-run-mcp-server 提供了灵活且强大的输入模式(Input Schema)系统,允许 AI 代理通过类型安全的接口向 package.json 脚本传递参数。该系统基于 JSON Schema 标准构建,通过 Zod 库实现运行时验证,确保 AI 生成的参数符合脚本预期的格式要求。
核心设计目标
本系统的设计遵循以下原则:
- 类型安全 - 通过 JSON Schema 定义参数结构,Zod 在运行时进行验证
- 向后兼容 - 基础参数
_和args始终可用 - 灵活扩展 - 支持自定义输入字段,映射为 CLI 标志位
- 容错处理 - 解析失败时提供清晰的错误信息
来源:https://github.com/fstubner/npm-run-mcp-server / 项目说明书
命令行界面
npm-run-mcp-server 提供了一套完整的命令行界面(CLI),允许用户通过命令行参数控制 MCP 服务器的行为,包括工作目录指定、包管理器选择、配置文件加载和调试模式等核心功能。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
概述
该工具是 Model Context Protocol (MCP) 的服务器实现,专门将项目 package.json 中的 npm scripts 暴露为 MCP 工具供 AI Agent 使用。CLI 层负责环境检测、参数解析和运行时初始化,是整个系统的入口点。
核心功能定位
| 功能 | 说明 |
|---|---|
| 工作目录检测 | 自动定位 package.json 或手动指定 |
| 包管理器识别 | 支持 npm、pnpm、yarn、bun 四种主流工具 |
| 配置管理 | 支持 JSONC 格式的本地配置文件 |
| 调试支持 | 详细的运行时日志输出 |
CLI 参数参考
基础参数
| 参数 | 类型 | 说明 | |||
|---|---|---|---|---|---|
--cwd <path> | string | 手动设置工作目录路径 | |||
--pm <manager> | npm \ | pnpm \ | yarn \ | bun | 强制使用指定的包管理器 |
--config <path> | string | 指定配置文件路径 | |||
--verbose | flag | 启用详细调试日志 | |||
--list-scripts | flag | 仅列出可用脚本并退出 |
资料来源:src/index.ts:1-300
环境变量
CLI 支持通过环境变量进行配置,这些变量通常由 IDE 集成时自动设置:
| 环境变量 | 说明 |
|---|---|
MCP_VERBOSE | 启用详细日志输出 |
DEBUG | 包含 'mcp' 子串时启用日志 |
WORKSPACE_FOLDER_PATHS | Cursor IDE 多工作区路径(分号分隔) |
VSCODE_WORKSPACE_FOLDER | VS Code 工作区文件夹路径 |
CURSOR_WORKSPACE_FOLDER | Cursor 工作区文件夹路径 |
资料来源:src/index.ts:58-75
工作目录检测逻辑
服务器启动时按优先级依次检测工作目录:
graph TD
A[启动] --> B{--cwd 参数?}
B -->|是| C[使用 --cwd 值]
B -->|否| D{WORKSPACE_FOLDER_PATHS?}
D -->|是| E[取第一个路径<br/>处理 Windows→WSL 转换]
D -->|否| F{VSCODE_WORKSPACE_FOLDER?}
F -->|是| G[使用该路径]
F -->|否| H{CURSOR_WORKSPACE_FOLDER?}
H -->|是| I[使用该路径]
H -->|否| J[使用 cwd<br/>向上查找 package.json]
C --> K[查找 package.json]
E --> K
G --> K
I --> K
J --> KWindows 到 WSL 路径转换
当检测到运行在 Linux 环境且收到 Windows 格式路径时,系统会自动进行转换:
// 输入: H:\path\to\project (Windows)
// 输出: /mnt/h/path/to/project (WSL)
const drive = workspacePath[0].toLowerCase();
const path = workspacePath.slice(3).replace(/\\/g, '/');
workspacePath = `/mnt/${drive}${path}`;
资料来源:src/index.ts:82-87
包管理器检测
系统支持自动检测和手动覆盖两种方式来确定使用哪个包管理器:
graph TD
A[检测包管理器] --> B{--pm 参数?}
B -->|是| C[返回指定值]
B -->|否| D{package.json<br/>packageManager 字段?}
D -->|有| E[解析并返回<br/>npm/pnpm/yarn/bun]
D -->|无| F{lock 文件检测}
F -->|pnpm-lock.yaml| G[返回 pnpm]
F -->|yarn.lock| H[返回 yarn]
F -->|bun.lock/bun.lockb| I[返回 bun]
F -->|无| J[返回 npm]检测优先级
| 优先级 | 来源 | 说明 |
|---|---|---|
| 1 | --pm 参数 | 手动指定,优先级最高 |
| 2 | package.json.packageManager | packageManager 字段 |
| 3 | lock 文件 | 按类型检测 |
| 4 | 默认值 | 返回 npm |
资料来源:src/index.ts:120-135
配置文件系统
配置文件位置
服务器按以下顺序查找配置文件:
--config参数指定的路径npm-run-mcp.config.json.npm-run-mcp.json
配置文件结构
{
"include": ["test", "lint", "build"],
"exclude": ["eject", "publish"],
"scripts": {
"test": {
"toolName": "run_tests",
"description": "运行测试套件",
"argsDescription": "传递给测试的参数",
"inputSchema": {
"properties": {
"watch": { "type": "boolean" }
}
}
}
}
}
配置选项说明
| 字段 | 类型 | 说明 |
|---|---|---|
include | string[] | 白名单,仅暴露指定的脚本 |
exclude | string[] | 黑名单,排除指定的脚本 |
scripts | object | 各脚本的详细配置 |
资料来源:npm-run-mcp.config.schema.json
JSONC 支持
配置文件支持 JSONC 格式,允许使用 JavaScript 风格注释和尾部逗号:
{
// 这是一条注释
"include": ["test", "build", /* 内联注释 */ "lint"],
}
使用方式
直接运行
# 列出所有可用脚本
npx npm-run-mcp-server --list-scripts
# 指定工作目录
npx npm-run-mcp-server --cwd /path/to/project
# 强制使用 pnpm
npx npm-run-mcp-server --pm pnpm
# 指定配置文件
npx npm-run-mcp-server --config ./custom-config.json
# 启用调试输出
npx npm-run-mcp-server --verbose
本地开发
# 构建项目
npm run build
# 运行服务器
npm start
# 运行集成测试
npm run test:integration
MCP 协议启动
标准 MCP 通信通过 Stdio 传输层:
# 由 MCP Client 启动
npx npm-run-mcp-server
# 服务器通过 stdin/stdout 与客户端通信
资料来源:package.json:12-20
调试模式
启用方式
- 命令行参数:
--verbose - 环境变量:
MCP_VERBOSE=1 - DEBUG 环境变量包含 'mcp'
调试输出内容
启用后会输出以下信息:
[mcp] server starting: cwd=/path/to/project
[mcp] detected workspace: /path/to/project
[mcp] using package.json: /path/to/project/package.json
[mcp] detected package manager: pnpm
[mcp] loaded server info: [email protected]
资料来源:src/index.ts:60-73
常见问题
工作目录找不到 package.json
症状:服务器启动但没有暴露任何工具
排查步骤:
- 确认项目目录存在
package.json - 使用
--cwd参数显式指定路径 - 确认工作目录有读取权限
- 启用
--verbose查看检测路径
包管理器检测错误
症状:使用了错误的包管理器执行脚本
解决方案:使用 --pm 参数强制指定
npx npm-run-mcp-server --pm yarn
配置文件不生效
排查清单:
- 确认文件名正确:
npm-run-mcp.config.json或.npm-run-mcp.json - 检查 JSON 语法有效性
- 确认文件在工作目录根目录
- 使用
--verbose确认配置被加载
NPM 发布失败
社区反馈:NPM 发布工作流因 token 过期/撤销而失败。需在 GitHub Secrets 中轮换 NPM token。
技术架构
入口流程
sequenceDiagram
participant User
participant CLI as 命令行解析
participant Detector as 环境检测
participant Config as 配置加载
participant Server as MCP 服务器
User->>CLI: npm-run-mcp-server --cwd /path
CLI->>CLI: 解析参数和环境变量
CLI->>Detector: 检测工作目录
Detector-->>CLI: 返回项目路径
CLI->>Config: 加载 MCP 配置
Config-->>CLI: 返回过滤规则
CLI->>Server: 初始化 MCP 服务器
Server->>Server: 注册 npm scripts 为工具
Server-->>User: MCP Stdio 连接就绪依赖关系
| 模块 | 用途 |
|---|---|
@modelcontextprotocol/sdk | MCP 协议实现 |
cross-spawn | 跨平台脚本执行 |
jsonc-parser | JSONC 配置解析 |
zod | 输入验证 |
资料来源:package.json:25-30
版本历史
| 版本 | CLI 变更 |
|---|---|
| v0.2.10 | 新增 --config 参数和 JSONC 支持 |
| v0.2.13 | 依赖更新(qs, express) |
| v0.1.0 | 初始版本,包含基础 CLI 功能 |
相关发布说明请参阅 GitHub Releases。
资料来源:src/index.ts:1-300
系统架构
npm-run-mcp-server 是一个基于 Model Context Protocol (MCP) 的服务器实现,其核心功能是将项目中的 package.json 脚本转换为 AI Agent 可调用的 MCP 工具。该项目采用单入口架构,所有核心逻辑集中在 src/index.ts 中,通过 MCP SDK 与 AI 客户端(如 Claude Desktop、Cu...
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
概述
npm-run-mcp-server 是一个基于 Model Context Protocol (MCP) 的服务器实现,其核心功能是将项目中的 package.json 脚本转换为 AI Agent 可调用的 MCP 工具。该项目采用单入口架构,所有核心逻辑集中在 src/index.ts 中,通过 MCP SDK 与 AI 客户端(如 Claude Desktop、Cursor、VS Code)进行标准输入输出(stdio)通信。
主要技术栈:
- 运行时: Node.js (>=18.18.0),ESM 模块系统
- MCP 通信:
@modelcontextprotocol/sdkv1.25.1 - 配置解析:
jsonc-parser(支持 JSONC 注释和尾随逗号) - 数据验证:
zodv3.23.8 - 跨平台执行:
cross-spawnv7.0.5
资料来源:package.json:1-40
核心组件架构
graph TD
subgraph "启动层"
A["CLI 参数解析"] --> B["工作目录检测"]
B --> C["环境变量检测"]
end
subgraph "检测层"
C --> D["package.json 读取"]
D --> E["包管理器检测"]
E --> F["MCP 配置读取"]
end
subgraph "转换层"
F --> G["脚本名称规范化"]
G --> H["工具元数据生成"]
H --> I["Zod Schema 构建"]
end
subgraph "服务层"
I --> J["MCP Server 初始化"]
J --> K["StdioServerTransport"]
K --> L["工具注册"]
end
subgraph "执行层"
L --> M["MCP 工具调用"]
M --> N["进程 Spawn"]
N --> O["输出捕获与截断"]
end启动与初始化流程
工作目录检测策略
服务器启动时按以下优先级确定工作目录:
- CLI 参数:
--cwd显式指定的路径 - 环境变量:
WORKSPACE_FOLDER_PATHS(Cursor 设置,分号分隔) - IDE 环境变量:
VSCODE_WORKSPACE_FOLDER或CURSOR_WORKSPACE_FOLDER - 当前目录回退: 向上遍历查找包含
package.json的目录
let startCwd: string = process.cwd();
if (args.cwd) {
startCwd = resolve(String(args.cwd));
} else if (process.env.WORKSPACE_FOLDER_PATHS) {
const workspacePaths = process.env.WORKSPACE_FOLDER_PATHS.split(';');
startCwd = workspacePaths[0];
} else if (process.env.VSCODE_WORKSPACE_FOLDER) {
startCwd = process.env.VSCODE_WORKSPACE_FOLDER;
} else if (process.env.CURSOR_WORKSPACE_FOLDER) {
startCwd = process.env.CURSOR_WORKSPACE_FOLDER;
}
资料来源:src/index.ts:89-110
WSL 路径转换
当检测到在 WSL 环境下运行且接收到 Windows 格式路径时,自动转换为 WSL 路径格式:
if (process.platform === 'linux' && workspacePath.match(/^[A-Za-z]:\\/)) {
const drive = workspacePath[0].toLowerCase();
const path = workspacePath.slice(3).replace(/\\/g, '/');
workspacePath = `/mnt/${drive}${path}`;
}
资料来源:src/index.ts:95-99
包管理器检测机制
服务器支持 npm、pnpm、yarn、bun 四种包管理器,检测顺序如下:
graph TD
A["开始检测"] --> B{"--pm 参数指定?"}
B -->|是| Z["使用指定包管理器"]
B -->|否| C{"packageManager 字段?"}
C -->|是| D{"有效值?"}
D -->|npm/pnpm/yarn/bun| Z
D -->|否| E{"lockfile 存在?"}
C -->|否| E
E --> F["pnpm-lock.yaml?"]
F -->|是| G["pnpm"]
F -->|否| H["yarn.lock?"]
H -->|是| I["yarn"]
H -->|否| J["bun.lockb/bun.lock?"]
J -->|是| K["bun"]
J -->|否| L["默认 npm"]
G --> Z
I --> Z
K --> Z
L --> Z检测函数实现
function detectPackageManager(
projectDir: string,
pkg: PackageJson,
override?: PackageManager
): PackageManager {
if (override) return override;
// 优先使用 packageManager 字段
if (pkg.packageManager) {
const pm = pkg.packageManager.split('@')[0] as PackageManager;
if (pm === 'npm' || pm === 'pnpm' || pm === 'yarn' || pm === 'bun')
return pm;
}
// 基于 lockfile 检测
if (existsSync(resolve(projectDir, 'pnpm-lock.yaml'))) return 'pnpm';
if (existsSync(resolve(projectDir, 'yarn.lock'))) return 'yarn';
if (existsSync(resolve(projectDir, 'bun.lockb')) ||
existsSync(resolve(projectDir, 'bun.lock'))) return 'bun';
return 'npm';
}
资料来源:src/index.ts:131-151
配置系统
配置文件位置
按以下顺序查找配置文件:
--configCLI 参数指定的路径- 项目根目录的
npm-run-mcp.config.json - 项目根目录的
.npm-run-mcp.json
配置采用 JSONC 格式,支持注释和尾随逗号。
资料来源:npm-run-mcp.config.schema.json:1-10
配置 Schema
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "npm-run-mcp-server config",
"type": "object",
"additionalProperties": false,
"properties": {
"include": {
"type": "array",
"items": { "type": "string" },
"description": "精确包含的脚本名称列表"
},
"exclude": {
"type": "array",
"items": { "type": "string" },
"description": "精确排除的脚本名称列表"
},
"scripts": {
"type": "object",
"description": "每个脚本的元数据覆盖配置"
}
}
}
资料来源:npm-run-mcp.config.schema.json:11-40
脚本过滤逻辑
graph TD
A["所有脚本名称"] --> B{"include 存在?"}
B -->|是| C["只保留 include 中的脚本"]
B -->|否| D{"exclude 存在?"}
D -->|是| E["移除 exclude 中的脚本"]
D -->|否| F["返回所有脚本"]
C --> F
E --> FMCP 工具生成
工具名称规范化
脚本名称经过以下转换规则:
- 转小写
- 非字母数字字符替换为下划线
- 空名称回退为
script
function sanitizeToolName(name: string): string {
const normalized = name.toLowerCase().replace(/[^a-z0-9_-]/g, '_');
return normalized.length > 0 ? normalized : 'script';
}
资料来源:src/index.ts:175-178
输入 Schema 构建
每个 MCP 工具的输入包含两个内置字段:
| 字段 | 类型 | 描述 | |
|---|---|---|---|
_ | string[] | 额外参数数组 | |
args | `string \ | string[]` | 追加在 -- 之后的参数 |
额外配置字段可通过 inputSchema 定义,JSON Schema 类型到 Zod 的转换支持:
| JSON Schema 类型 | Zod 类型 |
|---|---|
string | z.string() |
boolean | z.boolean() |
number | z.number() |
integer | z.number().int() |
array (string items) | z.array(z.string()) |
object | z.object() |
资料来源:src/index.ts:180-230
进程执行与输出处理
命令构建
function buildRunCommand(
pm: PackageManager,
scriptName: string,
extraArgs: string[]
): { command: string; args: string[] } {
const command = pm;
const baseArgs = ['run', scriptName];
const args = extraArgs.length > 0
? [...baseArgs, '--', ...extraArgs]
: baseArgs;
return { command, args };
}
资料来源:src/index.ts:154-163
输出截断机制
| 配置项 | 默认值 | 说明 |
|---|---|---|
outputCaptureLimit | 120000 | 单次捕获上限(字节) |
trimOutput.limit | 12000 | 返回给客户端的截断限制 |
当输出超过限制时,会返回前 12000 字符并附加截断提示。
function trimOutput(out: string, limit = 12000, totalLength?: number): {
text: string;
truncated: boolean
} {
const total = typeof totalLength === 'number' ? totalLength : out.length;
if (total <= limit) return { text: out, truncated: false };
return {
text: out.slice(0, limit) + `\n...[truncated ${total - limit} chars]`,
truncated: true
};
}
资料来源:src/index.ts:248-254
超时控制
| 配置项 | 默认值 |
|---|---|
DEFAULT_TIMEOUT_MS | 5 分钟(300000ms) |
MCP 协议集成
服务器注册
const server = new McpServer({
name: serverName,
version: serverVersion
});
使用 StdioServerTransport 建立连接:
const transport = new StdioServerTransport();
await server.connect(transport);
工具注册流程
sequenceDiagram
participant Client as MCP Client
participant Server as npm-run-mcp-server
participant Package as package.json
participant Config as npm-run-mcp.config.json
Server->>Package: 读取 scripts
Server->>Config: 读取 MCP 配置
Server->>Server: 过滤脚本名称
Server->>Server: 规范化工具名称
Server->>Server: 构建 Zod Schema
Server->>Server: 注册 MCP Tools
Server->>Client: 连接 stdio transport
Client->>Server: 工具调用请求
Server->>Server: 执行 spawn 进程
Server->>Client: 返回执行结果工具调用处理
当 AI 客户端调用工具时:
- 解析输入参数
- 根据参数类型生成 CLI flags
- 构建执行命令
- Spawn 子进程
- 捕获 stdout/stderr
- 处理超时
- 返回结构化结果
依赖关系图
@modelcontextprotocol/sdk (MCP SDK)
├── 协议通信
└── 类型定义
cross-spawn
└── 跨平台进程执行
jsonc-parser
└── JSONC 配置解析
zod
└── Schema 验证与转换
资料来源:package.json:18-21
错误处理与边界情况
无 package.json 场景
当未找到 package.json 时,服务器启动但不注册任何工具,仅等待 stdio 连接请求。
if (!projectDir || !projectPkg) {
const transport = new StdioServerTransport();
await server.connect(transport);
return;
}
资料来源:src/index.ts:118-127
空脚本列表
if (scriptNames.length === 0) {
console.error(`npm-run-mcp-server: No scripts found in ${pkgJsonPath}`);
}
过滤后无有效脚本
if (filteredScriptNames.length === 0) {
const hint = mcpConfig.include?.length
? 'Check your config "include"/"exclude" settings.'
: 'Check your package.json "scripts" section.';
console.error(`npm-run-mcp-server: No scripts selected for exposure. ${hint}`);
}
调试支持
Verbose 模式
通过以下任一方式启用:
- CLI 参数:
--verbose - 环境变量:
MCP_VERBOSE=1 - 环境变量:
DEBUG=mcp(需包含 "mcp" 字符串)
调试输出内容
| 信息 | 条件 |
|---|---|
cwd | 启动时 |
workspace | 环境变量检测 |
package.json 路径 | 文件存在时 |
server info | verbose 模式 |
package manager | 检测完成后 |
include 列表中的缺失脚本 | 配置了 include 时 |
关键文件清单
| 文件路径 | 用途 |
|---|---|
src/index.ts | 主入口,包含所有核心逻辑 |
package.json | 项目配置与依赖声明 |
npm-run-mcp.config.schema.json | 配置文件 JSON Schema |
server.json | MCP Registry 注册信息 |
README.md | 用户文档 |
scripts/build.cjs | 构建脚本 |
scripts/integration-test.mjs | 集成测试 |
资料来源:package.json:1-40
包管理器检测
包管理器检测是 npm-run-mcp-server 的核心功能之一,负责自动识别项目所使用的 Node.js 包管理器。该模块确保服务器能够使用正确的包管理器命令(如 npm、pnpm、yarn 或 bun)来执行 package.json 中定义的脚本。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
功能概述
包管理器检测是 npm-run-mcp-server 的核心功能之一,负责自动识别项目所使用的 Node.js 包管理器。该模块确保服务器能够使用正确的包管理器命令(如 npm、pnpm、yarn 或 bun)来执行 package.json 中定义的脚本。
支持自动检测四种主流包管理器:npm、pnpm、yarn 和 bun。
检测逻辑
优先级策略
包管理器检测采用三级优先级策略,从高到低依次为:
- 命令行参数覆盖 - 优先级最高,允许用户强制指定特定包管理器
- package.json 显式声明 - 检测
packageManager字段 - Lockfile 启发式检测 - 通过检测 lockfile 文件推断包管理器
- 默认回退 - 若以上均无法确定,返回
npm作为默认值
function detectPackageManager(projectDir: string, pkg: PackageJson, override?: PackageManager): PackageManager {
if (override) return override;
if (pkg.packageManager) {
const pm = pkg.packageManager.split('@')[0] as PackageManager;
if (pm === 'npm' || pm === 'pnpm' || pm === 'yarn' || pm === 'bun') return pm;
}
if (existsSync(resolve(projectDir, 'pnpm-lock.yaml'))) return 'pnpm';
if (existsSync(resolve(projectDir, 'yarn.lock'))) return 'yarn';
if (existsSync(resolve(projectDir, 'bun.lockb')) || existsSync(resolve(projectDir, 'bun.lock'))) return 'bun';
return 'npm';
}
资料来源:src/index.ts
检测流程图
graph TD
A[开始检测] --> B{是否有 --pm 参数?}
B -->|是| C[使用命令行指定值]
B -->|否| D{package.json 是否有 packageManager 字段?}
D -->|是| E{字段值是否有效?}
D -->|否| F{是否存在 pnpm-lock.yaml?}
E -->|npm/pnpm/yarn/bun| G[使用 packageManager 值]
E -->|其他| F
F -->|是| H[使用 pnpm]
F -->|否| I{是否存在 yarn.lock?}
I -->|是| J[使用 yarn]
I -->|否| K{是否存在 bun.lockb 或 bun.lock?}
K -->|是| L[使用 bun]
K -->|否| M[使用 npm 默认值]
C --> N[返回包管理器]
G --> N
H --> N
J --> N
L --> N
M --> N支持的包管理器
| 包管理器 | 标识符 | Lockfile 检测 | packageManager 前缀 |
|---|---|---|---|
| npm | npm | 无 | [email protected] |
| pnpm | pnpm | pnpm-lock.yaml | [email protected] |
| yarn | yarn | yarn.lock | [email protected] |
| bun | bun | bun.lockb / bun.lock | [email protected] |
使用方式
CLI 参数指定
通过 --pm 参数强制指定包管理器:
npx npm-run-mcp-server --pm pnpm
npx npm-run-mcp-server --pm yarn
npx npm-run-mcp-server --pm bun
packageManager 字段
在项目 package.json 中声明使用的包管理器:
{
"packageManager": "[email protected]"
}
服务器会自动提取 @ 前的包管理器名称。
自动检测
服务器启动时自动执行检测,无需额外配置。检测结果会输出到 stderr(当启用 verbose 模式时):
npx npm-run-mcp-server --verbose
# 输出: [mcp] detected package manager: pnpm
构建运行命令
检测到包管理器后,buildRunCommand 函数负责构建实际的执行命令:
function buildRunCommand(
pm: PackageManager,
scriptName: string,
extraArgs: string[]
): { command: string; args: string[] } {
const command = pm;
const baseArgs = ['run', scriptName];
const args = extraArgs.length > 0 ? [...baseArgs, '--', ...extraArgs] : baseArgs;
return { command, args };
}
| 参数 | 类型 | 说明 |
|---|---|---|
pm | PackageManager | 检测到的包管理器 |
scriptName | string | 要执行的脚本名称 |
extraArgs | string[] | 额外参数 |
返回的 command 和 args 直接用于 spawn 调用执行脚本。
已知问题
根据社区反馈,NPM 发布工作流曾因 NPM token 过期/撤销而失败,建议用户在实际使用中注意 token 有效期管理。
资料来源:src/index.ts
工具注册机制
npm-run-mcp-server 的核心功能是将 package.json 中定义的 npm scripts 自动转换为 MCP (Model Context Protocol) 工具,使 AI 代理能够直接调用项目脚本。工具注册机制负责将脚本转换为符合 MCP 协议的工具定义,包括输入参数验证、名称规范化、配置过滤等关键步骤。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
概述
npm-run-mcp-server 的核心功能是将 package.json 中定义的 npm scripts 自动转换为 MCP (Model Context Protocol) 工具,使 AI 代理能够直接调用项目脚本。工具注册机制负责将脚本转换为符合 MCP 协议的工具定义,包括输入参数验证、名称规范化、配置过滤等关键步骤。
工具注册流程始于服务器启动阶段,在读取项目 package.json 后,系统会根据配置文件(npm-run-mcp.config.json 或 .npm-run-mcp.json)过滤可暴露的脚本,然后为每个符合条件的脚本生成 MCP 工具定义。 资料来源:src/index.ts:1-200
核心流程
graph TD
A[读取 package.json] --> B[读取 MCP 配置文件]
B --> C[过滤脚本名称]
C --> D[生成工具名称映射]
D --> E[构建输入 Schema]
E --> F[注册 MCP 工具]
F --> G[等待工具调用]脚本名称规范化
sanitizeScriptName 函数
脚本名称需转换为符合 MCP 工具命名规范的标识符。sanitizeScriptName 函数负责此转换:
function sanitizeScriptName(name: string): string {
const normalized = name.toLowerCase().replace(/[^a-z0-9_-]/g, '_');
return normalized.length > 0 ? normalized : 'script';
}
转换规则:
| 输入示例 | 输出结果 | 说明 |
|---|---|---|
test:unit | test_unit | 冒号替换为下划线 |
build:prod | build_prod | 保留下划线和连字符 |
lint-fix | lint_fix | 连字符替换为下划线 |
clean | clean | 纯字母保持不变 |
@scope/pkg | _scope_pkg | 非法字符替换 |
该函数确保所有生成的工具名称仅包含小写字母、数字、下划线和连字符,同时处理空名称的边界情况。 资料来源:src/index.ts:120-123
配置过滤机制
filterScriptNames 函数
在注册工具前,系统根据用户配置决定哪些脚本应被暴露:
function filterScriptNames(
scriptNames: string[],
mcpConfig: McpConfig
): string[] {
let filtered = scriptNames;
if (mcpConfig.include && mcpConfig.include.length > 0) {
filtered = filtered.filter((name) => mcpConfig.include!.includes(name));
}
if (mcpConfig.exclude && mcpConfig.exclude.length > 0) {
filtered = filtered.filter((name) => !mcpConfig.exclude!.includes(name));
}
return filtered;
}
过滤优先级:
- include 优先:如果配置了
include数组,仅暴露列表中的脚本 - exclude 次之:在 include 结果基础上排除指定脚本
- 无配置时:暴露所有脚本
过滤逻辑确保配置冲突时,include 白名单优先于 exclude 黑名单,这在企业项目中用于限制敏感脚本(如 publish、eject)的访问尤为重要。 资料来源:src/index.ts:200-215
工具名称映射
系统维护一个 toolNameToScripts 映射表,处理脚本名称转换后的冲突问题:
const toolNameToScripts = new Map<string, string[]>();
for (const scriptName of filteredScriptNames) {
const overrideName = mcpConfig.scripts?.[scriptName]?.toolName;
const toolName = overrideName ?? sanitizeScriptName(scriptName);
// 处理同名冲突
}
冲突处理机制:
当多个脚本经过规范化后产生相同工具名称时,系统通过 toolNameToScripts 映射记录所有原始脚本。这确保了每个工具调用能准确定位到对应的脚本命令。
用户可通过配置文件的 scripts[scriptName].toolName 字段自定义工具名称,避免自动生成的名称不符合预期:
{
"scripts": {
"test:unit": {
"toolName": "run_unit_tests"
}
}
}
资料来源:src/index.ts:230-245
输入 Schema 生成
jsonSchemaToZod 函数
配置文件的 inputSchema 使用 JSON Schema 定义工具参数,系统将其转换为 Zod 验证模式:
function jsonSchemaToZod(schema: unknown): z.ZodTypeAny {
if (!isPlainObject(schema)) return z.any();
// Handle enum types
if (Array.isArray(schema.enum) && schema.enum.every((v) => typeof v === 'string')) {
const values = schema.enum as string[];
let base: z.ZodTypeAny = z.literal(values[0]);
for (const v of values.slice(1)) {
base = z.union([base, z.literal(v)]);
}
return base;
}
// Type-based conversion
switch (schema.type) {
case 'string': return z.string();
case 'boolean': return z.boolean();
case 'number': return z.number();
case 'integer': return z.number().int();
case 'array': {
const items = schema.items;
if (isPlainObject(items) && items.type === 'string') {
return z.array(z.string());
}
return z.array(z.any());
}
case 'object': {
const properties = schema.properties || {};
const requiredSet = new Set(schema.required || []);
const shape: Record<string, z.ZodTypeAny> = {};
for (const [key, value] of Object.entries(properties)) {
let prop = jsonSchemaToZod(value);
if (!requiredSet.has(key)) prop = prop.optional();
shape[key] = prop;
}
const obj = z.object(shape);
return schema.additionalProperties === false ? obj.strict() : obj.passthrough();
}
default: return z.any();
}
}
支持的 Schema 类型映射:
| JSON Schema Type | Zod Type | 说明 |
|---|---|---|
string | z.string() | 字符串输入 |
boolean | z.boolean() | 布尔开关 |
number | z.number() | 数值类型 |
integer | z.number().int() | 整数类型 |
array (string items) | z.array(z.string()) | 字符串数组 |
object | z.object({...}) | 嵌套对象 |
enum | z.union([...]) | 枚举值 |
资料来源:src/index.ts:130-175
buildToolInputSchema 函数
每个 MCP 工具的基础输入 Schema 包含两个标准字段:
function buildToolInputSchema(configForScript: McpScriptConfig | undefined): z.ZodTypeAny {
const base = z.object({
_: z.array(z.string()).optional(),
args: z
.union([z.string(), z.array(z.string())])
.optional()
.describe(configForScript?.argsDescription ?? 'Optional arguments appended after -- to the script'),
}).passthrough();
if (!configForScript?.inputSchema) return base;
const converted = jsonSchemaToZod(configForScript.inputSchema);
// ... merge logic
return mergedSchema;
}
基础 Schema 结构:
| 字段 | 类型 | 说明 | |
|---|---|---|---|
_ | string[] | 位置参数数组(可选) | |
args | `string \ | string[]` | 追加到 -- 后的额外参数(可选) |
资料来源:src/index.ts:180-200
参数到 CLI 标志转换
convertArgsToFlags 函数
当 AI 调用工具时,输入参数需转换为 CLI 标志传给 npm/pnpm/yarn/bun:
function convertArgsToFlags(
args: Record<string, unknown>,
inputSchema: z.ZodSchema
): string[] {
const parsed = inputSchema.safeParse(args);
if (!parsed.success) return [];
const validArgs = parsed.data;
const flags: string[] = [];
const positional: string[] = [];
const rawArgs = typeof validArgs.args === 'string'
? [validArgs.args]
: (validArgs.args || []);
for (const [key, value] of Object.entries(validArgs)) {
if (key === '_' || key === 'args') continue;
const flag = key.length === 1 ? `-${key}` : `--${key}`;
if (value === null || value === undefined) continue;
if (typeof value === 'boolean') {
if (value) flags.push(flag);
continue;
}
if (typeof value === 'string') {
flags.push(flag, value);
continue;
}
if (Array.isArray(value)) {
for (const item of value) {
if (item !== null && item !== undefined) {
if (typeof item === 'boolean') {
if (item) flags.push(flag);
} else {
flags.push(flag, String(item));
}
}
}
continue;
}
if (typeof value === 'object') {
flags.push(flag, JSON.stringify(value));
}
}
return [...flags, ...positional, ...rawArgs];
}
转换规则示例:
| 输入参数 | CLI 标志 |
|---|---|
{ watch: true } | --watch |
{ output: "dist" } | --output dist |
{ files: ["a.ts", "b.ts"] } | --files a.ts --files b.ts |
{ config: { ts: true } } | --config '{"ts":true}' |
{ args: "--verbose" } | -- --verbose |
资料来源:src/index.ts:300-360
MCP 服务器集成
工具注册到 McpServer
最终的工具注册通过 @modelcontextprotocol/sdk 实现:
import { McpServer } from '@modelcontextprotocol/sdk';
const server = new McpServer({ name: serverName, version: serverVersion });
// 为每个脚本注册工具
for (const scriptName of filteredScriptNames) {
const toolName = overrideName ?? sanitizeScriptName(scriptName);
const description = mcpConfig.scripts?.[scriptName]?.description
?? `${scriptName}: ${scripts[scriptName]}`;
const inputSchema = buildToolInputSchema(mcpConfig.scripts?.[scriptName]);
server.tool(
toolName,
description,
inputSchema,
async (args) => {
const extraArgs = convertArgsToFlags(args, inputSchema);
const { command, args: cmdArgs } = buildRunCommand(pm, scriptName, extraArgs);
const result = await runProcess(command, cmdArgs, options);
return {
content: [{ type: 'text', text: result.stdout + result.stderr }]
};
}
);
}
// 连接 stdio 传输层
const transport = new StdioServerTransport();
await server.connect(transport);
McpServer.tool 注册参数:
| 参数 | 类型 | 说明 |
|---|---|---|
| name | string | 工具标识符 |
| description | string | 工具功能描述 |
| inputSchema | z.ZodSchema | 参数验证 Schema |
| handler | function | 工具执行回调 |
资料来源:src/index.ts:240-280
完整执行流程
sequenceDiagram
participant AI as AI Agent
participant MCP as MCP Server
participant PM as Package Manager
participant Proj as Project Scripts
AI->>MCP: 调用工具 (run_build)
MCP->>MCP: 验证输入参数
MCP->>PM: npm run build -- --mode production
PM->>Proj: 执行构建脚本
Proj-->>PM: 输出构建结果
PM-->>MCP: stdout/stderr
MCP-->>AI: 返回执行结果配置文件结构
工具注册支持完整的 JSON Schema 验证:
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "npm-run-mcp.config.schema.json",
"type": "object",
"additionalProperties": false,
"properties": {
"include": {
"type": "array",
"items": { "type": "string" },
"description": "Exact script names to include"
},
"exclude": {
"type": "array",
"items": { "type": "string" },
"description": "Exact script names to exclude"
},
"scripts": {
"type": "object",
"additionalProperties": {
"type": "object",
"properties": {
"toolName": { "type": "string" },
"description": { "type": "string" },
"argsDescription": { "type": "string" },
"inputSchema": { "type": "object" }
}
}
}
}
}
完整配置示例:
{
"include": ["dev", "build", "test"],
"exclude": ["publish", "eject"],
"scripts": {
"test": {
"description": "运行测试套件",
"argsDescription": "传递给测试框架的参数",
"inputSchema": {
"type": "object",
"properties": {
"watch": {
"type": "boolean",
"description": "监听文件变化"
},
"coverage": {
"type": "boolean",
"description": "生成覆盖率报告"
},
"grep": {
"type": "string",
"description": "只运行匹配的正则表达式"
}
}
}
}
}
}
资料来源:npm-run-mcp.config.schema.json:1-60
依赖项
工具注册机制依赖以下核心依赖包:
| 包名 | 版本 | 用途 |
|---|---|---|
@modelcontextprotocol/sdk | ^1.25.1 | MCP 协议实现与工具注册 |
zod | ^3.23.8 | 输入参数验证(bundled) |
jsonc-parser | ^3.3.1 | JSONC 配置解析(支持注释) |
资料来源:package.json:1-40
注意事项
- JSONC 支持:配置文件支持 JavaScript 风格注释和尾随逗号,由
jsonc-parser处理 - Windows 路径转换:在 WSL 环境下运行时,自动转换 Windows 路径格式
- 超时控制:默认超时为 5 分钟,可通过环境变量或参数调整
- 输出截断:单次输出超过 12000 字符时自动截断并标注
资料来源:src/index.ts:230-245
文件监视与热重载
根据对源码的全面分析,npm-run-mcp-server 当前版本 (v0.2.13) 并不支持文件监视(File Watching)与热重载(Hot Reload)功能。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
功能概述
根据对源码的全面分析,npm-run-mcp-server 当前版本 (v0.2.13) 并不支持文件监视(File Watching)与热重载(Hot Reload)功能。
该仓库的核心定位是作为 Model Context Protocol (MCP) 服务器,将 package.json 中的脚本暴露为 AI 代理可调用的工具,而非开发工作流中的实时监听与自动重载服务。
当前架构说明
核心功能模块
当前实现主要包含以下功能模块:
| 模块 | 功能描述 | 相关源码位置 |
|---|---|---|
| 包管理器自动检测 | 检测 npm/pnpm/yarn/bun | src/index.ts:detectPackageManager() |
| 脚本执行引擎 | 使用 cross-spawn 执行脚本 | src/index.ts:runProcess() |
| 配置文件解析 | 支持 JSONC 格式配置 | src/index.ts:readProjectMcpConfig() |
| CLI 参数处理 | 支持 --cwd, --pm, --config 等 | src/index.ts 入口逻辑 |
现有工作流程
当前服务器遵循以下工作模式:
graph TD
A[MCP Server 启动] --> B[检测工作目录]
B --> C[查找 package.json]
C --> D[自动检测包管理器]
D --> E[加载 MCP 配置文件]
E --> F[注册脚本为 MCP Tools]
F --> G[等待 AI Agent 调用]
G --> H[执行对应 npm 脚本]
H --> I[返回执行结果]
I --> G资料来源:src/index.ts:入口逻辑
脚本执行机制
进程执行与超时控制
脚本执行采用原生 child_process.spawn 实现,默认超时时间为 5 分钟:
const DEFAULT_TIMEOUT_MS = 5 * 60 * 1000; // 5 minutes
资料来源:src/index.ts:DEFAULT_TIMEOUT_MS
执行函数返回结构:
interface ProcessResult {
stdout: string; // 标准输出
stderr: string; // 标准错误
exitCode: number | null; // 退出码
signal: NodeJS.Signals | null; // 中断信号
totalLength: number; // 总输出长度
timedOut: boolean; // 是否超时
}
输出截断机制
为防止大量输出导致协议阻塞,服务器实现了自动截断功能:
function trimOutput(out: string, limit = 12000, totalLength?: number)
默认限制为 12000 字符,超过部分显示为:
...[truncated X chars]
资料来源:src/index.ts:trimOutput()
配置系统
配置文件格式
支持 npm-run-mcp.config.json 或 .npm-run-mcp.json,支持 JSONC 语法(注释和尾随逗号):
{
"include": ["test", "lint", "build"],
"exclude": ["publish", "eject"],
"scripts": {
"test": {
"description": "运行测试套件",
"inputSchema": {
"properties": {
"watch": { "type": "boolean", "description": "监视文件变化" }
}
}
}
}
}
配置选项说明
| 字段 | 类型 | 说明 |
|---|---|---|
include | string[] | 白名单 - 仅暴露指定的脚本 |
exclude | string[] | 黑名单 - 排除指定的脚本 |
scripts | object | 单个脚本的详细配置 |
缺失功能说明
为何当前版本不支持热重载
- 协议限制:MCP 协议主要设计为请求-响应模式,而非事件驱动
- 架构设计:服务器启动时静态读取
package.json,无动态监听机制 - 依赖关系:核心依赖
@modelcontextprotocol/sdk未提供文件系统监听接口
替代方案建议
如需实现脚本变更监听,可考虑以下方案:
- 外部脚本封装:在项目级
package.json中添加dev脚本使用nodemon或watch工具 - 自定义 MCP 扩展:基于 SDK 扩展支持
watch模式 - IDE 集成:利用 VS Code/Cursor 的文件监视功能配合 MCP 工具调用
版本历史参考
| 版本 | 发布日期 | 相关变更 |
|---|---|---|
| v0.2.13 | 最新 | 依赖更新 (qs, express) |
| v0.2.10 | - | 添加配置文件支持 |
| v0.1.0 | - | 初始版本发布 |
资料来源:社区发布信息
结论
npm-run-mcp-server 当前不具备文件监视与热重载功能。该工具专注于将 npm 脚本可靠地暴露为 AI 可调用的 MCP 工具,强调的是静态配置与明确的工作流程控制,而非动态监听。
如需开发环境热重载,建议使用专门的开发服务器(如 Vite、webpack-dev-server)或任务运行器(如 nodemon、concurrently)配合此 MCP 服务器使用。
资料来源:src/index.ts:入口逻辑
失败模式与踩坑日记
保留 Doramagic 在发现、验证和编译中沉淀的项目专属风险,不把社区讨论只当作装饰信息。
假设不成立时,用户拿不到承诺的能力。
新项目、停更项目和活跃项目会被混在一起,推荐信任度下降。
下游已经要求复核,不能在页面中弱化。
风险会影响是否适合普通用户安装。
Pitfall Log / 踩坑日志
项目:fstubner/npm-run-mcp-server
摘要:发现 6 个潜在踩坑项,其中 0 个为 high/blocking;最高优先级:能力坑 - 能力判断依赖假设。
1. 能力坑 · 能力判断依赖假设
- 严重度:medium
- 证据强度:source_linked
- 发现:README/documentation is current enough for a first validation pass.
- 对用户的影响:假设不成立时,用户拿不到承诺的能力。
- 建议检查:将假设转成下游验证清单。
- 防护动作:假设必须转成验证项;没有验证结果前不能写成事实。
- 证据:capability.assumptions | mcp_registry:io.github.fstubner/npm-run-mcp-server:0.2.13 | https://registry.modelcontextprotocol.io/v0.1/servers/io.github.fstubner%2Fnpm-run-mcp-server/versions/0.2.13 | README/documentation is current enough for a first validation pass.
2. 维护坑 · 维护活跃度未知
- 严重度:medium
- 证据强度:source_linked
- 发现:未记录 last_activity_observed。
- 对用户的影响:新项目、停更项目和活跃项目会被混在一起,推荐信任度下降。
- 建议检查:补 GitHub 最近 commit、release、issue/PR 响应信号。
- 防护动作:维护活跃度未知时,推荐强度不能标为高信任。
- 证据:evidence.maintainer_signals | mcp_registry:io.github.fstubner/npm-run-mcp-server:0.2.13 | https://registry.modelcontextprotocol.io/v0.1/servers/io.github.fstubner%2Fnpm-run-mcp-server/versions/0.2.13 | last_activity_observed missing
3. 安全/权限坑 · 下游验证发现风险项
- 严重度:medium
- 证据强度:source_linked
- 发现:no_demo
- 对用户的影响:下游已经要求复核,不能在页面中弱化。
- 建议检查:进入安全/权限治理复核队列。
- 防护动作:下游风险存在时必须保持 review/recommendation 降级。
- 证据:downstream_validation.risk_items | mcp_registry:io.github.fstubner/npm-run-mcp-server:0.2.13 | https://registry.modelcontextprotocol.io/v0.1/servers/io.github.fstubner%2Fnpm-run-mcp-server/versions/0.2.13 | no_demo; severity=medium
4. 安全/权限坑 · 存在评分风险
- 严重度:medium
- 证据强度:source_linked
- 发现:no_demo
- 对用户的影响:风险会影响是否适合普通用户安装。
- 建议检查:把风险写入边界卡,并确认是否需要人工复核。
- 防护动作:评分风险必须进入边界卡,不能只作为内部分数。
- 证据:risks.scoring_risks | mcp_registry:io.github.fstubner/npm-run-mcp-server:0.2.13 | https://registry.modelcontextprotocol.io/v0.1/servers/io.github.fstubner%2Fnpm-run-mcp-server/versions/0.2.13 | no_demo; severity=medium
5. 维护坑 · issue/PR 响应质量未知
- 严重度:low
- 证据强度:source_linked
- 发现:issue_or_pr_quality=unknown。
- 对用户的影响:用户无法判断遇到问题后是否有人维护。
- 建议检查:抽样最近 issue/PR,判断是否长期无人处理。
- 防护动作:issue/PR 响应未知时,必须提示维护风险。
- 证据:evidence.maintainer_signals | mcp_registry:io.github.fstubner/npm-run-mcp-server:0.2.13 | https://registry.modelcontextprotocol.io/v0.1/servers/io.github.fstubner%2Fnpm-run-mcp-server/versions/0.2.13 | issue_or_pr_quality=unknown
6. 维护坑 · 发布节奏不明确
- 严重度:low
- 证据强度:source_linked
- 发现:release_recency=unknown。
- 对用户的影响:安装命令和文档可能落后于代码,用户踩坑概率升高。
- 建议检查:确认最近 release/tag 和 README 安装命令是否一致。
- 防护动作:发布节奏未知或过期时,安装说明必须标注可能漂移。
- 证据:evidence.maintainer_signals | mcp_registry:io.github.fstubner/npm-run-mcp-server:0.2.13 | https://registry.modelcontextprotocol.io/v0.1/servers/io.github.fstubner%2Fnpm-run-mcp-server/versions/0.2.13 | release_recency=unknown
来源:Doramagic 发现、验证与编译记录