Legion MCP
About
MCP-native LLM councils for debates, juries, blind panels, voting, refinement, and highly customizable multi-model deliberation.
Details
- Author
- faulkj
- Categories
- Productivity, AI
Jump to
Setup
Install Legion MCP in your MCP client (Claude Desktop, Cursor, Windsurf, and others).
Repository: https://github.com/faulkj/legion-mcp
Follow the installation instructions in the repository README, then restart your MCP client.
"I am Legion, for we are many."
Every model is reached through the OpenAIResponses APIwire format. Use OpenAI or Azure directly, route other providers through a compatible gateway (such as aLiteLLMproxy), and configure the entire council through hot-reloadable files.
- How it works
- Design decisions
- Requirements
- Setup
- Configuration
- Logging
- Run
- Try it
- Use in VS Code
- Deploy
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
- One tool per model, named after the slugified model name (e.g.Claude→claude). Each accepts apromptplus optionalcontext,role,system,temperature, andmaxTokens.
- Aquorumtoolfans one prompt out to several models — with roles, multi-round discussion, visibility modes, and synthesis — and returns each answer separately. SeePresetsfor the orchestration options.
- Presetsare named, pre-staffed councils (debate, courtroom, code review, …), each exposed as its own tool.
- Identity and telemetry ride instructuredContent, not the answer text. Logging goes tostderr(safe for stdio).
- No provider adapters.There is no provider-specific code and no built-in model list. Legion speaks one wire format; models that don't speak it natively go through a gateway. Supporting a new model requires no change here.
- Models are config, not code.Adding a model means adding a JSON file. The directory is re-read per request, so no rebuild or restart.
- One tool per model.Each model appears to the calling AI as its own tool with its own description, rather than a single tool with a model parameter. Thequorumtool covers the ad-hoc multi-model case, and each preset inconfig/presets/is exposed as its own enforced, pre-staffed council tool.
- Stateless.Every call is one-shot withstore: false. Nothing is persisted, so there is no database and no conversation state to manage.
- Small.A few hundred lines of TypeScript, one bundled output file, six dependencies.
- Node.js 24+
- At least one OpenAI-Responses-compatible endpoint (a provider API directly, or a gateway such as LiteLLM for models that need bridging)
npm install copy .env.example .env # then edit .env
All configuration lives in aconfig/directory. The bundled defaults arealways the base layer; aconfig/folder in the current working directory isoverlaid on top of them, per file:
- Directory resources(models/,roles/,presets/,tools/): a local file overrides the bundled file of the same name; a local-only file is added; every bundled file you don't touch stays. So dropping in oneconfig/presets/refine.jsonoverrides just that preset — the other bundled presets remain.
- Single-file text(prompts.json,errors.json,schema.json): mergedper key— bundled < local. A partial local file overrides only the keys it sets.
- description.md: local wins whole if present, else bundled.
The overlay canoverride or add, but not delete a bundled entry. To turn off bundled presets you don't want, useDISABLE_PRESETS(see below).
Installing from npm? You must supply your own model files.The bundled config ships only key-free.example.jsonmodel files, which the scanner deliberately ignores — so the bundle contributeszeroreal models. With no real model file the serverfails fast at startup(No model files found in ...). Drop oneconfig/models/<name>.jsonnext to where you run the server (see below) — the rest falls back to the bundled defaults.
The layout below is identical either way, and everything hot-reloads per request.
At least one model file isrequired— the server fails fast without one. Each JSON file becomes a tool, named after the slugified file name (config/models/fable.json→ toolfable):
{ "model": "claude-fable-5", "description": "Claude Fable — fast, creative, general purpose.", "baseUrl": "https://api.example.com", "apiKey": "sk-optional-per-model-key" }
- model(required) — the deployed model id the endpoint routes to.
- description— helps the calling AI pick the right model.
- system— optional baseline system instructions baked into every call to this model.
- baseUrl/apiKey— optional; omitted values fall back toDEFAULT_BASE_URL/DEFAULT_API_KEY.
- omitParams— optional list of request params to drop for this model, e.g.["temperature"]. The server stays provider-agnostic: it never assumes which models reject which params — you declare each model's quirks here. Useful for reasoning models and some deployments that rejecttemperature.
Hot-drop:the directory is re-scanned per request — add or edit a model file and it's live on the next call, no restart.
Secrets & git:model files can contain API keys, soconfig/models/.jsonis git-ignored. Copy a.example.json(tracked, key-free, ignored by the scanner) to get started:
copy config\models\gpt.example.json config\models\gpt.json # then add your key
Optional hot-droppable instruction files. Each.mdfile becomes a named role (slugified from filename). Drop a file, it's live on the next call. This repo shipsskeptic.md,builder.md,judge.md, andshort.md(a terse "answer immediately, no deliberation" role useful for constrained-output turns) as ready-to-use starters — edit or delete them freely (they hold no secrets).
Available selectors in tools becomeroleName, e.g. passingrole: "skeptic"or using"model:skeptic"inquorum.models.
Optional hot-droppablecouncil recipes, one JSON file per preset (named after the slugified file name, like models).Each preset becomes its own tool— dropconfig/presets/code_review.jsonand acode_reviewtool appears on the next request. Each preset has adescription, aroleslist, and optional authoritativemode/synthesizerdefaults. Each role defines its behaviorinline— a role'sdescriptionisits instructions (the behavior contract); a role with nodescriptionfalls back to a matchingconfig/roles/<role>.mdfile:
{ "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 } ] }
The calling AI invokes the preset tool directly (e.g.code_review) and still writes themodelsselectors, assigning any model to any preset role. Presets areenforced: every selector must use a preset role and every role must be staffed within its cardinality, else the result is an error saying what to fix.
For example, a courtroom call assigns lawyers to sides with@teamtags. The first lawyer listed for each side gives that side's closing statement:
{ "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." } }
This repo ships these presets — edit or delete freely:
Role text nudges output, it doesn't cap it— usemaxTokensfor a hard limit, and budget generously for reasoning models and multi-round quorums.
Optional markdown served to clients as MCPinstructions— describe your models and when the AI should use each. See this repo's copy for a template.
Tool, field & message text —config/.jsonandconfig/tools/.md
All user-facing text lives in config, not code, and hot-reloads per request. Each file merges over the bundled JSON base per key, so override only what you want; open the shipped copies to see the full key set and{token}placeholders:
- config/tools/<tool>.md— a tool's description (e.g.quorum.md). Delete to fall back to the built-in string.
- config/schema.json— input-field descriptions (prompt= shared fields,quorum= quorum-only; aquorumkey wins on a name clash).
- config/prompts.json— the prompt-shaping templates models read: role contract, context block, transcript header, round banners. Tune how strongly roles bind and how rounds are framed here.
- config/errors.json— runtime error messages shown to the calling AI.
(Startup/config-validation errors stay in code — a message that reports a broken config file can't live inside it.)
Every model must resolve abaseUrlandapiKeyfrom its file or the defaults — validated at startup.
The serverfails fastat startup on a missing/empty models directory, invalid model files, an unresolvable endpoint or key, or two file names that slugify to the same tool.
Every tool call is a stateless, one-shot Responses API request. Models whose endpoints natively speak Responses (OpenAI, Azure OpenAI / Foundry) set abaseUrlto be calleddirectly; the rest fall back to the defaults — typically an OpenAI-compatible gateway like LiteLLM that bridges to their native APIs.
- info(blue): server start and one metadata line per model call — model, latency, token usage, role, context presence. No prompt/response content.
- debug(gray): additionally logs the full prompt and response (context is noted as present, not printed).
- warn(orange) /error(red): fallbacks and failures.
Color is auto-disabled when stderr is not a TTY.
One entrypoint, transport as an argument (stdiois the default):
npm run dev # stdio transport npm run dev:http # Streamable HTTP transport on :$PORT/mcp
Production (compiled tobin/server.js):
npm run build npm start # node bin/server.js (stdio) npm run start:http # node bin/server.js http
npx @modelcontextprotocol/inspector npx tsx ts/server.ts
{ "servers": { "legion": { "command": "node", "args": ["bin/server.js"], "cwd": "path/to/legion", "env": { "DEFAULT_BASE_URL": "https://your-gateway.example.com", "DEFAULT_API_KEY": "sk-your-key" } } } }
For the HTTP transport, point your client athttp://<host>:<PORT>/mcp.
- GET /health— cheapliveness: confirms the process is up and config loaded. Returns{ status: "ok", name, version, models }(a count). Makes no external calls. This is what containerHEALTHCHECKs and Kubernetes liveness/readiness probes should hit.
- GET /health?deep— optionalconnectivitycheck: sends a tiny prompt to every model and reports per-model reachability (503if any fail). Makes a real billable call per model, so use it manually —don'twire it to an automatic probe.
Ready-to-use container deployment examples (Azure App Service, Azure Container Apps, Docker Compose, Kubernetes, and Compose + Caddy for HTTPS) live inexamples/— each installs Legion from npm and ships a complete drop-inconfig/.
Persistent memory for any AI assistant. Zero token cost until recall. Stores memories in local SQLite, ranks by 6-factor scoring, returns results 79% smaller than JSON. Works with Claude, ChatGPT, Grok, Cursor, Windsurf, and any MCP client.
An MCP server which brings Jotform to your AI client or LLM
After Effects MCP is a full-featured automation bridge that connects AI clients (like VS Code, Claude Desktop, and Claude Code) to Adobe After Effects through MCP, enabling scripted control of compositions, layers, effects, keyframes/graph easing, presets, markers, audio levels, waveform analysis, and effect discovery via a live bridge panel.
Project management your AI can actually run — connect Claude, ChatGPT, Cursor & Codex to one board over MCP.
Compare LLM cost & latency on one prompt, translate PDF keeping layout, cited research, make PPTX
AIOProductOS spine over MCP — customers, revenue, feedback, work, analytics on one typed record.
The memory layer for AI coding tools. Local-first, semantic, 9 MCP tools with consolidation and project scoping. Works with Claude Code, Cursor, Windsurf & any MCP client.
One MCP server for Claude, ChatGPT & Gemini — wraps your ERPs, CRMs, APIs and knowledge base into a single governed endpoint.
Run your field service business from Claude: answer calls, book and dispatch jobs, build estimates, chase invoices. Built for HVAC, plumbing, electrical, roofing and pest control.
Complete Swiss accounting integration for Bexio via MCP. Works with Claude Desktop, n8n, and any MCP client. 221 tools for invoices, contacts, projects & more.
Sign in to leave a review
Use Google, GitHub, or an email account so ratings stay tied to real people.
No reviews posted yet.

