Skip to main content
Glama
dxt-openrouter-router

dxt-openrouter-router

by sphilius

DXT OpenRouter Router

npm license

A tiny MCP (stdio) server that returns a ready-to-send OpenRouter request body from a named preset and your current energy budget:

energy

Model slug becomes

Meaning

low

…:floor

cheapest provider serving that model

balanced

… (base slug)

the model's default provider

high

…:nitro

highest-throughput provider

Two things make this different from a normal cost router:

  1. It routes on energy, not just cost. The input is a fact about you, not about the task. "Cheap" and "fast" are the same axis viewed from different energy levels.

  2. Zero Data Retention is the default. Every body ships provider.data_collection: "deny", so a preset has to explicitly opt out of privacy rather than opt in to it.

It builds the request. It does not send it — so it never needs your API key in-process, and never sees a response.


Install

npm install -g dxt-openrouter-router

Or run it without installing:

npx dxt-openrouter-router

Related MCP server: mcp-openrouter

Register it with an MCP host

Claude Desktop (claude_desktop_config.json) or any MCP client:

{
  "mcpServers": {
    "openrouter-router": {
      "command": "npx",
      "args": ["-y", "dxt-openrouter-router"],
      "env": {
        "ROUTING_PRESETS_PATH": "C:\\path\\to\\routing.presets.json"
      }
    }
  }
}

ROUTING_PRESETS_PATH is optional — omit it and the bundled routing.presets.json is used. The file is re-read on every call, so you can edit presets without restarting the host.

The routeLLM tool

Argument

Required

Description

preset

✅

A key from routing.presets.json, e.g. research_long_context

energy

low | balanced | high (default balanced)

user_prompt

The user message to place in the body

system

Overrides the preset's own system prompt

overrides

Extra body fields merged in last, e.g. { "temperature": 0.2 }

Example

// call
{ "preset": "research_long_context", "energy": "low", "user_prompt": "Synthesize these sources..." }
// result
{
  "url": "https://openrouter.ai/api/v1/chat/completions",
  "method": "POST",
  "headers": {
    "Authorization": "Bearer $OPENROUTER_API_KEY",  // literal placeholder — never your real key
    "Content-Type": "application/json"
  },
  "api_key_configured": true,
  "body": {
    "temperature": 0.2,
    "model": "meta-llama/llama-3.1-70b-instruct:floor",
    "messages": [
      { "role": "system", "content": "You are a careful research synthesist. ..." },
      { "role": "user", "content": "Synthesize these sources..." }
    ],
    "provider": { "data_collection": "deny" }
  }
}

Presets

routing.presets.json is a plain map of name → preset:

{
  "presets": {
    "daily_driver": {
      "model": "google/gemini-3.6-flash",   // no :floor/:nitro here — energy adds that
      "description": "Default workhorse — unit tests, refactors, docs, CLI loops.",
      "system": "Optional default system prompt.",
      "provider": { "data_collection": "deny" },      // merged over the ZDR default
      "response_format": { "type": "json_object" },   // passed straight through
      "params": { "temperature": 0.4 }                // any other OpenRouter body field
    }
  }
}

Bundled presets mirror a simple decision tree:

Preset

Model

Reach for it when

quick_ping

x-ai/grok-4.5

formats, clarifications, vibe checks

daily_driver

google/gemini-3.6-flash

~80% of volume — tests, refactors, docs

logic_engine

openai/gpt-5.6-sol

math, symbolic logic, formal reasoning

high_reasoning

anthropic/claude-opus-4.8

architecture, nuanced review, agentic work

research_long_context

meta-llama/llama-3.1-70b-instruct

long-context synthesis across sources

structured_json

google/gemini-3.6-flash

extraction that must return parseable JSON

Slugs were verified against https://openrouter.ai/api/v1/models on 2026-07-22. OpenRouter slugs change as models ship — re-check before relying on them.

Secrets

🔒 This package contains no API key, and the tool output never includes one.

  • OPENROUTER_API_KEY is read from the environment, and only ever reported as the boolean api_key_configured.

  • The Authorization header is emitted as the literal string Bearer $OPENROUTER_API_KEY, so tool output is safe to paste into a chat log, an issue, or a commit.

  • Copy .env.example → .env for local use. .env is gitignored.

Use as a library

The pure core is exported, so you can build bodies without MCP:

import { buildRequestBody, loadPresets } from "dxt-openrouter-router";

const presets = loadPresets("./routing.presets.json");
const body = buildRequestBody(presets, { preset: "daily_driver", energy: "low" });

Develop

npm install
npm run build     # tsc -> dist/
npm test          # node --test test/

License

MIT © Sasha Philius

Available Tools

1 tool
routeLLMA

Build a ready-to-send OpenRouter chat-completion request body from a named preset and the user's current energy budget. energy=low appends :floor (cheapest provider), energy=high appends :nitro (highest throughput), energy=balanced uses the base model slug. Zero Data Retention (provider.data_collection=deny) is on by default. Returns the URL, headers and body — it does NOT send the request.

Inputs: preset (required), energy, system, overrides, +1 more.

Tool Schema Changelog

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

Loading tool schema changelog…

    TDQS

    A3.8/5.0

    Scored across 1 tool

    Disambiguation5/5

    There is only one tool, so there is no possibility of ambiguity or overlap with other tools. The purpose of routeLLM is clearly defined and distinct.

    Naming Consistency3/5

    With only a single tool, there is no pattern to evaluate for consistency. The name routeLLM uses a camelCase convention mixing a verb and a domain noun, which is readable though generic.

    Tool Count2/5

    A single tool feels thin for a server named 'openrouter-router.' The router domain likely requires at least companion operations (e.g., send, list presets, get budget) to be practically useful on its own, so one tool is under-scoped.

    Completeness2/5

    The tool only builds a request body and explicitly does not send the request. For routing purposes, there is a notable dead end—no send capability, no way to list/manage presets, and no health or configuration operations. The surface is significantly incomplete for the stated routing purpose.

    Maintenance

    ActivityInactive
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers