idfm-mcp
Provides tools for querying real-time Paris public transport data through the official Île-de-France Mobilités PRIM API, including stop search, next departures, journey planning, and traffic disruptions.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@idfm-mcp When is the next RER B from Gentilly?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
idfm-mcp
An open-source MCP server that lets any AI assistant (Claude Desktop, Cursor, …) answer real-time questions about Paris public transport, using the official Île-de-France Mobilités PRIM API.
"When is the next RER B from Gentilly?" · "Are there disruptions on Metro line 7?" · "How do I get from Bastille to Orly at 18:30?"

Tools
Tool | What it does | PRIM API |
| Find stations by name, with their IDs and lines | Navitia |
| Real-time departures: line, destination, minutes to wait, delay, platform | SIRI Lite |
| Up to 3 routes with duration, transfers and steps | Navitia |
| Current and planned incidents/works, most severe first | Navitia |
Related MCP server: TFL MCP Server for Poke
Architecture
flowchart LR
U([User]) --> C["MCP client<br/>(Claude Desktop, Cursor)"]
C <-->|"MCP over stdio"| S
subgraph S["idfm-mcp"]
direction TB
SV["server.py<br/>4 tools · input resolution<br/>errors → ToolError"]
F["formatting.py<br/>short LLM-readable text"]
CL["client.py<br/>auth · timeouts · typed errors<br/>ID conversion · parsing"]
M["models.py<br/>pydantic models"]
SV --> CL
SV --> F
CL --> M
F --> M
end
CL <-->|"HTTPS + apikey header"| P[("IDFM PRIM API<br/>SIRI Lite + Navitia")]Each layer has one job: client.py is the only code that knows HTTP and raw JSON;
server.py is the only code that knows MCP; formatting.py decides what the LLM reads.
See docs/prim-api.md for the API details and gotchas.
Install
Requirements: uv and a free PRIM API key.
git clone https://github.com/Drathod-24/idfm-mcp.git
cd idfm-mcp
uv sync
cp .env.example .env # then paste your key into .envGet a key: create an account on prim.iledefrance-mobilites.fr, open Mes jetons d'authentification → API → Générer mon jeton. The token is shown only once.
Use with Claude Desktop
Open Settings → Developer → Edit Config (claude_desktop_config.json) and add:
{
"mcpServers": {
"idfm": {
"command": "uv",
"args": ["--directory", "/absolute/path/to/idfm-mcp", "run", "idfm-mcp"],
"env": { "IDFM_API_KEY": "your-prim-api-key" }
}
}
}On Windows, use a path like "C:\\Users\\you\\idfm-mcp". Restart Claude Desktop; the
tools appear under the 🔌 icon. (env is optional if the key is already in .env.)
Cursor uses the same JSON in ~/.cursor/mcp.json.
Test with MCP Inspector
# Interactive web UI
npx @modelcontextprotocol/inspector uv --directory . run idfm-mcp
# Or scripted (CLI mode)
npx @modelcontextprotocol/inspector --cli uv --directory . run idfm-mcp --method tools/list
npx @modelcontextprotocol/inspector --cli uv --directory . run idfm-mcp \
--method tools/call --tool-name search_stop --tool-arg query=GentillyExample questions and answers
These are the tools' real output formats, produced from the test fixtures (times are illustrative):
"When is the next RER B from Gentilly?" → next_departures(stop_id="Gentilly", line="RER B")
Next departures at Gentilly (stop_area:IDFM:63244) (now 09:25):
- RER B → Aéroport CDG 2 TGV: now, 09:26
- RER B → Saint-Rémy-lès-Chevreuse: in 8 min, 09:33 (+2 min vs schedule, platform 2)"Are there disruptions on Metro line 7?" → traffic_disruptions(line="Metro 7")
1 disruption(s) for Métro 7:
- [Métro 7] Métro 7 : trafic perturbé — reduced service
En raison de travaux, le trafic est interrompu entre Place d'Italie et Villejuif. Des bus de remplacement sont mis en place.
Until 05/11 23:00
(1 elevator/escalator notices not shown.)"How do I get from Gentilly to Étoile at 9:30?" → plan_journey(from_place="Gentilly", to_place="Étoile", departure_time="09:30")
Routes from Gentilly to Étoile:
Option 1: 09:30 → 10:02 (32 min, 1 transfer)
1. Walk 4 min to Gentilly
2. RER B toward Aéroport CDG 2 TGV: Gentilly → Châtelet les Halles (09:34–09:45)
3. Change: walk 5 min to Châtelet
4. Métro 1 toward La Défense: Châtelet → Charles de Gaulle - Étoile (09:50–10:02)Errors are answers too: a missing key, a bad stop ID, a 429 quota error or a timeout
comes back as a clear MCP error (isError: true), never a crash:
IDFM API quota exceeded (default: 5 requests/second, 1000/day). Wait a bit before retrying.Development
uv run pytest # 68 tests; every PRIM call is mocked with respx, no key needed
uv run pytest -m live # optional: ~5 real calls to check fixtures match the real API
uv run ruff check . && uv run ruff format --check .CI (GitHub Actions) runs ruff, pytest and the eval dataset check on Python 3.11–3.13 on every push.
Evals
evals/questions.json has 20 natural-language questions (English
and French, plus one off-topic) with the acceptable first tool call for each. The runner
reads the tool definitions from the server itself, asks Claude which tool it would
call, and scores tool name + arguments. It tests the docstrings, which are what an LLM
actually sees.
uv run python evals/run_evals.py --offline # validate the dataset (runs in CI)
uv run --group evals python evals/run_evals.py # live run, needs ANTHROPIC_API_KEYCategory | Cases | Passed |
Next departures | 6 | pending |
Stop search | 3 | pending |
Journey planning | 5 | pending |
Disruptions | 5 | pending |
Off-topic (no tool) | 1 | pending |
Total | 20 | pending |
Full per-question results: evals/results.md. The live eval has not been run yet.
Limitations
Real-time coverage is partial: PRIM does not provide live data for every stop yet; an empty list is a normal answer.
Default quota is 1,000 requests/day per API.
next_departuresuses 1–3 calls (name lookup, line names, departures). There is no caching yet.Test fixtures are synthetic, built from the docs; run
pytest -m livewith a key to check them against the real API.Line resolution is heuristic: a bare number ("7") is assumed to be a Metro line.
plan_journeytakes the best match for free-text places and does not ask when names are ambiguous.The eval tests only the first tool call, not multi-turn conversations or answer quality.
Next steps
Cache stop/line lookups (they rarely change) to save quota
Record real API responses as fixtures
Multi-turn evals: score the final answer, not just the routing
Streamable HTTP transport for remote deployment
Accessibility: expose elevator outages as their own tool
Publish to PyPI so it runs with
uvx idfm-mcp
License
MIT. Data from Île-de-France Mobilités via PRIM, under the Mobility License / ODbL. This project is not affiliated with Île-de-France Mobilités, RATP or SNCF.
Available Tools
4 toolsnext_departuresARead-only
Get the next real-time departures at a station, with minutes until departure.
Use for questions like "When is the next RER B from Gentilly?" or "Next metro at
Bastille?". Shows line, destination, minutes to wait, delay and platform.
Args:
stop_id: Station ID from search_stop (e.g. "stop_area:IDFM:63244"). A plain
station name also works; the best match is used.
line: Optional line filter, e.g. "RER B", "Metro 7", "Tram T3a", "Bus 57".
Leave empty to get all lines at the station.
Inputs: stop_id (required), line.
plan_journeyARead-only
Plan a public transport journey between two places in Île-de-France.
Use for "How do I get from X to Y?" or "Fastest way to Orly from Bastille at 18:00?".
Returns up to 3 options with total duration, number of transfers and each step
(lines to take, where to change, walking time).
Args:
from_place: Origin: station name, address or landmark (e.g. "Gentilly",
"Tour Eiffel", "10 rue de Rivoli Paris") or a stop ID from search_stop.
to_place: Destination, same formats as from_place.
departure_time: Optional, Paris local time: "18:30" (today) or
"2026-11-05T18:30". Defaults to now.
Inputs: to_place (required), from_place (required), departure_time.
search_stopARead-only
Find Paris / Île-de-France stations and stops by name and return their IDs.
Use this first when the user names a station (e.g. "Gentilly", "Châtelet",
"Gare de Lyon") and you need its ID for next_departures. Returns up to 5 matches
with the lines serving each one, so you can pick the right station.
Args:
query: Station or stop name, in French or English spelling. e.g. "Gentilly".
Inputs: query (required).
traffic_disruptionsARead-only
Get current traffic disruptions, incidents and works on the Île-de-France network.
Use for "Are there problems on Metro 7?", "Is the RER A running?" or "Any
disruptions right now?". Returns active and planned disruptions, most severe first.
Elevator/escalator outages are counted but not listed.
Args:
line: Optional line, e.g. "Metro 7", "RER B", "Tram T2", "Transilien L".
Leave empty for a network-wide summary.
Inputs: line.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 4 tools
Each tool maps to a clearly distinct transit task: station lookup, real-time departures, journey planning, and disruption status. There is little risk of misselection, and descriptions reinforce the boundaries between tools.
Two tools follow a verb_noun pattern (search_stop, plan_journey), but next_departures is an adjective_noun phrase and traffic_disruptions is a noun_noun phrase. The names are readable and individually clear, but the set does not follow one predictable convention.
Four tools is well-scoped for a focused Île-de-France transit query server. Each tool serves a distinct core user need, and there are no redundant or filler tools.
The server covers the main transit workflows: finding stops, checking next departures, planning journeys, and viewing disruptions. Minor gaps remain, such as line-level details, fare information, or accessibility-specific queries, but agents can handle core tasks without dead ends.
Maintenance
Related MCP Connectors
Plan door-to-door trips across French trains, buses, transit and flights.
Mobility, geocoding and nearby urban services for AI agents.
Belgian trains for AI agents: live journeys, departures, delays, disruptions. Free, no key.
Read-only public transit departures, stop search, and city coverage for bus and train users.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceProvides real-time access to Paris public transport data (métro, RER, bus, tram, Transilien) including live departure times and traffic disruptions through the IDFM PRIM API.2MIT
- FlicenseNot gradedqualityDmaintenanceEnables AI assistants to access real-time Transport for London data, including tube/bus arrivals, line status, journey planning, and disruptions.1-
- AlicenseBqualityDmaintenanceProvides real-time Transport for London journey data, including routes, alerts, and disruptions, allowing AI assistants to search journeys and get station information.17 npm4ISC
- AlicenseNot gradedqualityBmaintenanceEnables AI assistants to query live Transport for London data, including service status, arrivals, journey planning, bike points, crowding, and fares.1MIT