Skip to main content
Glama
Firnschnee

Dual Model MCP Server

by Firnschnee

Dual Model MCP Server

An MCP server that queries multiple LLMs (default: Claude Fable 5.1 and OpenAI GPT-6 Astra, reasoning effort high) in parallel via OpenRouter and returns side-by-side responses, optionally with an automatic synthesis step that compares them. A second tool, ask_gpt, asks a single cheap model (default GPT-5.6 Sol) for an everyday second opinion.

Runs locally over stdio (Claude Code, Claude Desktop, Cherry Studio) and remotely over Streamable HTTP – so you can use it from claude.ai on the web and in the mobile apps as a custom connector.

The Problem

Sometimes a single AI model gets stuck in a particular perspective or reasoning pattern. You ask a question, get a good answer, but you know there's another angle, another approach that might be equally valuable (or better). Switching between different models, waiting for separate responses, losing context. It's tedious.

Related MCP server: cognition-wheel

The Solution

Dual Model MCP Server sends your prompt to multiple models simultaneously, giving you independent, high-quality responses side-by-side. Compare, contrast, combine, all in one go. Perfect for:

  • Decision-making: See technical/medical/business/research/legal questions from multiple angles

  • Quality assurance: Spot blind spots in reasoning or missed edge cases

  • Creative work: Get diverse perspectives on problems

  • Validation: Cross-check facts and arguments between models

Features

  • Parallel queries – All models respond simultaneously, not sequentially

  • Resilient – If one model fails, you still get the others' answers instead of a total error

  • Synthesis step (optional) – A third, cheap model compares the answers: convergences, contradictions, unique points

  • Token usage reporting – Every response includes per-model and total token counts

  • Configurable without rebuild – Models, reasoning effort, max_tokens, temperature, timeout via .env; per-call overrides via tool parameters

  • N models, not just two – Configure any number of OpenRouter models

  • Structured responses – Default system prompt produces 6-8 concise paragraphs (analysis, context, evidence, arguments, alternatives, reflection, conclusion); custom system prompts supported

  • Easy integration – Works with Claude Code, Claude Desktop, Cherry Studio, or any MCP client

  • Remote access – Optional HTTP mode serves the same tool over HTTPS for claude.ai (web/mobile) via custom connector, secured by a secret URL path

Quick Start

Installation

git clone https://github.com/Firnschnee/dual-model-mcp.git
cd dual-model-mcp
npm install

npm install builds the server automatically (via the prepare script).

Setup

  1. Get an OpenRouter API key:

    • Go to openrouter.ai

    • Create an account / sign in

    • Copy your API key from settings

  2. Create .env file (copy the template):

    cp .env.example .env

    Then edit .env and paste your key:

    OPENROUTER_API_KEY=your_actual_api_key_here

    .env is gitignored, so your key never lands in version control. The server loads .env relative to its own location, so it works no matter which working directory your MCP client uses.

  3. Verify:

    npm start

    You should see:

    ✅ Server läuft! Warte auf MCP-Anfragen via STDIO...

    Stop it with Ctrl+C. You do not need to keep it running: MCP clients start the server themselves as a child process whenever they need it.

Usage

With Claude Code

claude mcp add --scope user dual-model -- node C:/path/to/dual-model-mcp/build/index.js

Or add it to a single project via .mcp.json in the project root:

{
  "mcpServers": {
    "dual-model": {
      "command": "node",
      "args": ["C:/path/to/dual-model-mcp/build/index.js"]
    }
  }
}

Then ask Claude Code to use the query_dual_models tool, e.g. "Frag beide Modelle: ... und synthetisiere die Antworten."

With claude.ai (web & mobile)

claude.ai talks to remote MCP servers over Streamable HTTP. The HTTP entry point serves exactly that; you need a server with a public HTTPS domain and a reverse proxy.

  1. On your server: clone, install, and configure:

    git clone https://github.com/Firnschnee/dual-model-mcp.git
    cd dual-model-mcp && npm ci

    In .env (or a systemd EnvironmentFile), set your API key plus:

    MCP_PATH_SECRET=$(openssl rand -hex 24)
  2. Run the HTTP entry point (ideally as a systemd service):

    npm run start:http

    It binds to 127.0.0.1:3777 and serves MCP at /<MCP_PATH_SECRET>/mcp. Requests to any other path get a bare 404.

  3. Route it through your reverse proxy. Caddy example:

    your-domain.example {
        handle /<MCP_PATH_SECRET>/mcp {
            reverse_proxy 127.0.0.1:3777
        }
    }
  4. Add the connector in claude.ai: Settings → Connectors → Add custom connector → https://your-domain.example/<MCP_PATH_SECRET>/mcp. The tool then works in web chats and the mobile apps.

Security model: the secret path is the only authentication – anyone who knows the URL can spend your OpenRouter credit. Keep the URL private, set a spending limit in the OpenRouter dashboard as a backstop, and rotate the secret (env file + proxy + connector URL) if it ever leaks. For anything beyond personal use, put proper OAuth in front instead.

With Cherry Studio

  1. Open Cherry Studio

  2. Settings → MCP Servers → Add

  3. Fill in:

    • Name: Dual Model MCP

    • Command: node

    • Arguments: C:\path\to\dual-model-mcp\build\index.js

  4. Save & restart Cherry Studio

  5. Choose the MCP server in the chat window, ask a question, and all models respond

Tool parameters

query_dual_models accepts:

Parameter

Type

Default

Description

prompt

string

(required)

The prompt sent to all models

system_prompt

string

structured 6-8 paragraph prompt

Custom system prompt

models

string[]

from .env / built-in

OpenRouter model IDs for this call only

max_tokens

number

32000

Max output tokens per model (reasoning tokens count against this)

effort

none…max

high

Reasoning effort, passed through OpenRouter's unified reasoning parameter

temperature

number

unset

Sampling temperature (0-2). Ignored by OpenAI and Anthropic reasoning models

synthesize

boolean

false

Adds a comparison step: convergences, contradictions, unique points

ask_gpt is the everyday variant: one cheap model (default GPT-5.6 Sol at effort high), no synthesis, same output format. It accepts prompt, system_prompt, max_tokens and effort. Keeping it as a separate tool means a caller that wants a quick second opinion does not accidentally trigger the expensive escalation tool.

Configuration

All settings live in .env (see .env.example):

Variable

Default

Description

OPENROUTER_API_KEY

(required)

Your OpenRouter API key

MODELS

anthropic/claude-fable-5.1,openai/gpt-6-astra

Comma-separated model IDs to query in parallel

REASONING_EFFORT

high

Reasoning effort for all models (none, minimal, low, medium, high, xhigh, max)

ASK_GPT_MODEL

openai/gpt-5.6-sol

Model behind the ask_gpt tool

ASK_GPT_EFFORT

high

Reasoning effort for ask_gpt

ASK_GPT_MAX_TOKENS

32000

Max output tokens for ask_gpt

SYNTHESIS_MODEL

google/gemini-3.8-flash

Model for the synthesis step

MAX_TOKENS

32000

Max output tokens per model, including reasoning tokens

TEMPERATURE

unset

Sampling temperature; only sent when set

REQUEST_TIMEOUT_MS

600000

Per-request timeout

MCP_PATH_SECRET

(required in HTTP mode)

Secret URL path segment, min. 16 chars

MCP_HTTP_HOST

127.0.0.1

HTTP bind address (keep local behind a reverse proxy)

MCP_HTTP_PORT

3777

HTTP port

No rebuild needed after changing .env; the MCP client restarts the server on demand.

Stack & Dependencies

Aspect

Technology

Language

TypeScript

Protocol

Model Context Protocol (MCP)

API

OpenRouter (supports 200+ models)

Runtime

Node.js 20+ (native fetch, AbortSignal.any, no HTTP client dependency)

Build

tsc + npm

Cost & Token Usage

This is an escalation tool, not a daily driver: the default models are the most expensive tier of both vendors (roughly $10 in / $50 out per million tokens each), and max_tokens defaults to 32000 per model so that effort: high has room to think and still answer. Reasoning tokens count against max_tokens on every provider; if the budget runs out before the answer starts, the tool says so instead of reporting an empty response, and a truncated answer is flagged as such. A single hard question can cost a dollar or two.

Note on claude.ai: the web client gives up on a tool call after roughly four minutes. Calls that run longer are billed by OpenRouter but never reach the chat. The HTTP entry point aborts in-flight model calls when the client disconnects, and ask_gpt defaults to effort high rather than xhigh for that reason. Claude Code over stdio has no such limit. Every response reports actual token usage per model and in total, so you can see what a query cost. For quick factual questions, pass a smaller max_tokens per call.

Testing

npm test

Runs a minimal smoke test: starts the built server, sends one short prompt with a one-sentence system prompt, prints the response. Costs a few hundred tokens.

Contributing

Found a bug? Have an idea? Fork & submit a PR!

License

MIT License – See LICENSE file

Available Tools

2 tools
ask_gptZweitmeinung von GPTA

Holt eine Zweitmeinung von openai/gpt-5.6-sol (Reasoning-Effort high) via OpenRouter. Günstige Alltagsvariante für eine andere Perspektive, keine Eskalation. Das Modell sieht nur den Prompt: Kontext, Code und bisherige Versuche mitgeben.

ParametersJSON Schema
NameRequiredDescriptionDefault
effortNoOptional: Reasoning-Effort. Standard: high
promptYesDie Frage samt allem Kontext, den das Modell braucht
max_tokensNoOptional: max_tokens. Standard: 32000
system_promptNoOptional: Custom System-Prompt. Falls leer: Standard-Prompt (strukturiert, 6-8 Absätze).

TDQS

A4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations the description carries the full burden, and it does disclose a genuinely important trait: the model sees only the prompt, so context, code and prior attempts must be supplied by the caller. It omits cost/latency expectations, failure behavior, and what the returned answer looks like.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three tight sentences: identity/route first, fit-for-purpose second, the critical prompt-only caveat last. No filler and no repetition of schema content.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a four-parameter inference tool with full schema coverage, no output schema and no annotations, the description covers the essentials, including the non-obvious statelessness caveat a caller would otherwise miss. Minor gap: nothing about cost, latency or error behavior.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so all four parameters (prompt, effort, max_tokens, system_prompt) are already documented; baseline 3 applies. The description reinforces the default effort of high and the 'only the prompt is visible' constraint, but adds no syntax or format detail beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

Names a concrete verb+resource ('Holt eine Zweitmeinung'), the exact model (openai/gpt-5.6-sol), the effort level and the transport (OpenRouter), so the agent knows precisely what it gets. It differentiates itself by tier ('Günstige Alltagsvariante, keine Eskalation') but never names or contrasts the sibling query_dual_models explicitly.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Clear context for use — a cheap everyday option for a second perspective — plus an explicit exclusion ('keine Eskalation'), which tells the agent when NOT to pick it. It stops short of naming the alternative route to use instead, so routing is only partially resolved.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

query_dual_modelsMulti-Modell-AnfrageA

Schickt eine Prompt parallel an mehrere Modelle via OpenRouter (Standard: anthropic/claude-fable-5.1, openai/gpt-6-astra, Reasoning-Effort high). Eskalationsstufe für harte Probleme, nicht für Routinefragen: teuer und langsam. Liefert alle Antworten nebeneinander, optional mit Synthese (Konvergenzen, Widersprüche, Unikate). Standard-System-Prompt: strukturierte Antwort in 6-8 Absätzen.

ParametersJSON Schema
NameRequiredDescriptionDefault
effortNoOptional: Reasoning-Effort für alle Modelle. Standard: high
modelsNoOptional: OpenRouter-Modell-IDs für diesen Aufruf. Standard: anthropic/claude-fable-5.1, openai/gpt-6-astra
promptYesDie Prompt für alle Modelle
max_tokensNoOptional: max_tokens pro Modell. Standard: 32000
synthesizeNoOptional: Zusätzlicher Vergleichsschritt über alle Antworten (Konvergenzen, Widersprüche, Unikate).
temperatureNoOptional: Temperature. Standard: nicht gesetzt (Provider-Default). Reasoning-Modelle von OpenAI und Anthropic ignorieren den Parameter.
system_promptNoOptional: Custom System-Prompt. Falls leer: Standard-Prompt (strukturiert, 6-8 Absätze).

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations the description carries the whole burden, and it delivers: cost/latency warning, default model set, default effort, default system prompt, and the return shape (all answers side by side, optional synthesis). It omits rate limits, auth requirements, and per-model failure behavior, keeping it short of 5.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three dense sentences, all front-loaded: purpose first, then usage gating with the cost caveat, then output and default behavior. No filler and nothing buried.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 7-parameter tool with no output schema and no annotations, the description covers purpose, cost, defaults, and return shape well. Minor gaps remain around error handling and what happens when individual models fail, but the essentials for correct invocation are present.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so every parameter is already documented in the schema, including defaults for effort, models, max_tokens and system_prompt. The description mostly repeats those defaults rather than adding format or constraint meaning, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (schickt ... parallel an mehrere Modelle) and resource (multi-model query via OpenRouter), and the multi-model scope directly distinguishes it from the single-model sibling ask_gpt. An agent can tell them apart immediately.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly frames when to use it (Eskalationsstufe für harte Probleme) and when not (nicht für Routinefragen), with the cost/latency rationale. It does not name ask_gpt as the concrete alternative for routine single-model queries, so it falls short of full 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 2 tool updatesv1.2.2
    • Addedask_gpt
    • Changedquery_dual_models4 fields changed
      • addedInput schema / properties / effort
        Added value: +{
        +  "description": "Optional: Reasoning-Effort für alle Modelle. Standard: high",
        +  "enum": [
        +    "none",
        +    "minimal",
        +    "low",
        +    "medium",
        +    "high",
        +    "xhigh",
        +    "max"
        +  ],
        +  "type": "string"
        +}
      • changedInput schema / properties / max_tokens / description
        Previous value: -"Optional: max_tokens pro Modell. Standard: 6000"New value: +"Optional: max_tokens pro Modell. Standard: 32000"
      • changedInput schema / properties / models / description
        Previous value: -"Optional: OpenRouter-Modell-IDs für diesen Aufruf. Standard: anthropic/claude-opus-4.8, openai/gpt-5.5"New value: +"Optional: OpenRouter-Modell-IDs für diesen Aufruf. Standard: anthropic/claude-fable-5.1, openai/gpt-6-astra"
      • changedInput schema / properties / temperature / description
        Previous value: -"Optional: Temperature. Standard: 0.7"New value: +"Optional: Temperature. Standard: nicht gesetzt (Provider-Default). Reasoning-Modelle von OpenAI und Anthropic ignorieren den Parameter."
  2. 1 tool updatev1.0.1
    • Changedquery_dual_models8 fields changed
      • addedInput schema / $schema
        Added value: +"http://json-schema.org/draft-07/schema#"
      • addedInput schema / additionalProperties
        Added value: +false
      • addedInput schema / properties / max_tokens
        Added value: +{
        +  "description": "Optional: max_tokens pro Modell. Standard: 6000",
        +  "exclusiveMinimum": 0,
        +  "type": "integer"
        +}
      • addedInput schema / properties / models
        Added value: +{
        +  "description": "Optional: OpenRouter-Modell-IDs für diesen Aufruf. Standard: anthropic/claude-opus-4.8, openai/gpt-5.5",
        +  "items": {
        +    "type": "string"
        +  },
        +  "minItems": 1,
        +  "type": "array"
        +}
      • changedInput schema / properties / prompt / description
        Previous value: -"Die Prompt für beide Modelle"New value: +"Die Prompt für alle Modelle"
      • addedInput schema / properties / synthesize
        Added value: +{
        +  "description": "Optional: Zusätzlicher Vergleichsschritt über alle Antworten (Konvergenzen, Widersprüche, Unikate).",
        +  "type": "boolean"
        +}
      • changedInput schema / properties / system_prompt / description
        Previous value: -"Optional: Custom System-Prompt. Falls leer: Standard-Prompt (strukturiert, prägnant, 6-8 Absätze)."New value: +"Optional: Custom System-Prompt. Falls leer: Standard-Prompt (strukturiert, 6-8 Absätze)."
      • addedInput schema / properties / temperature
        Added value: +{
        +  "description": "Optional: Temperature. Standard: 0.7",
        +  "maximum": 2,
        +  "minimum": 0,
        +  "type": "number"
        +}
  3. 1 tool updatev1.0.0
    • First observedquery_dual_models

TDQS

A4.1/5.0

Scored across 2 tools

Disambiguation4/5

The two tools have distinct purposes: query_dual_models is an escalation tool for hard problems with parallel multi-model synthesis, while ask_gpt is a cheap everyday second opinion. The descriptions explicitly differentiate them (e.g., 'keine Eskalation'), though both involve querying external models, so mild overlap remains.

Naming Consistency4/5

Both names follow a verb_noun snake_case pattern (query_dual_models, ask_gpt). The verbs 'query' and 'ask' are synonyms rather than identical, and the nouns differ in specificity, but the convention is readable and consistent enough.

Tool Count4/5

Two tools is slightly below the typical 3-15 range, but each tool serves a clear, distinct use case (escalation vs. everyday second opinion). The count is well-scoped for a focused dual-model query server.

Completeness4/5

The surface covers the two main workflows: multi-model escalation and single-model second opinion. Minor gaps exist, such as no tool to discover available models or configure model defaults, but core needs are met.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    D
    maintenance
    Query multiple AI models (GPT-4, Claude, Gemini, Grok) in parallel for diverse perspectives. Get different expert viewpoints when stuck or need enhanced reasoning.
    1
    MIT
  • A
    license
    A
    quality
    D
    maintenance
    Enables querying multiple AI models in parallel (Claude, Gemini, O3) and synthesizing their responses using anonymous analysis to reduce bias, providing a comprehensive answer.
    1
    25 npm
    193
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    Queries multiple AI models simultaneously (GPT 5.2, Claude Opus 4.5, Gemini 3, Grok 4.1) via a single API call to provide diverse expert perspectives and consensus recommendations.
    MIT