mcpField
M
mcp-factory

mcp-factory

本地服务
github.com/jaimenbell开发工具09 周前更新

关于 mcp-factory

MCP Factory 根据经过验证的清单生成 MCP 服务框架,并通过运行时中心提供其工具,适合管理多项工具集成的开发者。它以清单驱动注册,并通过子进程代理将多个服务汇聚到一个 MCP 端点。

主要功能

  1. 01验证 mcp.yaml 清单
  2. 02生成 Python 和 Node.js 服务框架
  3. 03注册现有服务而不生成代码
  4. 04扫描清单并更新客户端配置
  5. 05通过单个 MCP 中心代理各 Bot 工具
  6. 06检查工具及参数设计

适用场景

  1. 01根据集成清单搭建服务框架
  2. 02批量注册项目目录中的服务
  3. 03通过一个端点提供多个 Bot 服务
  4. 04生成前检查工具描述和参数架构

MCP 相关

可生成 MCP 服务框架和配置项,也可作为 MCP 中心运行,将工具代理到各 Bot 的子进程服务。启动时扫描清单,并通过单个端点公开已注册工具。

配置

本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。

mcp.json · 通用配置
{
"mcpServers": {
"jaimenbell-mcp-factory": {
"command": "uvx",
"args": [
"jaimenbell-mcp-factory"
]
}
}
}
启动命令uvx jaimenbell-mcp-factory

本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。

安装包
pypijaimenbell-mcp-factory0.1.3

工具

还没有获取到工具列表

本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。

详细介绍

MCP Factory

CI tests python PyPI MCP Registry

下方的测试数量可验证(python -m pytest tests/ → 348 passed, 8 skipped),并由 scripts/check_readme_counts.py 在 CI 中强制检查;如果本 README 中的数量与实际测试套件不符,就会导致构建失败。

60 秒快速入门

通过 PyPI 安装(注册表用户):

pip install jaimenbell-mcp-factory
mcp-factory-hub --serve
# equivalent: python -m mcp_factory --serve

**通过 git 检出代码(贡献者):**请参阅本 README 中的 python hub_server.py ... 示例——仓库根目录下的 hub_server.py 是一个向后兼容的包装器,调用的正是控制台脚本运行的同一 mcp_factory.cli 模块,因此两种方式的行为完全一致。

**MCP Integration Sprint 背后的清单驱动引擎。**为 bot 仓库编写一个 mcp.yaml,Factory 就会生成服务存根和 ~/.claude.json 条目;运行 hub 后,它会通过单个 MCP 端点提供每个 bot 的工具。

SDK 包装器只是简单部分。让 MCP 服务能够安全地连接到真实内部工具所依赖的工程实践——限定范围的身份验证和环境变量、宽容失败的错误处理、经过验证的清单、避免冲突的注册表,以及真实的测试套件——正是此引擎围绕其构建的核心。每个合作项目都需要手工构建同样的生产层;Factory 负责搭建脚手架,不会弄虚作假。

回复前先浏览代码

本仓库公开可见,**因此你可以亲自验证这些实践,而不是只听我一面之词。**以下每项声明都对应一个可打开查看的文件:

声明文件位置查看内容
经过验证、按环境限定的清单mcp_factory/manifest.py严格的 from_dict 验证(缺少字段或字段无效时会抛出异常);用于限定服务可访问哪些机密信息的 env_required / env 模型
宽容失败的子进程代理mcp_factory/runtime/subprocess_adapter.py类型化的 SubprocessError、延迟启动、JSON-RPC 错误传递、受 timeout / OSError 保护的拆卸,以及 atexit 清理——bot 失效时会返回清晰的错误,而不会导致 hub 崩溃
避免冲突、由清单驱动的注册表mcp_factory/runtime/registry.py · registry.json重复的 <bot>.<tool> 名称会触发 CollisionError;注册表由清单生成,而非手动维护
在干净检出环境中测试tests/348 passed, 8 skipped, 0 failed(Python 3.12);8 个跳过项是真实的集成测试或 lint 检查;缺少所需条件时,这些测试或检查会直接跳过

诚实准则:348 是在干净检出环境中得到的真实、可复现的数量——与公开 CI 运行所产生并作为门槛的数量相同。mcp-factory 生成的是脚手架并运行 hub——它不会“生成生产服务”,也不声称具备客户端或 CI 相关能力。加固后的生产层(每个工具的身份验证边界、完整的故障处理集合、双轴版本固定)是在此引擎之上针对每个合作项目构建的。下面介绍的两种 Python 脚手架风格都适用这一点——请参阅“两种 Python 风格”,了解 fastmcp 变体在此基线之上具体增加了什么、没有增加什么。

快速开始

Factory 模式(通过一个清单生成配置)
# Reference an existing MCP server (no code generated — just the config entry)
python hub_server.py --manifest examples/fleet_health.yaml

# Scaffold a new MCP server from scratch
python hub_server.py --manifest my_bot/mcp.yaml --output-dir my_bot/

# Dry run — preview without writing
python hub_server.py --manifest my_bot/mcp.yaml --dry-run

# Self-verify: compare factory output to live ~/.claude.json entry
python hub_server.py --manifest examples/fleet_health.yaml --verify ~/.claude.json

默认情况下,输出始终写入 ~/.claude.json.factory-test——绝不会写入实际的 ~/.claude.json。审核后请手动复制条目。

扫描模式(批量注册所有机器人)
# Dry-run diff: show what would change in ~/.claude.json
python hub_server.py --scan C:\path\to\projects

# Apply: write ~/.claude.json after backing it up
python hub_server.py --scan C:\path\to\projects --apply

# Force-update entries already registered
python hub_server.py --scan C:\path\to\projects --apply --force

--scan 会发现所有 projects/*/mcp.yaml 文件,逐一验证,并与当前的 ~/.claude.json 进行差异比较。默认根目录为 C:\path\to\projects。使用 --apply 时,写入前会在 ~/.claude.json.scan-backup-<timestamp> 创建带时间戳的备份。

**跳过逻辑:**除非传入 --force,否则会跳过名称已存在于 ~/.claude.json 中的清单。这可以防止意外覆盖手动编写的条目。

服务模式(运行时中心——所有机器人的单一 MCP)
# Run the hub as a live MCP server (stdio transport)
python hub_server.py --serve

# Serve with multiple scan roots (repeatable)
python hub_server.py --serve \
  --scan-root C:\path\to\projects \
  --scan-root C:\path\to\Claude

# Register+serve in one step (scan --apply then start hub)
python hub_server.py --register \
  --scan-root C:\path\to\projects \
  --scan-root C:\path\to\Claude

中心会在启动时扫描每个 --scan-root 下的所有 mcp.yaml 清单,然后在 <bot>.<tool> 命名空间下公开每个机器人的工具(例如,fleet-health.fleet_status、my-bot.run_scan)。工具会通过延迟启动代理到各个机器人的子进程 MCP 服务。

中心元工具:_hub.list_bots 会返回已注册的机器人及其子进程状态。

中心已在 ~/.claude.json 中预先注册为 mcp-factory-hub(参见 scripts/register_hub.py)。

Node.js 模板

当 mcp.yaml 中设置 runtime.type: node 时,Factory 会生成 Node.js 桩代码:

runtime:
  type: node
  command: "node"
  output: "path/to/server.js"

生成的桩代码使用 @modelcontextprotocol/sdk,采用 stdio 传输,并使用 zod 验证参数。可参阅 examples/node_example.yaml 查看可运行的演示。

两种 Python 风格:原始 SDK 与 FastMCP

对于 runtime.type: python,Factory 可以根据完全相同的清单搭建以下任一种风格:

runtime:
  type: python
  command: "python"
  style: raw       # default — official `mcp` SDK, hand-rolled list_tools/call_tool
  # style: fastmcp # FastMCP v3 (PrefectHQ/fastmcp), decorator-based tool registration

两种风格都会读取相同的 tools: / env_required: 字段,并生成使用相同 stdio JSON-RPC 线路协议的服务端——运行时中心的 SubprocessAdapter 无需修改适配器即可代理其中任一种(可参阅 tests/test_fastmcp_template.py::TestFastmcpServeSmoke,了解实时生成并调用的测试)。

style: raw (python_server.py.j2)style: fastmcp (python_fastmcp.j2)
SDK官方 mcp 包,mcp.server.Serverfastmcp(固定为 fastmcp==3.4.2——4.0.0b1 是会破坏 sampling/roots 的测试版,不要使用浮动版本)
工具注册手动进行 @server.list_tools() / @server.call_tool() 分发每个工具对应一个由 @mcp.tool(...) 装饰的函数
参数架构为每个参数手动构建 JSON Schema 字典在真实 Python 参数上使用 Annotated[type, Field(description=...)]——FastMCP 会根据函数签名推导 JSON Schema,包括必填与可选项
工具主体# TODO: implement 桩代码相同的桩代码,外层包裹 try/except Exception——填充实现中的运行时错误会返回结构化的 {"status": "error", ...},而不是导致进程崩溃
env_required不在脚手架层面强制执行会渲染为启动检查 _check_required_env(),如果声明的变量缺失,就会向 stderr 发出警告——这只检查变量是否存在,不验证凭据

**坦诚说明差距:**两种风格都未实现按工具授权、速率限制,也未实现中心级 subprocess_adapter.py 免费提供的“完整故障处理集”(类型化错误、延迟启动、atexit 清理)——这些仍需在任一脚手架基础上,针对每个具体项目单独构建。fastmcp 模板的容错包装器和环境变量存在性检查是新增的真实代码(阅读 mcp_factory/templates/python_fastmcp.j2),并非关于身份验证的营销说法——之所以加入,是因为 FastMCP 的装饰器模型让它们能够以较低成本清晰地实现;它们尚未(目前还没有)回移到原始模板中,因此两种风格开箱即用的功能略有不同。如果你的项目需要 FastMCP 在此之外的特定功能(资源、提示词、HTTP/SSE 传输、基于中间件的身份验证),生成的文件就是一个普通的 FastMCP 应用——可直接扩展。

可参阅 examples/fastmcp_example.yaml 查看可运行的演示清单。

mcp.yaml 架构

name: my-bot                   # REQUIRED — unique MCP server name (key in claude.json)
description: >                 # REQUIRED — shown in Claude's tool descriptions
  What this bot does and when to use it.

runtime:                       # REQUIRED
  type: python                 # python | node | binary
  command: "C:\\Python314\\python.exe"  # full path to interpreter
  script: "path/to/server.py"  # existing server (skips scaffold generation)
  output: "path/to/out.py"     # where to write generated scaffold (omit = auto)
  style: raw                   # python only: raw (default) | fastmcp — see "Two Python styles"

tools:                         # REQUIRED — list of MCP tools to expose
  - name: tool_name            # REQUIRED — programmatic identifier
    title: "Tool Name"         # Optional — human display name (see below)
    description: >             # REQUIRED — used by Claude for routing
      What this tool does.
    annotations:               # Optional — the four MCP behaviour hints
      readOnlyHint: true       # tool does not modify anything
      destructiveHint: false   # tool does not perform destructive updates
      idempotentHint: true     # repeat calls have no additional effect
      openWorldHint: false     # tool does not touch an open external world
    args:                      # Optional list of arguments
      - name: arg_name         # REQUIRED
        type: string           # string | number | boolean | object | array
        required: true         # default: true
        description: "..."     # shown in Claude's tool schema

env_required:                  # env var names that must be set at runtime
  - MY_API_KEY

env:                           # static env vars injected into claude.json entry
  MY_API_KEY: ""               # leave value empty — fill in ~/.claude.json manually

tags: [trading, health]        # for documentation / future routing
priority: high                 # high | medium | low
关键规则
  • runtime.script + 已有文件 → 工厂会引用该文件,跳过脚手架生成
  • runtime.script + 文件不存在 → 验证错误(新建脚手架时使用 runtime.output)
  • runtime.output → 生成的存根文件的显式路径(建议使用绝对路径)
  • 既没有 script 也没有 output → 在配置写入步骤报错
title 和 annotations

这两个字段都是可选的,也都值得声明。

title 是面向用户显示的名称,因此 name 可以保持为程序标识符。显示名称的优先级为 title → annotations.title → name;工厂只会暴露顶层的 title,因此一个清单不能声明两个相互竞争的显示名称。

annotations 的重要性超乎表面。四个提示都有保守的默认值——destructiveHint 和 openWorldHint 的默认值都是 true,readOnlyHint 的默认值是 false——因此,如果工具没有声明任何内容,谨慎的客户端会将其视为可能具有最高危险性的工具。只读工具通过声明 readOnlyHint: true 来避免这种情况。只接受上述四个提示名称,每个值都必须是实际的布尔值;未知键会导致硬错误,而不是被静默忽略(否则,拼写错误 readonlyHint 会导致工具在协议传输中实际上没有任何注解)。

注解只是提示,不是安全边界——规范明确指出,客户端绝不应基于来自不可信服务的注解来决定是否使用工具。注解会影响客户端的用户体验,但不会强制执行任何操作。

这两个字段都会由两个 Python 模板生成。Node 模板目前还不会渲染它们——仓库不会 vendoring node_modules,因此无法在测试中执行经过修改的调用形式;发布未经验证的生成代码,比维持当前形式更糟。即使在 Node 清单中声明这些字段仍然有效,并且具备向前兼容性。

生成时工具设计检查

清单验证是一道安全关卡:只要存在任何可能向生成的服务注入代码的情况,就会失败关闭。但它不会检查生成的工具质量如何。清单可能完全有效,但生成的服务仍可能让 Agent 的表现显著变差。

因此,工厂模式的每次运行都会执行工具设计检查(步骤 2),涵盖三个范围内的 15 条规则:

范围检查项
清单工具数量限额;忽略大小写和分隔符后发生冲突的名称;跨服务冲突的泛化名称
工具描述为空/过于单薄/充斥填充内容;描述仅复述名称;名称不符合 snake_case 或过长;缺少注解;列表工具无上限;注解与名称相矛盾
参数未描述的参数;未限定的参数名称;没有描述、因此也没有 schema 形状的结构化(object/array)参数

默认情况下,检查仅提供建议:打印发现项,继续生成,并以状态码 0 退出。 --lint-strict 会将错误级别的发现项视为致命问题:报告这些问题、不写入脚手架,并以状态码 3 退出。

mcp-factory-hub --manifest examples/fastmcp_example.yaml --lint-strict

这项检查有三个有意设计的特性:

  • 无法判断时会报告 INDETERMINATE,而不是判定为合格:例如,清单中的 runtime.script 已存在(工厂会引用这个手写文件,而不会生成文件,因此工具列表可能与实际服务不符),或者运行时没有模板。--lint-strict 绝不会因结果不确定而阻止执行:不能把没有判定结果转换成判定结果。
  • 没有工具名称字符集规则,尽管 SEP-986 定义了相关规则。清单自身的标识符验证已经更严格,会在解析时拒绝违规项,因此该规则不可能对任何进入检查的输入生效;无法触发的检查不算检查。只有 SEP-986 中关于长度的部分未在上游强制执行,因此规则也只检查长度。
  • 每条规则都附带正向对照测试:测试证明规则会针对已知有问题的工具定义触发,而对已知良好的定义保持静默;此外还有套件级测试,确保格式良好的清单不会产生任何发现项。examples/ 中的示例本身也必须通过检查,相关测试为 tests/test_examples_lint_clean.py。

如何添加新的 MCP

  1. 在你的机器人仓库根目录(或 examples/ 中)编写 mcp.yaml
  2. 运行工厂:
    python hub_server.py --manifest path/to/mcp.yaml
    
  3. 检查 ~/.claude.json.factory-test,确认条目无误
  4. 将条目复制到 ~/.claude.json 的 mcpServers 下
  5. 重启 Claude Code

如果机器人没有现成的服务,工厂会在 generated/<name>_server.py 生成一个存根。填写其中的 # TODO: implement 部分,并在后续运行时将 runtime.script 设置为该存根路径。

运行时 Hub 架构

hub_server.py --serve
  └── mcp_factory/runtime/
      ├── hub.py               async MCP server (lists + routes all tools)
      ├── registry.py          maps <bot>.<tool> → manifest + adapter
      └── subprocess_adapter.py  spawns per-bot MCP server, proxies JSON-RPC

子进程生命周期:

  • 首次调用工具时才惰性启动适配器(不会预先启动进程)
  • Hub 会话期间保持运行(每个机器人一个进程)
  • _hub.list_bots() 报告状态:idle(尚未启动)或 running
  • Hub 退出时通过 atexit 停止所有适配器;如有需要,stop() 会在 5 s 后强制结束进程

工具命名:<bot-name>.<tool-name> —— 保留连字符,以点号作为分隔符。 示例:fleet-health.fleet_status、my-bot.get_alerts。

第 4 天 —— workflow_runner.py

用于研究工作流的独立 CLI 测试工具,与 hub_server.py 相互独立。

# Discover and list all SKILL.md workflows
python -m mcp_factory.workflow_runner --list

# Run a specific workflow
python -m mcp_factory.workflow_runner --run my-skill

# Validate all discovered SKILL.md files
python -m mcp_factory.workflow_runner --validate

# Write/update registry.json from discovered skills
python -m mcp_factory.workflow_runner --write-registry

# Check for drift between discovered skills and registry.json
python -m mcp_factory.workflow_runner --check

# Control cache behavior
python -m mcp_factory.workflow_runner --run my-skill --cache-policy force-refresh
python -m mcp_factory.workflow_runner --run my-skill --cache-policy read-only
工作原理

workflow_runner.py 默认扫描 ~/research(使用 --scan-root 覆盖),查找包含 YAML 前置元数据的 SKILL.md 文件。每个 SKILL.md 都定义一个带有元数据的命名工作流:

---
name: my-skill
description: What this workflow does
output_path_template: "~/vault/output/{date}/{name}.md"
---
Prompt body passed to claude -p subprocess...
  • 发现: 使用 git ls-files 枚举每个扫描根目录下受跟踪的 SKILL.md 文件
  • 验证: 检查必需的前置元数据字段(name、description)
  • 缓存: 使用基于 SHA 的缓存,以提示词内容为键;auto(默认)在输出未变化时跳过重跑,force-refresh 始终重新运行,read-only 从不写入
  • 运行: 将 claude -p <prompt> 作为子进程调用,并流式传输输出
  • 写入输出: 展开 output_path_template,将结果写入知识库
  • 注册表: --write-registry 将发现的技能持久化到 registry.json;--check 检测文件系统与注册表之间的差异,但不写入

目录结构

mcp-factory/
├── hub_server.py              # CLI entry point (factory / scan / serve)
├── mcp_factory/
│   ├── manifest.py            # Manifest dataclass + YAML loader + validation
│   ├── generator.py           # Python MCP server stub scaffolder
│   ├── config.py              # claude.json entry builder + comparator
│   ├── scan.py                # --scan mode: manifest discovery + diff/apply
│   ├── workflow_runner.py     # Day 4: standalone CLI harness for SKILL.md workflows
│   ├── templates/              # packaged as data so `pip install` ships them too
│   │   ├── python_server.py.j2    # Jinja2 template — raw mcp SDK stubs (style: raw, default)
│   │   ├── python_fastmcp.j2      # Jinja2 template — FastMCP v2 stubs (style: fastmcp)
│   │   └── node_server.js.j2      # Jinja2 template for generated Node.js stubs
│   └── runtime/
│       ├── subprocess_adapter.py  # subprocess MCP client (JSON-RPC proxy)
│       ├── registry.py            # tool registry with collision detection
│       └── hub.py                 # async hub MCP server
├── tests/
│   ├── fixtures/
│   │   ├── fleet_health.yaml   # Day 1 self-verification fixture
│   │   ├── minimal.yaml        # Minimal valid manifest
│   │   └── mock_mcp_server.py  # Stdlib-only mock MCP server for adapter tests
│   ├── test_manifest.py
│   ├── test_generator.py
│   ├── test_subprocess_adapter.py
│   ├── test_registry.py
│   ├── test_scan.py
│   ├── test_hub_cli.py
│   ├── test_mcp_pkg.py
│   ├── test_node_template.py
│   ├── test_python_template.py
│   ├── test_fastmcp_template.py  # style: fastmcp generation + import + serve-smoke tests
│   ├── test_register_flag.py
│   ├── test_registration.py
│   ├── test_smoke_hub.py
│   ├── test_watcher.py
│   ├── test_workflow_runner.py  # Day 4: workflow_runner unit + integration tests
│   └── test_integration_fleet_health.py  # live integration tests (skipped if server absent)
├── examples/
│   ├── fleet_health.yaml      # Example manifest referencing an existing server
│   ├── node_example.yaml      # Example manifest for the node template
│   └── fastmcp_example.yaml   # Example manifest for the fastmcp template
└── pyproject.toml

自我验证

examples/fleet_health.yaml 清单引用了一个示例服务。运行:

python hub_server.py --manifest examples/fleet_health.yaml --verify ~/.claude.json

可确认工厂会生成匹配的 ~/.claude.json 条目。

运行测试

python -m pytest tests/ -v

在干净的检出副本上(Python 3.12),执行 pip install -e .[dev] 后:348 项通过,8 项跳过,0 项失败——这与公开 CI 运行得出的结果相同,也是其门槛。

当所需资源或条件不存在时,8 项跳过的测试会自动跳过:

  • test_integration_fleet_health.py(5 项测试)需要磁盘上存在 fleet-health server.py(FLEET_HEALTH_SERVER_PATH)。
  • test_node_template.py(1 项测试)需要存在 node 和 @modelcontextprotocol/sdk(node_modules/)。
  • test_examples_lint_clean.py(2 项测试)会跳过 examples/fleet_health.yaml。该文件引用了一个现有的手写服务,工具设计检查会正确地将其报告为 INDETERMINATE,而不会评判它无法看到的代码;跳过测试是如实记录这一情况的方式。

test_smoke_hub.py(4 项测试)现在无需连接实际运行的机器人群即可真正运行:hub 的演示清单回退机制(见下文)即使在空扫描根目录下也能提供可发现的内容,因此这些测试现在会在干净的检出副本上无条件运行。

(在维护者的机器人群机器上,由于 fleet-health 服务和实际运行的机器人都存在,其余跳过的集成测试会真正运行,通过的测试数也会更高——但本 README 仅声明干净检出副本和公开 CI 都能复现的结果。)

fastmcp 风格的模板测试(test_fastmcp_template.py)不在此跳过列表中——fastmcp 已作为 [dev] 额外依赖安装,因此在标准开发环境中会真正运行。

商业支持

由 Jaimen Bell 维护。如需生产环境 MCP 集成、自定义服务或 Agent 可靠性方面的工作,请访问 jaimenbell.dev。

正在构建自己的 MCP 服务?MCP Starter Kit 提供模板、构建指南,以及发布这个服务时积累的打包经验。

mcp-name: io.github.jaimenbell/mcp-factory

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。