OpenRouter · Groq · Cerebras · Sail · one comparable shape
Open Dashboard MCP
Pick the cheapest model that still does the job — across every provider you hold a key with, not one at a time.
Install
claude mcp add open-dashboard -- npx -y open-dashboard-mcp
Node 20 or newer. No API key is needed for any tool except the optional key inventory. Published on npm as open-dashboard-mcp.
How it stays current
It is consumed as an MCP server, not a snapshot. npx -y open-dashboard-mcp
resolves the latest published version on every launch, so an upgrade reaches you with nothing to reinstall
anywhere. A periodic snapshot would freeze pricing at build time — and a model that stopped being free yesterday
would still read as free in a copy taken last week, which is the precise harm this exists to prevent.
Every tool reads a public, zero-credential API at query time. That host is a hobby-tier deployment with no uptime obligation, and it is a dependency of every answer. Two things follow, and both are visible in the response rather than left to assumption.
Responses are cached, and every answer carries its own age. One economics query can make two dozen upstream requests — measured, ten requests and 733 ms cold, then zero requests and 3 ms on a repeat. Each piece of evidence carries when it was measured and how old it is:
"freshness": {
"state": "cached",
"fetchedAt": "2026-08-27T20:21:52.494Z",
"ageSeconds": 30,
"expiresAt": "2026-08-27T20:26:52.494Z"
}
When the host is slow or down, the answer says so. With nothing cached you get a structured unavailable carrying a reason — never a fabricated number. With an expired entry in hand the last known value is returned, but marked:
"state": "expired",
"note": "Upstream could not be reached, so this is the last known value,
measured 2026-08-27T20:21:52.494Z (3600s ago). It is not current."
Unmeasured is not zero, and stale is not fresh. A number is never handed back as current when it is not, and the age arrives with the answer so a caller can refuse it.
Why it exists
A free model does not announce itself when it stops being free. It simply starts costing money, and the bill arrives before the surprise does. Meanwhile the model that is cheapest for a task on one provider is rarely cheapest on another, and OpenRouter's own MCP server is single-vendor by construction — it cannot compare across the providers you actually use.
This server reads all three catalogues, puts them in one shape, and refuses to guess where they disagree.
What it does today
Each claim below is marked with what was actually measured, not what is intended. Where the answer is no, it says no.
-
Yes — today
Sees real prices, per token and per million tokens, across all three providers. Prices are carried as exact decimal strings end to end, so a price like $0.000000088606 per token does not become a rounded float on the way to you.
-
Yes — today
Reads published discounts, not just list prices — on OpenRouter. OpenRouter attaches discounts to a provider endpoint, not to the model, which is why looking at the model list alone shows none. Measured 2026-08-19: zero of 550 models carried a discount field; 272 of 272 provider endpoints did.
Not parity across providers. Groq and Cerebras publish no discounts at all, so their rows always report
not_published_by_provider. That is a fact about those providers rather than something this tool can close, and discount coverage should be read as rich for OpenRouter and absent elsewhere. -
Yes — today
Answers “cheapest that satisfies these criteria”, not merely “cheapest”. Capability is modelled and filtered before ranking: output modality, minimum context length, tool-call support, reasoning support, provider, current availability, and retirement risk. Quality and benchmark fitness are not modelled — see the roadmap.
-
Yes — today
Separates genuinely free from rate-limited free. A real zero-priced model, a rate-limited free routing tier, and “the provider publishes no price at all” are three different answers. The third is reported as unknown and never as free.
-
Yes — today
Constrains a selection to free models only, and notices when that set shrinks — both ways. A free-only query is one flag. A model that disappears from a catalogue is reported as a disappearance; a model that stays listed and stops being free is reported as a price change. Those are the two ways the free set can shrink, and both are now covered.
-
Yes — today
Detects a model that stopped being free. Its id does not change and it stays listed, so nothing else in a catalogue moves — the bill is the notification. The two most recent archived collection runs are compared and models that left free are reported in their own bucket, apart from every other price movement.
Shipped in 0.2.0. Prices are compared as exact decimals, never floats, and a null price counts as unknown rather than free. A source that could not be read says so instead of returning an empty list.
-
Yes, with the limit stated
An empty result is not an all-clear, and the tool says so itself. The comparison is the producer’s own pair of archived runs, not the window you asked about — and it publishes no date for the older of the two, so how far back it reaches cannot be established from the response. A tool that answered “nothing started charging” against an unknown window would be doing the exact thing this page says it prevents.
Shipped in 0.4.0. The report carries the date of the newest state it examined when the producer publishes one — and
nullwhen it does not, rather than a guess — states coverage asincompleteorindeterminateand never as complete, and a successful report’s status is alwayspartialrather thanok. Measured against production 2026-08-27, asking about 2026-08-18 onward: “Price movement could not be shown to cover 2026-08-18 to 2026-08-25, so this is not an all-clear on models that started charging.” It also refuses to state an exact count from a paginated page it only partly read, and refuses to rule the transition out from one. -
Not yet
“Automates switching to the correct model.”
The server never switches anything. All nine tools are read-only by construction — there is no code path that writes a config, changes a route, or mints a key. It is the input to automation: an agent holding this answer can switch, and that is the intended shape. But the switching lives in the agent, not here.
What each provider actually publishes
The four catalogues disagree about nearly everything, and normalising that is most of the work. Every gap below is declared per provider, so a missing value is reported as that provider withheld it rather than appearing as a blank you might read as zero.
| Provider | Models | With prices | Context | Modality | Deprecation signal | Spend API |
|---|---|---|---|---|---|---|
| OpenRouter | 562 | 417 | yes | yes | yes | yes |
| Groq | 13 | 6 | yes | yes | no | no |
| Cerebras | 2 | 0 | no | no | no | no |
| Sail | 9 | 9 | no | no | no | no |
Three rules follow from that table, and the server enforces all three:
- An unpriced model is cost-unknown, never free. It keeps its place in the answer, after the ranked rows, with a stated reason — otherwise “cheapest across everything” quietly means “cheapest among the rows that happened to carry a number”.
- No deprecation signal is not the same as no risk. Groq and Cerebras publish none, so their models report unforeseeable rather than a reassuring none. For those two, a model vanishing is the only retirement notice there ever is.
- Stale data announces itself. When one provider's catalogue was last confirmed days before another's, the answer says so instead of presenting a mixed-age comparison as current.
What it can tell you that one provider cannot
The same model, on the same day, across two providers:
openrouter openai/gpt-oss-120b in $0.037/M out $0.17/M
groq openai/gpt-oss-120b in $0.150/M out $0.60/M
Measured 2026-08-27. Four times cheaper on one provider than the other, for the identical model — the comparison a single-vendor tool cannot make.
Sail, and why a price carries its window
Sail publishes no prices programmatically. There is no catalogue endpoint to read, only a pricing document written for people — so the server reads that document, pins it by sha256, and parses the billing windows out of it.
The pin is the feature, not a detail. When the document’s digest does not match
the pinned value, every Sail model is dropped from the answer and the response says
PRICES ARE STALE and names the mismatch. It never falls back to prices it cannot
vouch for. A router quoting a stale price is worse than one that returns nothing, because the
caller cannot tell the difference.
Sail prices the same model differently by completion window — asap,
balanced and flex — so the window is part of the price rather than a
note about it. Two rows can carry identical numbers and require different settings to obtain,
and a caller who omits the setting pays the ASAP rate. Every Sail row therefore carries
pricingWindow naming the window its price came from, and
latencyTolerance is an input to the query.
| Sail models with prices | All three windows | Fewer windows |
|---|---|---|
| 9 | 4 | 5 |
Five of the nine publish only one or two windows, so what you asked for is not always what is
available. The rule is never slower than you asked for: a flex request will
accept a balanced or asap price if that is all the model publishes, and
pricingWindow says which one you got. An asap request is the strict case
— a model that publishes only flex is left out of the answer rather than quoted
at a price you could not obtain at that latency.
Roadmap — not built yet
Longer price history
Free-to-paid detection shipped in 0.2.0, and it compares the two most recent collection runs — so it answers “did anything change since the last collection”, not “what has this model cost over the past month”. 0.4.0 made that limit explicit in every answer rather than leaving it to be discovered, which is the honest version of the gap but not a closing of it. The archive retains a price observation per model per run, so a longer window — and the run dates that would let coverage actually be established — are a read away rather than new collection.
Automated switching
Deliberately out of scope for the server, which stays read-only so it can ship inside a distributed application without carrying a credential. The intended path is an agent that reads from here and writes to your own configuration — not a server that reaches into it.
Task-quality fitness
“Satisfies the criteria for the task” is currently as good as the criteria you can state: modality, context, tools, reasoning, availability. Whether a model is actually good enough at your task is not modelled, and a cheap model that passes every structural filter can still be the wrong choice.
Licence and source
MIT licensed. The package is published at
npmjs.com/package/open-dashboard-mcp,
and the server reads a public, zero-credential API; point it elsewhere with
DASHBOARD_BASE_URL.
The repository is not public yet, so there is no source link to give you. Its history carries infrastructure names that have to come out before it can be opened, and deleting a file does not remove it from the commits behind it. Saying “open source” over a link that 404s would be the same kind of claim this page spends the rest of its length refusing to make.