Skip to main content
Glama

Mobiliteit.lu MCP

An open-source Model Context Protocol server for Luxembourg public-transport data from the Mobiliteit.lu HAFAS API. It provides nearby-stop lookup, departures, and change notifications for subscribed stops.

The upstream API exposes real-time data as HTTP request/response snapshots. This server polls those snapshots and notifies MCP subscribers when departure data changes; this is near-real-time polling, not an upstream push feed.

Unofficial project. This server is an independent community project. It is not affiliated with, endorsed by, or operated by mobiliteit.lu, the Luxembourg Ministry of Mobility and Public Works, the Administration des transports publics, or HaCon/HAFAS.

Get an API key

You need your own API key before the server can return any data. This server does not contain transport data. It forwards each request to the mobiliteit.lu HAFAS open-data API at https://cdt.hafas.de/opendata/apiserver/, which rejects requests without a valid key (HTTP 401). No key is included with this project; each deployment should use its own.

Keys are issued by the Administration des transports publics (ATP) on request:

  1. Email opendata-api@atp.etat.lu and ask for an API key (accessId) for the mobiliteit.lu open-data API. Say briefly what you are building and roughly how many requests you expect; see Quotas below.

  2. Wait for the ATP to reply with your key, its request quota, and the usage terms. Check that those terms allow what you plan to do, especially if you will host the server for other people.

  3. Store the key outside the repository and give it to the server, either in a file referenced by MOBILITEIT_API_KEY_FILE (preferred) or in the MOBILITEIT_API_KEY environment variable. See configuration and client setup.

Never commit the key, paste it into prompts or chat, or include it in issue reports. .env.example documents the supported settings but is not loaded automatically. Open-sourcing this server does not grant API access or rights to redistribute the provider's data. The ATP publishes the data under CC BY 4.0; credit the ATP as the data source in anything you build on it.

Related MCP server: mcp-sbb-transport

Quotas

Each unique active stop feed is shared by its subscribers and polled once per interval. Defaults are a 30-second interval and one active stop feed. One continuously active feed at that interval makes about 2,880 upstream requests per day, before ordinary lookups and retries. Increase MOBILITEIT_MAX_ACTIVE_FEEDS only after confirming the quota issued for your API key. All upstream calls (tool calls, resource reads and polling) also share a rolling cap, MOBILITEIT_MAX_REQUESTS_PER_MINUTE (default 60), so one client cannot exhaust the key's quota. Failed upstream requests are logged to stderr; existing clients are not given fabricated or silently substituted results.

Transports and clients

Requires Node.js 22 or newer.

npm install
npm test
npm run typecheck
npm run build

For a hosted endpoint, see the step-by-step VPS deployment guide, or the serverless Vercel option for a tools-only endpoint without live subscriptions. It deploys the app with Docker Compose and Caddy-managed HTTPS. This is the recommended route for a trusted pilot; the current HTTP authentication is one shared bearer token, not per-user OAuth.

The default transport for a local installation is MCP over stdio:

node dist/src/index.js

MCP_TRANSPORT supports stdio, http, or both. HTTP listens on 127.0.0.1:3000 by default at /mcp; it requires MCP_HTTP_BEARER_TOKEN or MCP_HTTP_BEARER_TOKEN_FILE. Do not expose the service directly to the public internet without HTTPS and suitable authentication.

Cursor and Claude Desktop can launch the stdio server. Streamable HTTP enables remote clients where their MCP implementation supports it. Ollama support depends on the MCP host used with the model.

MCP tools and resources

  • find_nearby_stops: look up stops by WGS84 coordinates.

  • get_departures: request departures for a stop, including real-time data where supplied by the API.

  • mobiliteit://stops/{stopId}/departures: a resource clients can read and subscribe to. The server sends standard MCP resource-update notifications when a polled snapshot changes; clients can then read the resource again.

The polling interval can be configured with MOBILITEIT_POLL_INTERVAL_SECONDS (minimum 15 seconds). The maximum number of distinct simultaneously active feeds is configured with MOBILITEIT_MAX_ACTIVE_FEEDS.

Security

See SECURITY.md for how to report a vulnerability privately.

License

The server source code is licensed under Apache-2.0. This license does not apply to the upstream transport data, the HAFAS API, or their trademarks and usage terms.

More documentation

Available Tools

2 tools
find_nearby_stopsFind nearby public transport stopsA

Find public transport stops near a WGS84 coordinate in Luxembourg. Use the returned stop id with get_departures or subscribe to its departure resource.

Inputs: latitude (required), longitude (required), limit, language, +1 more.

get_departuresGet departures from a stopA

Get scheduled and real-time public transport departures for a Mobiliteit.lu stop id. Use the id returned by find_nearby_stops.

Inputs: stopId (required), date, time, limit, +2 more.

Tool Schema Changelog

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

Loading tool schema changelog…

    TDQS

    A3.9/5.0

    Scored across 2 tools

    Disambiguation5/5

    The two tools target clearly distinct actions: locating stops by coordinate versus retrieving departures for a known stop id. Their descriptions even cross-reference each other, so an agent can't confuse which to call first.

    Naming Consistency5/5

    Both names use a consistent snake_case verb_noun form (find_nearby_stops, get_departures) with well-chosen verbs that match their actions.

    Tool Count3/5

    Two tools is thin for a public transport server, which normally implies routing, lines, and schedules. The pair covers a narrow departure-board workflow but leaves the broader domain unaddressed.

    Completeness3/5

    Stop lookup and departures form a workable read-only core, but there's no journey planning, line/route info, or name-based stop search — notable gaps for a mobility domain.

    Related MCP Connectors

    Related MCP Servers