Skip to main content
Glama
swarnim-git3

mcp-model-router

by swarnim-git3

MCP Model Router

An MCP server that routes each prompt to whichever Claude model best fits it.

The routing decision itself is 100% local — plain Python, no LLM call. Only one model call happens per request: the one that actually answers it. That matters, because the obvious way to build this (ask a model to classify the prompt first) doubles the number of calls and charges you for the classifier on every single request.

The tool

The server exposes one tool over MCP:

smart_prompt(prompt: str) -> str

Any MCP-capable client can discover and call it. The response comes back with the routing decision attached, so you can always audit the choice:

[routed to opus (claude-opus-5) — matched opus signals (score=2)]

<the answer>

Related MCP server: Agentic Workbench

How routing works

choose_model(prompt) in router.py returns (tier, reason). In order:

  1. Force tags. A prompt starting with !opus, !sonnet, !haiku or !fable bypasses routing entirely.

  2. Signal scoring. Four buckets are scored against the prompt:

    • code patterns (fenced blocks, def, stack traces, .py/.js/.tsx, regex, unit test) → coding tier

    • reasoning keywords (why, analyze, trade-off, architecture, root cause, pros and cons) → deepest tier

    • creative keywords (write a story, poem, screenplay, lyrics) → narrative tier

    • extraction keywords (extract, classify, translate, one sentence, tl;dr) → fastest tier

  3. Complexity escalation. Question marks, bullet lines and numbered list items are summed; three or more structural signals adds a point to the deep-reasoning tier.

  4. Length fallback. Only if nothing scored: ≤12 words → fastest tier, ≥150 words → deepest tier, otherwise the balanced generalist.

Keyword signals deliberately outrank the length heuristic. Without that precedence, a short prompt like "write a short story" would let the word-count bonus outvote the creative-keyword match it should lose to.

Tuning it

Every decision is appended to logs/routing_log.csv:

timestamp

tier

reason

prompt_excerpt

The keyword lists in router.py are a starting point, not a final answer. Watch the log fill up and edit them directly. After any change, re-run the offline smoke test — it asserts expected routing on seven representative prompts and costs nothing, because it never touches the API:

python test_router.py

Setup

python -m venv .venv
.venv\Scripts\activate          # Windows
pip install -r requirements.txt

cp .env.example .env            # then put your real key in it

.env is gitignored — the key never leaves your machine.

Register the server with your MCP client via .mcp.json:

{
  "mcpServers": {
    "model-router": {
      "command": "<path>\\.venv\\Scripts\\python.exe",
      "args": ["<path>\\server.py"]
    }
  }
}

Adjust both paths to wherever you cloned this.

Files

File

Role

server.py

MCP server, tool definition, model execution, CSV logging

router.py

The classifier: model registry, force tags, signal scoring, length fallback

test_router.py

Offline smoke test — no API calls, no cost

.mcp.json

Client registration

Requirements

mcp · anthropic · python-dotenv

Related MCP Connectors

Related MCP Servers