Node.js · TypeScript · MCP

Multi-Model Broker

一个面向 MCP 的多模型任务代理层:MCP 客户端(ChatGPT、Codex 或任何 harness)把任务交给它, 它按能力路由到本机或云端的多个 worker(本地 Codex、本地 Claude Code、DeepSeek、GLM、Gemini、mock), 返回统一结构的结果并留下可审计的 trace。读/写能力严格分离,写型 worker 只能经各自的写工具到达。

Node.js ≥ 22.5 TypeScript 零原生模块 263 测试 / 33 文件 测试全部离线

它解决什么

把「用哪个模型、交给本机还是云端、怎么回收结果、怎么留痕」这些决策从客户端里抽出来,收敛到一处。 客户端只按统一结构提交任务,Broker 负责路由、并发、幂等、超时与审计;读路径和写路径分开, 写盘只能通过明确标注的写工具触发。它不替代任何模型,只在模型之上加一层可验证的调度与隔离。

MCP 双传输

stdio 接入本地 harness;Streamable HTTP(回环 + 共享密钥,可选 SSE 应答)供网络侧客户端使用。

确定性路由

按 requirements + 能力声明选择 worker,链式回退;显式指定 worker 永不被改写,无需 LLM 参与路由。

长任务与并发

waitMs 内阻塞返回;超时返回 taskId 用 get_task 轮询。每 worker 并发上限 + 全局上限。

幂等

idempotencyKey 去重,重复提交只等待不重跑,避免二次计费。

审计 trace

每次委派记录 goal、路由原因、provider/model、时间、工具事件、用量与错误。

读写隔离

只读工具拒绝写型 adapter;写型 worker 只能经唯一的写工具 run_agent 到达(首次必须点名 worker,之后可省略),标注 readOnlyHint: false。

公网可达不开端口

relay 子命令让本机主动外连自建中继(Cloudflare Worker + Durable Object),无需开放入站端口。

选定即记住,切换只一步

点名的 worker / model 成为该工具的默认,后续调用可省略;换一个就切换。list_workersdefaultFor 标出当前选择,trace 记下 choice.remembered

本地 agent 接入

codex-sdk 与 claude-code 两种 adapter;claude-code 的后端与模型由使用者自行配置(任意 Anthropic 兼容端点),本仓库不预置默认模型。

架构

客户端经本地 stdio 或公网中继进入 Broker Core,Core 把读工具路由到只读 worker、把写工具路由到写型 worker。

Multi-Model Broker architecture MCP clients (ChatGPT, Codex, any harness) connect via local stdio or an outbound relay to the Broker Core (Router, Scheduler, TaskManager, TraceStore), which routes read tools to read-only workers and write tool (run_agent, with its worker named explicitly) to write-capable workers. Multi-Model Broker — Architecture MCP 任务代理层 · 读/写通道分离 · 确定性路由 MCP 客户端 ChatGPT Codex 任意 harness 传输 本地 stdio 公网中继 本机主动外连 · 不开端口 Broker Core Router 确定性路由 · 无 LLM Scheduler 并发 · FIFO 信号量 TaskManager 任务生命周期 · 幂等 TraceStore 追加式审计事件 确定性路由 · 链式回退 · 显式指定 worker 不改写 facade: submit / delegate / delegate_batch / get_task / get_trace / cancel MCP 工具层只调用 Broker facade,不直接触碰 provider / storage Core 不依赖 ChatGPT,也不依赖 MCP 读工具 写工具 Provider adapters 只读 worker DeepSeek openai-compatible GLM openai-compatible Gemini Generative Language API mock 注入实现 · 离线 写型 worker 本地 Codex run_agent · readOnlyHint: false · destructiveHint: true 本地 Claude Code run_agent(worker=claude-code) · 你配置的后端 写型 worker 只能经 run_agent 到达 读工具 → 只读 worker:run_worker / delegate / delegate_batch 写工具 → 写型 worker:run_agent(worker=codex|codex-win|claude-code)

快速开始

依赖 Node.js ≥ 22.5(使用内置 node:sqlite,无需原生模块与构建工具链)。

安装与自检
npm ci
npm run check && npm test && npm run build
node dist/cli/index.js doctor
本地 stdio 接入
node dist/cli/index.js mcp-stdio \
  --profile local-full
回环 HTTP 接入
node dist/cli/index.js mcp-http \
  --profile chatgpt-agent \
  --token-env BROKER_HTTP_TOKEN \
  --port 8789

用自己的环境跑起来

  • 至少一个 API workercp .env.example .env,填入一个 *_API_KEY(DeepSeek / GLM / Gemini),在 config/providers.yaml 里启用它;只想先看看就用 config/providers.mock.yaml(纯假实现、零成本)。
  • 可选:本地写型 agentcodex 用本机已有 Codex 登录(broker 不读也不复制凭据);claude-code 需要 Anthropic 兼容端点与令牌 —— 直接 export ANTHROPIC_BASE_URL / ANTHROPIC_AUTH_TOKEN,或写进文件由 options.envScript$CLAUDE_ENV_SCRIPT 指向(默认 ~/.config/multimodel-broker/claude-code.env,密钥从不进命令行)。
  • 可选:公网接入relay setup 引导部署自建中继,本机主动外连、不开入站端口。

不假设任何目录布局,也不内置任何凭据;doctor 会逐个报告还缺什么,但从不打印密钥。

工具

MCP 面共 9 个注册工具,两个 profile 各暴露 8 个(差别只在 run_agentcancel_task);只读与写型分开标注。

工具 类型 说明
ping只读Broker 健康探测
list_workers只读列出已配置 worker 及其能力与健康状态
run_worker只读路由到某个只读 worker 执行,拒绝写型 adapter
run_agent写型驱动本机 agent(worker=codex / codex-win / claude-code,首次必须点名、之后可省略),readOnlyHint: false · destructiveHint: true
delegate只读单任务委派,拒绝写型 adapter
delegate_batch只读一次最多 8 个任务并行,部分失败也保留结果
get_task只读按 taskId 轮询长任务结果
get_trace只读读取某次委派的审计 trace
cancel_task只读取消排队/运行中的任务(本地运维工具,默认不下发给远程客户端)

安全基线

写盘与出网默认收紧,需要本地显式开启。