LLMconcil

LLMconcil

Enables Claude Code to send a prompt to multiple LLMs simultaneously and get a judge model's structured comparison of their responses. This surfaces consensus, contradictions, and blind spots, letting Claude write a more informed final answer.

Category
访问服务器

README

LLMconcil

An MCP server that lets Claude Code ask several other models the same question, then hands back a structured comparison of what they said.

The idea is stolen from OpenRouter's Fusion, including the part most people get wrong: the second model does not merge the answers. It compares them and reports where they agree, where they contradict each other, and what none of them brought up. Claude writes the final answer from that. A merged answer hides which parts were unanimous and which came from one model having a bad day; a comparison doesn't.

Claude Code
   │  fusion_deliberate(prompt, context=[{path, lines}, ...])
   ▼
 panel ──┬─→ google/gemini-3.1-pro-preview   (+ Google Search grounding)
         ├─→ deepseek/deepseek-v4-pro
         ├─→ x-ai/grok-4.5
         └─→ minimax/minimax-m3
   │       four independent answers, in parallel
   ▼
 judge  ──→ moonshotai/kimi-k3
   │       { consensus, contradictions, partial_coverage,
   │         unique_insights, blind_spots }
   ▼
 Claude Code writes the final answer

Worth it for architecture trade-offs, "is this actually a good idea", library choices, anything where being confidently wrong is expensive. Not worth it for tactical questions with one right answer — you'd be paying four models to agree.

Setup

Needs Python 3.11+ and an OpenRouter API key. Everything else is optional.

git clone https://github.com/azeur365/LLMconcil
cd LLMconcil
python3 -m venv .venv && source .venv/bin/activate
pip install -e .
cp .env.example .env      # then fill in OPENROUTER_API_KEY

Register it with Claude Code:

claude mcp add llmconcil -- "$PWD/.venv/bin/llmconcil"

fusion_deliberate shows up as a tool from there.

The council

council.toml decides who sits on the panel and who judges. This is the shipped default, the one in the diagram above:

[[panel]]
model = "google/gemini-3.1-pro-preview"
search = true

[[panel]]
model = "deepseek/deepseek-v4-pro"

[[panel]]
model = "x-ai/grok-4.5"

[[panel]]
model = "minimax/minimax-m3"

[judge]
model = "moonshotai/kimi-k3"

model is an OpenRouter slug. The file is re-read on every call, so you can change the line-up without restarting the server.

Pick models that disagree: four siblings from the same lab produce four near-identical answers and a judge with nothing to report. And keep the judge's vendor off the panel. blind_spots only means something coming from a model that didn't answer the prompt itself.

search = true turns on Grounding with Google Search for that seat. It only works on the AI Studio path, so it needs a Gemini model and a GEMINI_API_KEY. On any other seat it does nothing, and a Gemini seat that falls back to OpenRouter answers without grounding.

That asymmetry is deliberate. OpenRouter has its own web plugin, and it is not wired up here: it bills per request, and on a model whose provider has no native search it substitutes a third-party engine. Losing citations on a fallback is a smaller problem than a config flag that quietly changes which search engine answered and what it cost.

Gemini and Google AI Studio

Everything runs on OpenRouter, with one exception you can opt into.

If GEMINI_API_KEY is set, Gemini panellists are sent to Google directly instead of through OpenRouter. Nothing else changes: same slug in council.toml, same model, same grounding mechanism, same shape coming back. But the calls come out of your Gemini quota, which matters if your subscription includes credit that OpenRouter can't spend.

Without the key, Gemini rides on OpenRouter like everything else.

The key has to have billing enabled. AI Studio's free tier won't serve the Pro models this is pointed at, so there's no free path to fall back to and the code doesn't pretend otherwise: AI Studio answers are reported as unpriced, never as free.

When the call doesn't land, for any reason, it falls back to OpenRouter rather than dropping the panellist. Quota exhaustion and "this model is experiencing high demand" are both routine, and neither is worth losing an answer over. meta.aistudio_fallbacks records what went wrong, so a key that never works shows up instead of quietly spending OpenRouter credit.

The judge always goes through OpenRouter. It needs response_format: json_schema, which isn't worth reproducing on the genai SDK (where it also can't be combined with grounding) to save a few cents.

meta.served_by tells you which backend actually answered for each model.

The tool

fusion_deliberate(prompt, context?, panel?, judge?, temperature?, reasoning_effort?)

context takes file refs ({path, lines}, read server-side), inline snippets ({text}), and images ({image}, png/jpg/gif/webp). Curate it. Everything you attach is sent to every panellist, so an irrelevant file costs you N times and dilutes the analysis. There's a 200k-token budget; over it the call is rejected with a message naming the offending files rather than silently truncating. Paths are confined to LLMCONCIL_ROOT, and binary or oversized (>5 MB) files are refused.

Attaching an image drops the panellists that can't see it, listed in meta.skipped_no_vision. Capability comes from OpenRouter's /models catalogue, fetched once and only when an image is attached. If that fetch fails, nothing is dropped and a text-only model fails on its own, visibly.

panel / judge override council.toml for one call. Both take bare slugs, so they carry no per-model options: a model named that way runs without search.

Returns {status, analysis, responses, failed_models, failure_reason, meta}. The raw panel answers come back alongside the analysis, so Claude can go read what a model actually said instead of trusting the judge's summary of it.

meta.cost_usd is what OpenRouter billed, read off the response rather than estimated from a price table. Calls it didn't bill (anything AI Studio served) are listed in meta.cost_excludes instead of being counted as free.

Here is analysis from a real run, asking whether a small team should pin exact dependency versions. Trimmed to one entry per key:

{
  "consensus": [
    "Pin exact versions, via a committed lockfile that freezes the full tree."
  ],
  "contradictions": [
    {
      "topic": "What should be declared in the manifest?",
      "stances": [
        {
          "model": "deepseek/deepseek-v4-pro",
          "stance": "Ranges. The lockfile does the actual pinning."
        },
        {
          "model": "x-ai/grok-4.5",
          "stance": "Exact versions, so intent survives someone deleting the lockfile."
        }
      ]
    }
  ]
}

That contradiction is the whole point. A merged answer would have picked one of those two and thrown the other away, and you would never have known the question was contested.

Configuration

Everything lives in .env, and everything but the first line has a default that works.

variable default what it does
OPENROUTER_API_KEY required; serves the whole council
GEMINI_API_KEY unset routes Gemini to AI Studio instead of OpenRouter
LLMCONCIL_COUNCIL ./council.toml where to read the line-up from
LLMCONCIL_ROOT working dir file refs outside this are rejected
LLMCONCIL_MAX_CONTEXT_TOKENS 200000 curation budget for attached context
LLMCONCIL_STALL_TIMEOUT 180 seconds of silence before a stream is killed
LLMCONCIL_JUDGE_CONTEXT_MAX 32000 above this, the judge doesn't re-read the context
LLMCONCIL_PROVIDER_SORT throughput OpenRouter provider routing; price, latency, none

Failure modes

A panellist that dies takes its own answer down and nothing else: it lands in failed_models with a reason and the rest of the council carries on. Same for the judge. You still get the panel answers, with an empty analysis and status: "error".

Every streamed call has a stall timeout (LLMCONCIL_STALL_TIMEOUT, default 180s) that fires when no token arrives within the window. It's deliberately a stall timeout and not a total one: a model reasoning hard for six minutes is working, a model silent for three is stuck, and a fixed deadline can't tell them apart. Keepalive frames don't reset it, or a stuck stream would keep itself alive forever.

Layout

file role
server.py the MCP server and the fusion_deliberate tool definition
fusion.py orchestration — panel fan-out, then the judge
council.py reads council.toml
backends.py which service serves which model
openrouter.py streaming client, stall timeout, model catalogue
gemini.py the Google AI Studio path
context.py file reading, line ranges, token budget
schema.py the JSON schema the judge has to fill in

Known rough edges

  • No tests. The failure paths are handled but only manually exercised.
  • The judge's structured output leans on response_format: json_schema. Models vary in how well they honour it, so there's a tolerant parser behind it that digs the first balanced JSON object out of the reply. A judge that ignores the schema entirely yields an empty analysis rather than garbage.
  • A near-200k context will overflow panellists with smaller windows. They fail individually and land in failed_models, but nothing warns you upfront.
  • The /models catalogue is fetched once and kept for the life of the process, so a model that gains vision after your server started won't be recognised until you restart it.

License

MIT

推荐服务器

Baidu Map

Baidu Map

百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。

官方
精选
JavaScript
Playwright MCP Server

Playwright MCP Server

一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。

官方
精选
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。

官方
精选
本地
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。

官方
精选
本地
TypeScript
VeyraX

VeyraX

一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。

官方
精选
本地
graphlit-mcp-server

graphlit-mcp-server

模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。

官方
精选
TypeScript
Kagi MCP Server

Kagi MCP Server

一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。

官方
精选
Python
e2b-mcp-server

e2b-mcp-server

使用 MCP 通过 e2b 运行代码。

官方
精选
Neon MCP Server

Neon MCP Server

用于与 Neon 管理 API 和数据库交互的 MCP 服务器

官方
精选
Exa MCP Server

Exa MCP Server

模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。

官方
精选