unmerged-approaches-mcp
v0.1.1
Published
MCP server that sends one identical brief to several LLMs in parallel and returns every answer unmerged, unranked and unsynthesized, so the calling agent can see agreement and disagreement instead of an averaged blur.
Downloads
250
Maintainers
Readme
unmerged-approaches-mcp
An MCP server that puts one identical brief to several LLMs in parallel and hands back every answer verbatim — unmerged, unranked, unsynthesized.
Most multi-model MCP servers end in a judge, a synthesizer, or a consensus loop. This one deliberately does not. The moment N answers are averaged into one confident paragraph, the single most useful piece of information is destroyed: whether the models actually agreed.
- Four models independently reaching the same conclusion is corroboration.
- Two against two is a real open question your one-model answer would have hidden from you.
A synthesizer renders both of those as the same smooth prose. This server refuses to, by design.
What it does
- Fans one brief out to up to 12 OpenRouter models concurrently — 400+ models, one API key.
- Returns per-model: the verbatim answer,
finish_reason, latency, token usage, cost, and a structured error when a model fails. - A slow or failing model becomes one failed entry; it never sinks the panel.
- Persists bounded, redacted, correlation-ID-addressable debug events.
- Never merges, ranks, scores, votes on, or picks a winner among the answers.
Install
stdio (Claude Desktop, Claude Code, Cursor, Cline, Zed)
{
"mcpServers": {
"unmerged-approaches": {
"command": "npx",
"args": ["-y", "unmerged-approaches-mcp@latest"],
"env": { "OPENROUTER_API_KEY": "sk-or-v1-..." }
}
}
}claude mcp add unmerged-approaches npx -y unmerged-approaches-mcpRemote Streamable HTTP
OPENROUTER_API_KEY=sk-or-v1-... UNMERGED_AUTH_TOKEN=your-token npx unmerged-approaches-mcp-http
# or: node src/http.jsMounts MCP at /mcp and a separate liveness probe at /health.
{
"mcpServers": {
"unmerged-approaches": {
"type": "http",
"url": "https://your-host.example/mcp"
}
}
}Send the token as Authorization: Bearer <token> or x-api-key. Keep secrets in your client's secret storage, never in a committed config file.
Tools
| Tool | Category | What it does |
|---|---|---|
| consult | PANEL | One brief → N models in parallel → N verbatim answers, unmerged |
| list_models | SYSTEM | Live OpenRouter catalog: substring search, free-only filter, cursor pagination |
| get_status | SYSTEM | Server version, credential validity, remaining credit, default panel, limits |
| get_debug_logs | DEBUG | Newest-first structured events, filterable by correlationId / level / event / operation / time |
All four are read-only and non-destructive. The server exposes no arbitrary HTTP, shell, or SQL primitive.
consult
| Argument | Type | Notes |
|---|---|---|
| brief | string, required | Sent byte-for-byte identically to every model. Max 200,000 chars. |
| models | string[] | Exact OpenRouter ids, max 12, deduplicated. Omit for the default panel. |
| system | string | Optional system prompt, identical for every model. |
| max_tokens | int | Default 8000, ceiling 32000. |
| temperature | number | 0–2, default 0.7. |
| timeout_ms | int | Default 180000, max 600000. Per model, not for the batch. |
Returns correlationId, requestedModels, answeredCount, completeCount, failedCount, totalCostUsd, wallClockMs, and answers[] with { model, actualModel, ok, complete, finishReason, content, error, latencyMs, usage }.
If every model fails, the call returns isError: true with code ALL_MODELS_FAILED. A partial panel is a success.
Writing a brief that is worth the money
The output is only as good as the isolation of the input. A brief that leaks your preferred answer gets it echoed back by every model, and you will mistake that echo for agreement.
- Include the goal, hard constraints, what is already decided, what was rejected and why, and what is genuinely unknown.
- Mark unverified claims as unverified. Distinguish what you observed from what you assumed.
- Do not name your preferred option, and do not tell the panel what an earlier model said.
- Ask for independent judgment, not novelty.
Environment variables
| Name | Required | Purpose |
|---|---|---|
| OPENROUTER_API_KEY | yes | OpenRouter credential. Server-side only; never accepted as a tool argument. |
| UNMERGED_DEFAULT_MODELS | no | Comma-separated default panel. |
| UNMERGED_MAX_MODELS | no | Panel size cap. Default 12. |
| UNMERGED_MAX_TOKENS | no | Default output ceiling per model. Default 8000. |
| UNMERGED_TIMEOUT_MS | no | Default per-model timeout. Default 180000. |
| UNMERGED_LOG_CAPACITY | no | Retained debug events. Default 500. |
| UNMERGED_AUTH_TOKEN | http only | Bearer / x-api-key token for the HTTP transport. |
| UNMERGED_ALLOWED_ORIGINS | http only | Comma-separated browser origin allowlist. Browsers are refused unless listed. |
| PORT, HOST | http only | Defaults 8787, 127.0.0.1. |
No value is ever written to logs, tool results, or client configuration.
Cost
You pay per model, per call. A 5-model panel is roughly 5× a single call. list_models with free_only: true finds zero-price models; free endpoints time out and rate-limit far more often, which shows up honestly in failedCount.
Security
- Credentials are read only from the server environment and are never accepted as tool arguments.
- Anything credential-shaped is stripped from errors and debug events before persistence.
- The HTTP transport validates
Origin, requires a bearer token when one is configured, and compares it in constant time. - Returned answers are untrusted third-party model output. If an agent calls this on attacker-influenced input, treat the answers as data to weigh, never as instructions to execute. This is a prompt-injection surface like any MCP tool that returns external content.
Development
npm install
npm run build # syntax check every entrypoint
npm test # 9 contract tests incl. a live stdio initialize/list/call handshakeLicense
MIT
