model-council-mcp
Routes questions to multiple AI models (local and cloud) and synthesizes their answers in individual, categorized, or deconflicted modes.
README
model-council-mcp
An MCP server that routes a question to a council of AI models — local (Ollama, vLLM, TRT-LLM, SGLang) and cloud (OpenAI, Anthropic, Groq) — and synthesizes their answers in three configurable modes:
| Mode | What you get |
|---|---|
individual |
Each model's raw answer, side by side |
categorized |
Judge groups responses into common agreement, complementary insights, and conflicting positions |
deconflicted |
Iterative loop — judge re-questions the council on each conflict until resolved or rounds exhausted; returns a deconfliction score (0–100 %) |
Install as a Claude Code plugin (recommended)
This repo is a self-contained Claude Code plugin — the server is bundled into a single zero-dependency file (bundle/server.cjs), so it runs offline against local models with no npm install step.
# 1. Add this repo as a marketplace (from GitHub)
/plugin marketplace add tsarihan/model-council-mcp
# 2. Install the plugin
/plugin install model-council@model-council
Zero-config: accept the defaults and it just works. With no council models pinned, the council auto-uses every local Ollama model plus your Ollama :cloud models (embedding models like bge-m3 are skipped). The judge auto-selects your largest model. Ask a question immediately — no setup.
On install, Claude Code prompts you for the (all-optional) configurable options — Ollama address, whether to pin specific council models, API keys, default mode, deconfliction rounds. Nothing is required. API keys are stored in your system keychain. Change settings any time from /plugin → Configure.
Local development / test install:
# Validate the manifest
claude plugin validate .
# Load without installing (dev loop)
claude --plugin-dir /path/to/model-council-mcp
Configurable options (prompted at install)
| Option | Purpose | Default |
|---|---|---|
| Ollama address | Base URL of your Ollama server | http://localhost:11434 |
| Council models | Pin specific models, or leave blank to auto-use all Ollama models | (empty → auto) |
| Auto-discover council | Use all Ollama chat models (local + :cloud) when none pinned |
true |
| Judge model | Categorizer/deconflicter, or auto (largest) |
auto |
| Default response mode | individual / categorized / deconflicted |
categorized |
| Max deconfliction rounds | 1–10 | 3 |
| OpenAI / Anthropic / Groq API key | Enable cloud models (stored in keychain) | — |
| vLLM / TRT-LLM / SGLang servers | name:host:port entries |
— |
| Max response tokens | Tokens per completion | 16000 |
| Cloud / local concurrency | Simultaneous requests (cloud pool / local pool) | 3 / 1 |
| Completion retries | Retries on an empty/failed response | 3 |
| Verbose deconfliction | Include per-round detail in deconflicted results | false |
| Claude subscription (CLI) | Use your Claude Pro/Max subscription via claude -p (no API key) |
false |
Install as a standalone MCP server (npm)
# Quick try
npx model-council-mcp
# Add to Claude Code
claude mcp add model-council-mcp -s user -- npx -y model-council-mcp
Or add to ~/.claude.json → mcpServers:
{
"mcpServers": {
"model-council": {
"command": "npx",
"args": ["-y", "model-council-mcp"],
"env": {
"OLLAMA_ADDRESS": "http://localhost:11434",
"COUNCIL_MODELS": "ollama:llama3,ollama:mistral",
"RESPONSE_MODE": "categorized"
}
}
}
}
Configuration (environment variables)
Provider connections
| Variable | Description | Default |
|---|---|---|
OLLAMA_ADDRESS |
Ollama server URL | http://localhost:11434 |
OPENAI_API_KEY |
Enables OpenAI models | — |
ANTHROPIC_API_KEY |
Enables Anthropic Claude models | — |
GROQ_API_KEY |
Enables Groq models | — |
VLLM_SERVERS |
vLLM servers (see below) | — |
TRTLLM_SERVERS |
TRT-LLM servers | — |
SGLANG_SERVERS |
SGLang servers | — |
CLAUDE_CLI |
true → add subscription-backed Claude members via the local claude CLI (no API key) |
false |
CLAUDE_CLI_MODELS |
Model aliases for the CLI member | opus,sonnet |
CLAUDE_CLI_PATH |
Path to the claude binary |
claude |
Claude via your subscription (first-party CLI)
Set CLAUDE_CLI=true to add council members that run through the locally-installed Claude Code CLI (claude -p) instead of the Anthropic API. Inference runs under whatever your claude CLI is logged in with — typically your own Claude Pro/Max subscription — so these members don't consume API credits. They appear as claude-cli:opus, claude-cli:sonnet, etc.
Behavior & requirements
- The
claudeCLI must be installed and logged in (claude→/login, orclaude setup-token). SetCLAUDE_CLI_PATHif it isn't onPATH. - Each call shells out to
claude -pwith all tools disabled (--tools ""), MCP disabled (--strict-mcp-config, so it can't recurse into this plugin), and sessions not persisted — a clean single text answer. ANTHROPIC_API_KEY/ANTHROPIC_AUTH_TOKENare stripped from the nested call, because the CLI silently prefers an API key over the subscription. So these members stay subscription-billed even if you also set an API key for the regularanthropic:provider.- They are not auto-discovered — add them explicitly via
configure_councilorCOUNCIL_MODELS(e.g.claude-cli:opus), so they don't quietly draw down your subscription.
Where it works: anywhere the claude CLI actually executes — the Claude Code CLI, or the Claude Desktop app on a machine that also has the CLI. With /remote-control on your CLI, driving it from the Claude web/mobile code tab still runs claude -p on your machine, so it works there too. It does not work for a remotely-hosted copy of this server (no local CLI), and it can't borrow the Claude app's subscription directly (no client supports MCP sampling yet).
This uses the sanctioned first-party CLI under your own subscription, for your own use. High-volume automated fan-out can hit your subscription's rate limits — keep
CLOUD_CONCURRENCYmodest (these members use the cloud pool). Reusing a subscription token against the raw Anthropic API from a third-party app is a separate thing and is prohibited; this feature does not do that.
OpenAI-compatible server format
Comma-separated list of name:host:port entries.
You can run multiple servers on different ports (e.g. different models on the same GPU host):
VLLM_SERVERS=gpu1:192.168.1.10:8000,gpu2:192.168.1.10:8001
TRTLLM_SERVERS=trt-main:192.168.1.20:8000
SGLANG_SERVERS=sgl1:192.168.1.30:30000
Full URLs also work: gpu3:http://10.0.0.5:9000
Default ports: vLLM → 8000, TRT-LLM → 8000, SGLang → 30000
Council defaults
| Variable | Description | Default |
|---|---|---|
COUNCIL_MODELS |
Comma-separated model IDs | (empty — use configure_council) |
JUDGE_MODEL |
Judge model ID or auto |
auto (largest council member) |
RESPONSE_MODE |
individual | categorized | deconflicted |
categorized |
MAX_DECONFLICT_ROUNDS |
Max deconfliction iterations | 3 |
Performance & output
| Variable | Description | Default |
|---|---|---|
MAX_TOKENS |
Max tokens requested per model completion | 16000 |
CLOUD_CONCURRENCY |
Max simultaneous requests to cloud members (Ollama cloud :cloud/-cloud, OpenAI, Anthropic, Groq). Ollama cloud needs Pro (3 concurrent) or Max (10) |
3 |
LOCAL_CONCURRENCY |
Max simultaneous requests to local models; 1 runs them one at a time to avoid contention, 0 = unlimited |
1 |
COMPLETION_RETRIES |
Attempts per completion before giving up on an empty/failed response | 3 |
DECONFLICT_VERBOSE |
true → deconflicted results include per-round detail by default |
false |
The council queries members in parallel but respects these concurrency limits — cloud members share one pool and local members another, so a large council never exceeds your Ollama cloud plan's concurrent-request cap, and local models can be run sequentially to avoid GPU contention.
Model ID format
provider:model
provider/serverId:model ← for named multi-server setups
Examples:
ollama:llama3
ollama:mistral:7b-instruct-q4_K_M
openai:gpt-4o
openai:o1-mini
anthropic:claude-opus-4-5
groq:llama-3.3-70b-versatile
vllm/gpu1:meta-llama/Meta-Llama-3-8B-Instruct
trtllm/trt-main:mistralai/Mistral-7B-v0.1
sglang/sgl1:deepseek-ai/DeepSeek-R1
MCP Tools
list_models
Discover all models across every configured provider.
{ "filter_provider": "ollama" }
Returns model IDs, parameter size, family, disk size — everything you need to fill configure_council.
configure_council
Update the council at runtime (changes persist for the session).
{
"models": ["ollama:llama3", "ollama:mistral", "openai:gpt-4o"],
"judge_model": "openai:gpt-4o",
"response_mode": "deconflicted",
"max_deconflict_rounds": 4
}
All fields are optional — only supplied fields are updated.
ask_council
Send a question to the full council.
{
"question": "What is the best way to handle errors in a distributed system?",
"mode": "deconflicted",
"max_deconflict_rounds": 3
}
mode and max_deconflict_rounds override the configured defaults for this call only. In deconflicted mode, set "verbose": true to include the initial categorization, every member's per-round responses, and the round-by-round re-categorization alongside the final synthesis.
Individual result
{
"mode": "individual",
"question": "...",
"responses": [
{ "label": "ollama:llama3", "response": "...", "latencyMs": 1240 },
{ "label": "openai:gpt-4o", "response": "...", "latencyMs": 843 }
]
}
Categorized result
{
"mode": "categorized",
"question": "...",
"commonAgreement": "All models agree that ...",
"complementary": [
{ "aspect": "performance", "models": ["ollama:llama3"], "insight": "..." }
],
"conflicting": [
{
"id": "conflict-1",
"topic": "retry strategy",
"positions": [
{ "models": ["ollama:llama3"], "position": "exponential backoff" },
{ "models": ["openai:gpt-4o"], "position": "circuit breaker preferred" }
]
}
],
"judgeModel": "openai:gpt-4o"
}
Deconflicted result
{
"mode": "deconflicted",
"question": "...",
"roundsTaken": 2,
"maxRounds": 3,
"deconflictionScore": 75,
"resolved": 3,
"totalConflicts": 4,
"finalSynthesis": "The council recommends ...",
"unresolvedConflicts": [ { "id": "conflict-3", "topic": "...", "positions": [...] } ],
"roundHistory": [
{ "round": 1, "conflictsEntering": 4, "conflictsResolved": 2, "conflictsRemaining": 2 },
{ "round": 2, "conflictsEntering": 2, "conflictsResolved": 1, "conflictsRemaining": 1 }
],
"judgeModel": "openai:gpt-4o"
}
Deconfliction score: resolved / totalConflicts × 100.
100 % means all conflicts resolved; n/m means n conflicts resolved out of m found.
get_council_config
Returns current council settings plus all configured provider connections and the full env-var reference.
Deconfliction algorithm
1. Query all council members in parallel → N raw responses
2. Judge model categorises → common / complementary / M conflicts
3. If M = 0 → synthesise final answer, score = 100 %
4. For each round r in 1..maxRounds:
a. Ask all members specifically about each open conflict
b. Judge re-categorises conflict responses
c. Conflicts where positions converge → marked resolved
d. If no conflicts remain → break
5. Score = resolvedCount / M × 100
6. Judge synthesises final answer, noting any unresolved conflicts
Example: full multi-provider setup
{
"mcpServers": {
"model-council": {
"command": "npx",
"args": ["-y", "model-council-mcp"],
"env": {
"OLLAMA_ADDRESS": "http://localhost:11434",
"OPENAI_API_KEY": "sk-...",
"ANTHROPIC_API_KEY": "sk-ant-...",
"GROQ_API_KEY": "gsk_...",
"VLLM_SERVERS": "gpu1:192.168.1.10:8000,gpu2:192.168.1.10:8001",
"SGLANG_SERVERS": "sgl1:192.168.1.30:30000",
"COUNCIL_MODELS": "ollama:llama3,ollama:mistral,openai:gpt-4o,anthropic:claude-sonnet-4-5,groq:llama-3.3-70b-versatile",
"JUDGE_MODEL": "anthropic:claude-opus-4-5",
"RESPONSE_MODE": "deconflicted",
"MAX_DECONFLICT_ROUNDS": "3"
}
}
}
}
Background
The council's value comes from decorrelation: routing a question to independent models from different families and providers surfaces systematic biases and blind spots that any single model — or a set of correlated ones — would hide. The categorized and deconflicted modes make that disagreement explicit and then work to resolve it.
This design is informed by The Mirror Law, which shows that a learner trained against a single reference reproduces that reference's error field — so the bias is invisible from the loss curve alone, and a decorrelated second reference is what makes the hidden bias observable.
Sarihan, Tom. The Mirror Law: Reference Quality and the Transfer of Systematic Bias in Imitation and Distillation. Preprint, 2026. DOI: 10.5281/zenodo.21282027. Code and materials: github.com/tsarihan/MirrorLaw.
@article{sarihan2026mirror,
title = {The Mirror Law: Reference Quality and the Transfer of Systematic Bias in Imitation and Distillation},
author = {Sarihan, Tom},
year = {2026},
doi = {10.5281/zenodo.21282027},
note = {Preprint}
}
License
Apache License 2.0 — Copyright (c) 2026 Tom Sarihan. See LICENSE and NOTICE.
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.