Skip to main content

What you’ll get

A walkthrough of what an agent sees on the Routeur MCP server: the initialize handshake, the tool list, and three tool calls with their real inputs and outputs from 2026-09-17: what is tradeable right now, why two markets are linked and whether prices respect it, and the same question priced on both venues. The last step is the whole session as one Python script with no MCP SDK, so you can see every byte.

Prerequisites

  • An API key in ROUTEUR_API_KEY
  • curl, or Python 3 with requests
  • Every request carries Accept: application/json, text/event-stream. An Accept that names only one of the two is refused with 400
1

Connect

The server is stateless Streamable HTTP: one POST per message, JSON back, no session id to keep. initialize returns the server’s instructions to the model.
Send MCP-Protocol-Version: 2025-06-18 on every request after this.
2

List the tools

38 tools on 2026-09-17: five composed (compare_venues, explain_relation, find_opportunities, market_snapshot, search_markets) and 33 generated from the REST operations (get_market, list_relations, get_relation_proof, get_market_book, get_market_rules, list_flow_signals, and so on). Each carries its input schema and annotations; find_opportunities, trimmed:
resources/list returns seven resources (routeur://concepts/glossary, routeur://concepts/relations, routeur://concepts/leads-and-fees, routeur://concepts/prices, routeur://openapi.json, routeur://categories, routeur://topics) and prompts/list three prompts (scan_for_mispricings, brief_me_on_event, backtest_price_band).
3

Question one: what can I trade right now?

Input
The result carries the answer twice: as text in content[0].text, and as JSON in structuredContent. Observed 2026-09-17 12:41 UTC:
Output (structuredContent)
One row: no lead was fillable and no gap paid, so what is left is a strategy match. An agent should say exactly that, and name the rule as history rather than as a forecast.
4

Question two: why are these two markets linked?

Input
Output (structuredContent, trimmed)
consistent: false on a 1¢ gap is arithmetic, not an opportunity; the note says where to check, and question one already answered it.
5

Question three: price it on both venues

Input
Output (structuredContent, trimmed)
Outcomes are matched across venues by proven equivalence, not by wording: “O/U 8.5” on Polymarket lines up with “Over 8.5 runs scored” on Kalshi because the graph proved them equivalent. The moneyline outcome has one price because only Polymarket lists it in this event.
6

The whole session as one script

No SDK, so every message is visible. The tool ids come from question two.
Python
Output observed 2026-09-17 12:48 UTC:

Read the result

Pitfalls

  • Accept must name both types or neither. Accept: application/json alone is refused with 400 Accept must contain both 'application/json' and 'text/event-stream'; HTTP clients that add a default Accept hit this. Set the full value once on the session.
  • Ask by question and you get search’s fallback. compare_venues and search_markets never come back empty: on 2026-09-17, search_markets {query: "fed decision", cross_venue: true} returned NFL and college-football totals labelled match: "trending", because no listed event matched. Read match (or notes) before quoting a result as the answer to the question.
  • find_opportunities is empty more often than not. executable_only defaults to true and fillable leads are rare. Say “nothing fillable right now” rather than loosening the filter silently; if you do set executable_only: false, the rows say “0 pairs fillable”.
  • Tool calls cost API requests. find_opportunities up to four, market_snapshot five, explain_relation two or three. The per-minute limit and daily quota are the key’s; initialize and tools/list are free.
  • Prices are strings. "0.55" is 55¢ per contract that pays $1. Do not round them to booleans or percentages in the model’s reply without saying so.