mcpField
L
Legion MCP

Legion MCP

已认证精选本地服务
github.com/faulkjAI 与智能体13 周前更新

关于 Legion MCP

Legion 是面向多模型协作工作流的 MCP 原生模型议事系统。它将配置的模型分别公开为工具,并提供 quorum 和预设议事组,用于辩论、评审团及其他结构化讨论。

主要功能

  1. 01每个已配置模型对应一个 MCP 工具
  2. 02跨多个模型发起 quorum 调用
  3. 03用于结构化讨论的预设议事组
  4. 04顺序、并行、私密和独立模式
  5. 05可热重载的模型与议事组配置

适用场景

  1. 01围绕问题开展多模型辩论
  2. 02收集盲审小组答复并投票
  3. 03将预设议事组用于代码评审
  4. 04通过多轮模型讨论完善答复

MCP 相关

将每个已配置模型、quorum 功能和各预设议事组分别作为 MCP 工具公开。它通过 OpenAI Responses API 线格式调用模型端点,可直接连接或经兼容网关转发。

配置

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

mcp.json · 通用配置
{
"mcpServers": {
"legion-mcp-cd96ce": {
"command": "npx",
"args": [
"-y",
"legion-mcp"
],
"env": {
"MCP_TRANSPORT": "<MCP_TRANSPORT>",
"DEFAULT_BASE_URL": "<DEFAULT_BASE_URL>",
"DEFAULT_API_KEY": "<DEFAULT_API_KEY>",
"ALLOW_NO_MODELS": "<ALLOW_NO_MODELS>",
"OPENAI_API_KEY": "<OPENAI_API_KEY>",
"MAX_ROUNDS": "<MAX_ROUNDS>",
"TOKEN_BUDGET": "<TOKEN_BUDGET>",
"DYNAMIC_ROLES": "<DYNAMIC_ROLES>",
"LOG_LEVEL": "<LOG_LEVEL>",
"ASYNC_TOOLS": "<ASYNC_TOOLS>",
"TRUST_PROXY_AUTH": "<TRUST_PROXY_AUTH>"
}
}
}
}
启动命令npx -y legion-mcp
需要配置的环境变量
MCP_TRANSPORTRun the installed package over MCP stdio (the binary defaults to HTTP).
DEFAULT_BASE_URLDefault OpenAI Responses-compatible API root for model files that omit baseUrl.
DEFAULT_API_KEY密钥Default provider or gateway key for model files that omit apiKey.
ALLOW_NO_MODELSBoot without any config/models/*.json. The package ships only key-free examples, which the scanner ignores, so this must stay true until a real model file exists beside the working directory.
OPENAI_API_KEY密钥Optional. A model file's apiKey may be "env:VAR" to read the key from an environment variable named VAR at startup; name those variables here as needed. The bundled gpt example reads this one.
MAX_ROUNDSMaximum discussion rounds accepted by a council run.
TOKEN_BUDGET密钥Optional soft cumulative token budget for a council run.
DYNAMIC_ROLESAllow callers to define ad-hoc council roles inline.
LOG_LEVELLogging verbosity. Logs are written to stderr for stdio safety.
ASYNC_TOOLSRun councils in the background: council tools return a job handle and poll/cancel tools are exposed. Jobs live in process memory only.
TRUST_PROXY_AUTH密钥Bind async jobs to the caller named by X-MS-CLIENT-PRINCIPAL-* headers. Only safe behind an ingress that strips client-supplied copies.

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

安装包
npmlegion-mcp0.8.0

工具

17

收录的工具列表 · 更新于 3 周前

参数类型必填说明
modelsarray是两个或更多选择器:"model" 或 "model:role"。同一模型可通过不同角色多次出现(例如 "gpt:judge" 和 "gpt:skeptic");每个选择器都是独立的发言者。可用模型:
roundsinteger否讨论轮数(默认 1;上限由 MAX_ROUNDS 设置)
objectivesobject否团队运行的可选逐团队目标:从团队标签到该团队共同目标的映射。使用 model:role@team 标记发言者;每个已标记团队都必须在此设置目标。每位队友都能看到自己团队的目标;综合器可以看到所有目标。
tokenBudgetinteger否整个运行过程的可选软性累计 token 预算(覆盖 TOKEN_BUDGET)。顺序模式会在轮次之间检查;并行模式会在轮次边界检查,因此触发前可能超出预算。超出后会妥善跳过剩余轮次,但仍会执行综合。这不是硬性上限。参见 structuredContent.budget。
promptstring是要发送给模型的问题或任务
contextstring否可选的补充文本(代码、文档、数据),作为单独的区块附加到提示词
systemstring否可选的系统提示词/指令
temperaturenumber否可选的采样温度
maxTokensinteger否可选的最大输出令牌数。预算需同时涵盖可见回答和任何隐藏推理:推理模型会在输出文本前消耗令牌进行思考,因此上限过紧可能导致没有空间输出可见回答。为推理模型预留充足余量;在多轮 quorum 中应进一步提高上限,因为记录会随着每轮增长。
rolesobject否此 quorum 调用的临时角色:角色名称到指令的映射。在 models 中使用 "model:role" 引用。
modeenum否每轮发言者能看到多少对话记录:sequential(默认;可见之前的所有发言)、parallel(仅可见之前已完成的轮次,看不到同轮参与者的发言)、private(仅可见自己的先前发言)、independent(直到综合阶段前,只能看到提示词)。sequential | parallel | private | independent
synthesizestring否综合发言轮次的选择器。综合者不会在常规轮次发言,只会在其综合时段发言。
synthesizeEveryany否综合者的运行时机(仅在设置 synthesize 时有效):数字 N 表示每 N 轮综合一次(并始终在最后综合);1 = 每轮;0 = 仅在结束时综合。"end" 是 0 的别名(默认值)。
framestring否可选的中立主持者选择器:负责在第 1 轮开场,通过明确讨论重点并塑造问题来引导讨论的主持者。不得表明立场,也不能带有团队标签。与负责收尾的 synthesize 相对应;主持者负责开场。
reframeEveryany否主持者再次发言的时机(仅在设置 frame 时有效):数字 N 表示每 N 轮重新设定框架,以引导/调整讨论方向;0 或 "end"(默认值)表示仅在开场设定框架。
closingStatementsboolean否为 true 时,每位轮次发言者都会在综合前,针对完整对话记录给出一条最终并行陈述。需要设置 synthesize。
votestring否可选的匿名同伴投票说明。设置后,每位参与的轮次发言者都会投一张隐藏选票,从候选项菜单中选择一个数字(除非 allowSelfVote 为 false,否则包含自己的席位),或选择 0 弃权。对话记录中只会添加按候选标签统计的匿名票数(不会显示谁投给了谁);选票会从日志中删去。该机制仅提供建议,不会淘汰候选人或选出获胜者;如果希望据此采取行动,请在提示词中指示综合者/裁判。
voteEveryany否匿名投票的触发时机(仅在设置 vote 时有效):数字 N 表示每 N 轮投票一次(始终包括最后一轮);0 或 "end"(默认值)表示仅在最后投票一次。
voteVisibilityenum否投票结果的显示范围:"aggregate"(默认)仅显示计数;"ballots" 还会显示匿名化后的选票文本(不显示投票者身份)。aggregate | ballots
allowSelfVoteboolean否投票者自己的席位是否显示在其投票菜单中(仅在设置 vote 时有效)。默认值为 true(投票者可以选择自己,如同真实选举)。对于自投属于钻规则空子的同伴评判投票(例如 "vote the weakest peer"),请设为 false。

详细介绍

Legion

“我乃军团,因为我们人数众多。”

一个原生支持 MCP 的模型议会。Legion 将 大模型作为独立工具公开,并将它们编排成辩论、陪审团、盲评小组、私密精进 挑战、研讨会和自定义多模型审议。

每个模型都通过 OpenAI Responses API 线路格式调用。可直接使用 OpenAI 或 Azure,也可通过兼容网关(例如 LiteLLM 代理)路由其他提供商,并通过支持热重载的文件配置整个议会。

目录

工作原理

flowchart LR
   AI[Calling AI] -->|claude / gpt / gemini …| Legion
   Legion -->|Responses API| GPT[OpenAI / Azure — direct]
   Legion -->|Responses API| GW[Gateway e.g. LiteLLM]
   GW --> Claude & Gemini & Llama
  • 每个模型对应一个工具,工具名称取自模型名称的 slug 化形式(例如 Claude → claude)。每个工具都接受一个 prompt,以及可选的 context、role、system、 temperature 和 maxTokens。
  • quorum 工具将一个提示词分发给多个模型——支持角色、多轮讨论、可见性模式 和综合整理——并分别返回每个答案。编排选项请参阅预设。
  • 预设是命名的预配置议会(辩论、法庭、代码审查……),每个预设都作为独立工具公开。
  • 身份信息和遥测数据通过 structuredContent 传递,而不放在答案文本中。 日志输出到 stderr(适用于 stdio)。

设计决策

  • 没有提供商适配器。 不包含针对特定提供商的代码,也没有内置模型列表。Legion 使用一种线路格式;不原生支持该格式的模型需通过网关接入。支持新模型无需修改此处代码。
  • 模型是配置,不是代码。 添加模型只需添加一个 JSON 文件。通过 HTTP 使用时,每次 请求都会重新读取目录,因此无需重新构建或重启;通过 stdio 使用时,每个连接只读取一次 配置(见热重载)。
  • 每个模型对应一个工具。 在发起调用的 AI 看来,每个模型都是拥有独立描述的工具, 而不是带模型参数的单一工具。quorum 工具适用于临时的多模型场景,而 config/presets/ 中的每个预设都作为独立的、强制执行预配置人员编组的议会工具公开。
  • 无状态。 每次调用都是一次性的,并设置 store: false。不会保留任何内容,因此无需 数据库,也无需管理对话状态。
  • 精简。 数千行 TypeScript、一个打包输出文件、五个依赖项。

要求

  • Node.js 24+
  • 至少一个兼容 OpenAI Responses 的端点(直接使用提供商 API,或使用 LiteLLM 等网关 为需要桥接的模型提供支持)

设置

通过 npm 安装——无需克隆或构建:

npx legion-mcp

从克隆的仓库安装:

npm install
copy .env.example .env   # then edit .env

配置

所有配置都位于 config/ 目录中。随附的默认配置始终是基础层;当前工作目录中的 config/ 文件夹会按文件叠加在其上:

  • 目录资源(models/、roles/、presets/、tools/):本地文件会覆盖同名的随附文件;仅存在于本地的文件会被添加;未修改的随附文件都会保留。因此,放入一个 config/presets/refine.json 只会覆盖该预设,其他随附预设仍会保留。
  • 单文件文本(prompts.json、errors.json、schema.json):按键合并——随附配置 < 本地配置。本地文件可以不完整,只覆盖其中设置的键。
  • description.md:若存在本地文件,则整份采用本地版本;否则采用随附版本。

叠加配置可以覆盖或添加条目,但不能删除随附条目。要选择哪些随附预设注册为工具,请使用 PRESETS(见下文)。

从 npm 安装?你必须提供自己的模型文件。随附配置仅包含不含密钥的 *.example.json 模型文件,扫描器会有意忽略这些文件,因此配置包不会提供任何真实模型。若没有真实模型文件,服务会在启动时快速失败(No model files found in ...)。请在运行服务的位置旁放入一个 config/models/<name>.json(见下文)——其余配置会回退到随附默认值。

无论采用哪种方式,下面的目录结构都相同。

热重载

配置会在构建服务实例时重新读取,不会在构建时固化——但具体何时读取取决于传输方式:

传输方式重新读取配置的时机编辑配置文件的效果
http每个请求下次调用时立即生效,无需重启。
stdio每次连接时一次客户端重新连接时生效。

HTTP 会为每个请求构建一个全新的服务,因此新增的模型、角色、预设或文本覆盖会在下次调用时立即生效。Stdio 会在整个连接期间固定使用同一个服务,因此相同的编辑要等客户端重启 Legion 后才会生效——对大多数桌面 MCP 客户端来说,这意味着重新加载服务,而不是重启机器。

本 README 中提到的“下次调用时立即生效”,指的是 HTTP 的行为;使用 stdio 时,则要等到下次连接。

Models — config/models/*.json

至少需要一个模型文件,否则服务会快速失败。 每个 JSON 文件都会变成一个工具,工具名称取自经过 slug 化的文件名 (config/models/fable.json → 工具 fable):

{
   "model": "claude-fable-5",
   "description": "Claude Fable — fast, creative, general purpose.",
   "baseUrl": "https://api.example.com",
   "apiKey": "sk-optional-per-model-key"
}
  • model(必填)— 端点路由到的已部署模型 ID。
  • description — 帮助调用方 AI 选择合适的模型。
  • system — 可选的基础系统指令,会内置到对该模型的每次调用中。
  • baseUrl / apiKey — 可选;省略的值会回退到 DEFAULT_BASE_URL / DEFAULT_API_KEY。apiKey 可通过 env: 前缀引用环境变量——"apiKey": "env:GPT_KEY" 会从环境中读取 GPT_KEY(未设置或为空会导致启动失败),因此密钥可以完全不写入文件。
  • omitParams — 可选的请求参数列表,用于针对该模型删除参数,例如 ["temperature"]。服务保持与提供方无关:不会假定哪些模型会拒绝哪些参数——你可以在此声明每个模型的特性。适用于推理模型以及某些会拒绝 temperature 的部署。
  • reasoning — 可选的 "minimal" | "low" | "medium" | "high",作为 reasoning.effort 发送。推理模型可能会耗尽全部 maxTokens 进行思考而不输出内容;设置 "low" 可能有助于为答案留出空间。端点必须支持此参数;它不会绕过内容过滤。
  • maxTokens — 可选的该模型输出硬上限。每个请求都会发送 min(requested, ceiling),无论调用方或预设角色要求多少。适用于思考空间越大就思考越深入、并可能返回空结果的模型。

热加载: 每次请求都会重新扫描目录——添加或编辑模型文件后,下次调用即可生效,无需重启。

密钥与 Git: 模型文件可能包含 API 密钥,因此 config/models/*.json 会被 Git 忽略。复制一个 *.example.json(已跟踪、不含密钥且会被扫描器忽略)即可开始:

copy config\models\gpt.example.json config\models\gpt.json   # then add your key
Roles — config/roles/*.md

可选的热加载指令文件。每个 .md 文件都会变成一个具名角色 (名称取自经过 slug 化的文件名)。放入文件后,下次调用即可生效。此仓库提供 skeptic.md、builder.md、judge.md 和 short.md(一种简短的“立即回答,不作推敲”角色,适用于输出受限的轮次)作为开箱即用的起始文件——可随意编辑或删除(其中不含密钥)。

工具中可用的选择器会变成 roleName,例如传入 role: "skeptic" 或在 quorum.models 中使用 "model:skeptic"。

Presets — config/presets/*.json

可选的热加载评审团方案,每个预设对应一个 JSON 文件(名称取自经过 slug 化的文件名,与模型文件类似)。每个预设都会变成独立的工具——放入 config/presets/code_review.json 后,下次请求就会出现 code_review 工具。每个预设都有一个 description、一个 roles 列表,以及可选的权威 mode / synthesizer 默认值。每个角色都内联定义其行为——角色的 description 就是其指令(行为约定);没有 description 的角色会回退到匹配的 config/roles/<role>.md 文件:

{
   "description": [
      "Free-for-all: pit several contestants against each other, then crown a winner.",
      "",
      "Staff `contestant` with as many models as you like; one `judge` decides."
   ],
   "mode": "parallel",
   "synthesizer": "judge",
   "roles": [
      { "role": "contestant", "description": "Argue why your answer beats the others.", "min": 2, "max": null },
      { "role": "judge",      "description": "Crown a single winner and justify it.", "min": 1, "max": 1 }
   ]
}

调用方 AI 会直接调用预设工具(例如 code_review),仍需编写 models 选择器,将任意模型分配给任意预设角色。预设会强制执行:每个选择器都必须使用预设角色,并且每个角色都必须按照其基数配置人员,否则结果会报错并指出需要修正的内容。

键:

键类型默认值描述
descriptionstring | string[]必填预设工具的 MCP 描述。
rolesPresetRole[]必填预设接受的角色。
mode"sequential" | "parallel" | "private" | "independent""sequential"控制每轮发言者能看到哪些先前轮次的内容。
defaultRounds正整数1调用未提供 rounds 时使用的轮数。
synthesizerstring无负责生成综合总结轮次的角色。单席位角色为中立角色,不参与各轮讨论;多席位角色(max > 1 或 null)会参与讨论,并由其首个活跃席位进行综合总结。
synthesizeEvery"end" | non-negative integer"end"在结束时或每隔 N 轮进行一次综合总结。
eliminatorstring无负责淘汰发言者的中立角色。与 eliminateEvery 配合使用时为必填项。
framerstring无负责开启讨论并引导讨论方向的中立角色。
reframeEvery"end" | non-negative integer"end"仅在开场时重新设定讨论方向,或在开场后每隔 N 轮重新设定一次。
closingStatementsbooleanfalse在最终综合总结前运行总结陈词阶段。
eliminateEverynon-negative integer | "spread"0允许淘汰者每隔 N 轮淘汰一名发言者,或均匀分配淘汰次数。仅限预设。
eliminationsOptionalbooleanfalse允许淘汰者选择不淘汰任何人。仅限预设。
enterEverynon-negative integer0每队先安排一名发言者,然后每隔 N 轮加入一名候补发言者。仅限预设。
votestring无投票说明;启用匿名投票。
voteEvery"end" | non-negative integer"end"在结束时或每隔 N 轮投票。
voteVisibility"aggregate" | "ballots""aggregate"在记录中仅包含票数总计,或同时包含匿名化的投票选项。
allowSelfVotebooleantrue在每位投票者的候选项列表中包含其自身席位。
voteByTeambooleanfalse为每个 @team 提供一个选项,并按团队汇总投票。

角色对象键:

键类型默认值描述
rolestring必填用于 model:role 选择器的角色名称。
descriptionstring | string[]对应的角色文件内联指令;数组会以换行符连接。否则必须存在 config/roles/<role>.md。
min非负整数1最少发言者人数;0 表示该角色可选。
max正整数或 null1最多发言者人数;null 表示不限人数。
maxTokens正整数8192调用方未提供 maxTokens 时,该角色的输出上限。调用方显式指定的值会覆盖所有角色,包括中立角色。包含隐藏推理。
silentbooleanfalse允许该角色在常规轮次中旁听和投票,但不发言。
voterboolean所有符合条件的角色如果有任何角色被标记,则仅允许标记的角色匿名投票。
candidateboolean所有符合条件的角色如果有任何角色被标记,则仅将标记的角色列为投票选项。
closingboolean所有符合条件的角色仅允许标记的角色进行总结陈词;每个团队或无团队归属的角色中,只有首位被标记的发言者进行总结陈词。
closingLastbooleanfalse在并行总结陈词之后,由该角色发言,且其上下文包含这些陈词;要求设置 closing: true。
tagTeambooleanfalse每个 @team 轮换一名被标记的发言者参与每个常规轮次。不能与 enterEvery 同时使用。
cameobooleanfalse仅在一轮发言——即调用的 cameoRound 指定的轮次,否则为中间轮次——而非每轮发言。属于临时客串,而非常驻角色。

例如,法庭辩论调用会使用 @team 标签为双方分配律师。每方列出的第一位律师代表该方作总结陈词:

{
   "models": [
      "gpt:lawyer@prosecution",
      "grok:lawyer@prosecution",
      "claude:lawyer@defense",
      "kimi:juror",
      "llama:juror",
      "mistral:juror",
      "opus:judge"
   ],
   "objectives": {
      "prosecution": "Prove liability.",
      "defense": "Defeat liability."
   }
}
编写说明

编写预设时需要注意的事项:

  • 淘汰时必须使用准确标签。 裁判从可选菜单中复制一条 CUT <label> 命令,然后在下一行给出理由。可选淘汰也允许使用 KEEP ALL。只写数字或选择含糊不清都会被拒绝。本地淘汰提示词覆盖项必须使用此命令格式。
  • 必需淘汰可能会停滞。 有限次数的清理重试无法保证只剩一名胜者。若运行未能解决,将保留其摘要和讨论,但返回 isError: true 和包含剩余标签的 structuredContent.incomplete。可选淘汰竞赛不受此要求约束。
  • min/max 统计该角色下的所有发言者,而非每队人数。 它们限制的是所有队伍中该角色的人数总和。因此,必须涵盖 2v2 至 6v6 阵营的 tag-team wrestler 角色应设置为 min: 4, max: 12;3v3 只是此范围内的一种有效人员配置(6 名摔跤手),并非其自身的 max: 3。引擎无法强制执行“双方人数相等”或“每方一人”,请改为在 description 中说明。
  • 中立角色不能加入队伍。 eliminator、framer 和单席位的 synthesizer 不接受 @team 标签,因此,属于某一方的角色不能担任这些职务。
  • 某些键需要搭配其他键使用,违反要求会在加载时被捕获:synthesizeEvery 需要 synthesizer,eliminateEvery 需要 eliminator,reframeEvery 需要 framer,closingLast 需要 closing,投票选项需要 vote,而单席位的 synthesizer 至少需要另一个必需角色(它不会参与常规轮次)。 enterEvery 和 tagTeam 不能同时使用,因为两者都会决定谁发言。
  • 格式错误的预设会被跳过,不会导致致命错误。 系统会记录 ❌ preset skipped — Invalid <file>: <reason>,其他所有工具仍会注册,因此,如果某个预设工具没有出现,请检查服务日志。
  • 成本按 speakers × rounds 次串行模型调用计算,因此 defaultRounds 和较大的 max 会让成本迅速增加。mode: "parallel" 会让每轮的耗时取决于最慢的发言者,但代价是发言者在同一轮内无法看到彼此。

此代码库附带以下预设,可随意编辑或删除:

battle_royale
自由混战;由监督者选出获胜者。
brainstorm
跨模型发散式创意生成。
bullying
一个模型为某个立场辩护,其余模型群起攻之;可选的教师会裁定它是否站得住脚。
code_review
结构化的多模型代码审查。
courtroom
标记团队的律师分别为对立双方辩护,陪审员按立场投票,法官作出裁决。
debate
对立双方围绕某个问题展开辩论,最终综合出结论。
double_blind
独立盲审小组——任何人都看不到其他人的内容。
election
候选人展开竞选,随后由全体成员进行无记名投票——匿名投票即为裁决,而非由法官决定。可选的 incumbent 为过往表现辩护;可选的沉默 electorate 会阅读每一轮内容并投票,但不参与竞选。
final_girl
每轮淘汰一名幸存者,直到只剩一人。
focus_group
由主持人引导、成员相互启发的讨论小组。
gauntlet
跨轮次进行的私下自我完善竞赛。
quick_take
快速的双声部直觉评估——一个给出直接回答,另一个提出一句反驳。
refine
接力润色现有成果。
tag_team
双打比赛:每轮每支队伍中只有一名标记为 @team 的摔跤手可以上场,其余成员在场边等候;每轮轮换,因此三人一方会轮流派上全部三人。可选的 run_in 会在单轮中闯入擂台(通过 cameoRound 安排),可选的 announcer 会解说比赛,ref 则宣布获胜队伍。
tiebreak
由具有决定性的一票解决僵局。
war_games
分批入场的团队笼斗:标记为 @team 的参赛者逐一入场,中立裁判判定犯规并宣布获胜队伍;也可选配负责安排比赛的 booker。
workshop
分工明确的创意团队。

哪些内置预设会注册为工具,由 PRESETS 控制——未设置时会全部注册;而你在自己的 config/presets/ 下添加的仅本地预设(即没有对应内置版本的标识名)无论如何都会注册,因为编写预设本身就代表选择启用。使用内置标识名的本地文件是对该预设的自定义,而非新预设,因此仍受 PRESETS 控制。如果没有内置预设,也没有本地预设,就不会有预设工具——不过请注意,内置预设是基础层,因此即使你没有随项目附带自己的 config/presets/ 文件夹,也会获得所有内置预设。

角色文本会引导输出,但不会限制输出长度——如需硬性限制每轮输出,请使用 maxTokens;对于推理模型和多轮法定人数,请预留充足预算。tokenBudget 是另一个维度:它会统计整个运行中每次调用的输入 和输出,因此应根据 turns × (context + maxTokens) 估算,并将其设得高于估算值——随着对话记录增长,输入会占据大部分用量。

AI 指引——config/description.md

可选的 Markdown 文档,会作为 MCP instructions 提供给客户端——介绍你的 模型,以及 AI 应在何时使用各个模型。模板请参阅本仓库中的副本。字面标记 {longRuns} 会根据 ASYNC_TOOLS 的设置替换为 config/sync/long-runs.md 或 config/async/long-runs.md,因此交付指引(阻塞并等待,或启动/轮询/取消)会随模式变化, 而无需重复文件的其余内容。若本地 description.md 不包含该标记,则会按原样提供;启动时会发出警告,提示缺少模式指引。

工具、字段和消息文本——config/*.json 和 config/tools/*.md

调用方读取并用于驱动 Legion 的文本——工具和字段描述、提示词框架、运行时错误——位于配置中,而不在代码中。(outputSchema 中的结果结构描述、生成的 staffing 行以及启动错误仍保留在代码中。)每个文件都会按键合并到内置 JSON 基础配置上,因此只需覆盖所需内容;打开随附文件即可查看完整键集合和 {token} 占位符:

  • config/tools/quorum.md、poll.md、cancel.md——quorum 工具以及(仅异步模式下)poll / cancel 工具的描述。删除其中一个文件即可回退到内置字符串。模型工具使用其模型文件中的 description 来描述自身,预设工具则使用预设自身的描述。
  • config/sync/long-runs.md、config/async/long-runs.md——按模式区分的内容块,会在 {longRuns} 处插入 description.md。
  • config/schema.json——输入字段描述(prompt = 共享字段,quorum = 仅限 quorum;名称冲突时以 quorum 键为准)。
  • config/prompts.json——模型读取的提示词构造模板:角色约定、上下文块、记录标题、轮次横幅。可在此调整角色约束的强度和轮次的呈现方式。
  • config/errors.json——显示给调用 AI 的运行时错误消息。

(启动/配置验证错误仍保留在代码中——报告配置文件损坏的消息不可能放在该文件本身中。)

环境变量
变量必需描述
DEFAULT_BASE_URL否*对于没有 baseUrl 的模型,其 API 根路径 — SDK 会附加 /responses。例如:https://api.openai.com/v1、https://<res>.openai.azure.com/openai/v1;LiteLLM 代理可使用其纯根路径。
DEFAULT_API_KEY否*对于没有 apiKey 的模型,其 API 密钥。密钥仅保留在服务端。
ALLOW_NO_MODELS否true 表示即使不存在模型文件也启动:不提供任何模型工具;quorum 和预设工具仍会注册,但在 config/models/*.json 文件出现之前无法使用(每次请求时热重载)。适用于只需列出工具的演示和注册表沙盒。默认值为 false — 缺少模型仍会导致启动失败。
MCP_TRANSPORT否http(默认值)或 stdio。
HOST否HTTP 绑定地址(默认值为 127.0.0.1)。设为 0.0.0.0 可对外提供服务 — 此时应设置 ALLOWED_HOSTS。
ALLOWED_HOSTS否用逗号分隔的主机名,用于保护非 localhost 绑定免受 DNS 重绑定攻击。
PORT否HTTP 端口(默认值为 5000;stdio 模式下忽略)。
MAX_ROUNDS否quorum 工具接受的最大讨论轮数(默认值为 5)。
MAX_TOKENS否每轮调用方可请求的最大可见 maxTokens;超出此值的请求将被拒绝(默认值为 3000)。超出此值的预设角色限制会被截断至此值。每个模型的推理额度会在此基础上额外增加。
MODEL_TIMEOUT否每次模型调用的超时时间,单位为毫秒(默认值为 90000),因此一个卡住的席位不会拖住整个议会。失败后会重试一次,因此席位在轮次失败前的最坏情况耗时大约会翻倍。
TOKEN_BUDGET否quorum 运行的默认软性累计令牌预算(未设置 = 无限制;单次调用的 tokenBudget 会覆盖此值)。
DYNAMIC_ROLES否允许调用方 AI 在行内定义临时 quorum 角色(默认值为 true)。
PRESETS否以逗号分隔的允许列表,指定要注册为工具的内置预设 slug(例如 code_review,debate)。未设置 = 注册所有内置预设,因此升级不会悄悄移除任何预设;已设置 = 仅注册所列预设,因此新发布的内置预设不会在未经允许时出现。你在自己的 config/presets/ 下添加的预设始终会注册 — 编写预设即表示选择启用;而与内置预设 slug 相同的本地文件会自定义该预设,但仍受此列表约束。未知名称会被忽略。
LOG_LEVEL否debug | info | warn | error(默认值为 info)。
ASYNC_TOOLS否true 表示在后台运行议会:quorum 和预设工具会立即返回作业句柄,并开放 poll / cancel 工具。适用于工具调用会在议会完成前超时的宿主。作业仅保存在此进程的内存中。默认值为 false。
TRUST_PROXY_AUTH否true 表示将每个作业绑定到由 X-MS-CLIENT-PRINCIPAL-* 标头指定的调用方(Azure Container Apps Easy Auth)。仅可在会移除客户端所提供副本的入口后安全使用。默认值为 false — 任何持有 jobId 的人都可以轮询或取消作业。
JOB_MAX_ACTIVE / JOB_MAX_RETAINED / JOB_RETAIN_MS / JOB_POLL_INTERVAL_MS / JOB_SHUTDOWN_GRACE_MS否异步作业限制:并发议会数(3)、保留的已完成作业数(20)、保留时长(1800000 毫秒)、建议的轮询间隔(10000 毫秒)、SIGTERM 排空时长(20000 毫秒)。

* 每个模型都必须从其文件或默认值中解析出 baseUrl 和 apiKey — 并在启动时进行验证。

模型目录缺失或为空(除非 ALLOW_NO_MODELS=true)、模型文件无效、无法解析端点或密钥,或者两个文件名 slug 化后对应同一工具时,服务会在启动时立即失败。

路由

每次工具调用都是无状态、仅执行一次的 Responses API 请求。原生支持 Responses 的模型端点(OpenAI、Azure OpenAI / Foundry)会将 baseUrl 设为直接调用;其余模型则回退到默认值 — 通常是 LiteLLM 这类可桥接至原生 API 的 OpenAI 兼容网关。

日志记录

  • info(蓝色):服务器启动信息,以及每次模型调用的一行元数据——模型、延迟、令牌用量、角色、上下文是否存在。不包含提示词或响应内容。
  • debug(灰色):此外还会记录完整的提示词和响应(会标明上下文是否存在,但不会打印上下文内容)。
  • warn(橙色)/error(红色):回退和故障。

当标准错误输出不是 TTY 时,会自动禁用颜色。

运行

仅有一个入口点;传输方式由 MCP_TRANSPORT 决定(默认值为 http,桌面 MCP 客户端请设置为 stdio)。

从 npm 运行(legion-mcp 可执行文件——请在包含 config/ 的目录中运行):

npx legion-mcp                             # Streamable HTTP transport on :$PORT/mcp
$env:MCP_TRANSPORT='stdio'; npx legion-mcp # stdio transport

全局安装或作为依赖安装后,可通过 PATH 使用同一个可执行文件:

npm install -g legion-mcp
legion-mcp

开发模式(无需构建步骤,通过 tsx 运行):

npm run dev         # Streamable HTTP transport on :$PORT/mcp
npm run dev:stdio   # stdio transport

生产模式(编译至 bin/server.js):

npm run build
npm start           # http
npm run start:stdio # stdio
异步模式 — ASYNC_TOOLS=true

一次议会运行可能需要数分钟;托管版 ChatGPT 和 Codex 远早于此时就会放弃工具调用(观察到约 124 秒;Codex 默认超时为 60 秒)。启用 ASYNC_TOOLS=true 后,quorum 和预设工具会验证请求,在后台启动议会,并立即返回一个句柄,其中包含 structuredContent.jobId、当前的 state/phase,以及建议的 pollIntervalMs。此时会额外提供两个工具:

  • poll — 只读;返回任务状态、截至目前已完成的答案和公开备注,以及(任务结束后)result:完整的议会输出,格式与通常相同。full: true 会添加渲染后的转录和时间线。
  • cancel — 中止正在进行的模型调用,返回已完成的内容,并将任务结束状态设为 cancelled,不进行综合。可重复调用。

各个模型工具仍保持同步。服务器的 instructions 会切换为启动/轮询/取消工作流,以便调用模型了解后续操作。任务保存在进程内存中,并受 JOB_* 上限控制——重启会丢失任务,而路由到其他副本的请求也无法访问这些任务,因此启用此模式时请运行单个实例(或固定会话路由)。在 Azure Container Apps Easy Auth 后方运行时,设置 TRUST_PROXY_AUTH=true,将每个任务绑定到经过身份验证的调用者;否则,持有 jobId 即是唯一的访问控制方式。

试用

使用 MCP Inspector 列出工具:

npx @modelcontextprotocol/inspector -e MCP_TRANSPORT=stdio npx tsx ts/server.ts

在 VS Code 中使用

将以下内容添加到 mcp.json — 从 npm 安装:

{
   "servers": {
      "legion": {
         "command": "npx",
         "args": ["-y", "legion-mcp"],
         "cwd": "path/to/your/config/parent",
         "env": {
            "MCP_TRANSPORT": "stdio",
            "DEFAULT_BASE_URL": "https://your-gateway.example.com",
            "DEFAULT_API_KEY": "sk-your-key"
         }
      }
   }
}

或者从克隆的仓库安装:

{
   "servers": {
      "legion": {
         "command": "node",
         "args": ["bin/server.js"],
         "cwd": "path/to/legion",
         "env": {
            "MCP_TRANSPORT": "stdio",
            "DEFAULT_BASE_URL": "https://your-gateway.example.com",
            "DEFAULT_API_KEY": "sk-your-key"
         }
      }
   }
}

对于 HTTP 传输,请将客户端指向 http://<host>:<PORT>/mcp。

健康检查
  • GET /health — 轻量级的存活状态检查:确认进程正在运行且配置已加载。返回 { status: "ok", name, version, models }(数量)。不会发起外部调用。容器 HEALTHCHECK 和 Kubernetes 存活/就绪探针应访问此端点。
  • GET /health?deep — 可选的连通性检查:向每个模型发送一条简短提示词,并报告各模型的可访问性(若任一模型失败则返回 503)。每个模型都会产生一次真实的计费调用,因此请手动使用——不要将其接入自动探针。

部署

可直接使用的容器部署示例(Azure App Service、Azure Container Apps、Docker Compose、Kubernetes,以及用于 HTTPS 的 Compose + Caddy)位于 examples/ 中——每个示例都会从 npm 安装 Legion,并附带一套完整的即插即用 config/。

评论

支持 Markdown

第一次接触 MCP?

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

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