TfNSW Trip Planner MCP Server
Click on "Install 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., "@TfNSW Trip Planner MCP ServerPlan a trip from Central Station to Circular Quay at 5pm"
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.
TfNSW Trip Planner MCP Server
An MCP server exposing the
Transport for NSW trip planning APIs to
LLM clients, built on the
tfnsw-trip-planner library.
Ten tools cover stop search, journey planning, live departure boards, service alerts, nearby-stop lookup and live vehicle positions.
Authentication
The server stores no credentials. Every caller supplies their own TfNSW Open Data API key on every request:
X-API-Key: <your TfNSW API key>Get a free key from the TfNSW Open Data portal.
A request without the header gets an error naming the header rather than a
silent failure. apikey <key> and Bearer <key> forms are accepted too, since
TfNSW's own docs use the former.
Each tool call builds a client from that request's key and discards it when the call returns, so one caller's key is never reused for another's request.
HTTP connections are nevertheless pooled process-wide, which cuts roughly
93ms — a TCP and TLS handshake — off every call. The split is deliberate: a
connection pool is keyed by host, not by credential, so it can be shared safely,
whereas the library writes the API key into session.headers and a shared
session would let one caller's key overwrite another's mid-flight.
Related MCP server: Transport NSW API Client MCP
Endpoints
Path | Purpose |
| Streamable HTTP transport — use this |
| Legacy SSE transport, for clients that need it |
| Unauthenticated liveness probe |
| Service description |
Listens on 0.0.0.0:6401; override with the HOST and PORT environment
variables.
Connecting a client
Claude Code
Header support is built in:
claude mcp add --transport http tfnsw https://your-host/mcp --header "X-API-Key: YOUR_KEY"Claude Desktop
Claude Desktop's (and claude.ai's) native "Add custom connector" UI accepts a
URL and OAuth credentials only — it has no field for a custom header, so it
cannot be used with this server. Connect through the
mcp-remote bridge instead (needs Node):
{
"mcpServers": {
"tfnsw": {
"command": "npx",
"args": [
"mcp-remote",
"https://your-host/mcp",
"--transport", "http-only",
"--header", "X-API-Key:${TFNSW_KEY}"
],
"env": { "TFNSW_KEY": "YOUR_KEY" }
}
}
}mcp-remote needs Name:value with no space after the colon. Config lives at
~/Library/Application Support/Claude/claude_desktop_config.json on macOS, or
%APPDATA%\Claude\claude_desktop_config.json on Windows. Restart the app after
editing.
For a client that only speaks the older transport, point it at /sse and pass
--transport sse-only.
Tools
Stops are addressed by numeric ID, so resolve a name with find_stop or
best_stop first, then pass the ID onwards.
Tool | What it does |
| Search stops, wharves, POIs and addresses by name |
| Look up one stop by its numeric ID |
| Return only the single best-matching location for a name |
| Plan a journey between two stop IDs |
| Plan a journey starting from a GPS coordinate |
| Plan a cycling route, optionally mixed with transit |
| Live departure board for a stop or platform |
| Service alerts: disruptions, trackwork, planned changes |
| Stops and POIs near a coordinate, with distances |
| Live GPS positions of vehicles on a network |
Notes:
Times. Tools taking a
whenaccept ISO 8601, e.g.2026-08-30T09:15. Without an offset the value is Australia/Sydney local time. An unparseable value is rejected rather than ignored.Capped results.
get_alerts,find_nearbyandget_vehicle_positionscan each answer with far more than a caller can use — an unfiltered alert fetch returns every alert in NSW (~280, 1.3MB of JSON), and a 500m nearby search can return 600+ locations. They take amax_results(20, 50 and 100 respectively), constrained to>= 1.This is not only about context budget: MCP sends each result twice (as text content and as structured content) and clients cap a single SSE event at 1MiB, so an oversized reply fails outright with "SSE stream ended without a response".
Journey detail.
plan_trip,plan_trip_from_coordinateandplan_cycling_triptake adetaillevel, because the raw response is mostly map geometry. On a real Sydney-to-Katoomba trip the full response is 1.06MB — over the 1MB tool-result limit, so the call fails outright — and 96% of that is data a model never reads:leg field
share of payload
coords(route polyline)72%
stop_sequence24%
times, modes, interchanges, durations
4%
detailincludes
same Katoomba trip
summary(default)times, modes, interchanges, durations
39 KB
stops+ every intermediate stop
301 KB
full+ route polyline
1,061 KB
Every result reports the level it used, so a model can see it was trimmed and ask for more rather than assuming the data does not exist.
fullonly fits when paired withmax_resultsof 1–3.find_stoptakeslimit, notmax_results— deliberately a different name, because it bounds the upstream query rather than truncating a fetched list, socountis exact and no bandwidth is wasted.get_vehicle_positionsreads the GTFS-Realtime feed, which is a separate product on the Open Data portal — your key must be subscribed to it as well. An unrecognisedmodeis rejected with the list of valid feeds rather than being passed through to an opaque upstream 404. The nine valid feeds arebuses,sydneytrains,metro,nswtrains,ferries/sydneyferries,lightrail/cbdandsoutheast,lightrail/innerwest,lightrail/newcastleandlightrail/parramatta.The list is taken from the library rather than restated here, so the two cannot drift. TfNSW serves
sydneytrainsandlightrail/innerwestfrom a v2 endpoint and the rest from v1;tfnsw-trip-planner1.4.0 routes each feed to the version that actually serves it.
Results are returned as structured JSON. Every list-returning tool answers with
the same shape, so returned is always present and count is always the true
total before any capping:
{"count": 618, "returned": 50, "locations": [...]}Single lookups (find_stop_by_id, best_stop) return {"location": {...}},
or {"location": null} when nothing matches.
Running it
Docker (how it is deployed)
docker compose up --build -dcurl -sf localhost:6401/healthSee DEPLOYMENT.md for the Coolify setup.
Local development
uv syncuv run python -m tfnsw_trip_planner_mcpTests
The default suite is fully offline — the library client is mocked, so no key is needed and no request leaves the machine:
uv run pytestSmoke tests against the real API are opt-in and skipped unless a key is present:
TFNSW_API_KEY=your_key uv run pytest -m liveCI
GitHub Actions runs on every push and pull request: ruff, the offline suite,
and a Docker job that builds the image, waits for /health, and checks the
running container lists all 10 tools.
The live tests run on main and on manual dispatch. They skip themselves
unless a TFNSW_API_KEY repository secret exists, so CI is green without one —
add it under Settings → Secrets and variables → Actions to enable them. Fork
pull requests never receive the secret, so they always skip.
Layout
File | Role |
| The 10 tools and their argument mapping |
|
|
| Library dataclasses → JSON-safe structures |
| ASGI app wiring both transports plus |
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceThis server enables large language models to access and interact with real-time transport alerts from Transport for NSW's network, supporting filtering by transport mode and returning formatted alert information about disruptions and planned works.117MIT
- AlicenseBqualityDmaintenanceAn MCP service for interacting with Transport NSW's API that enables users to find transport stops around locations and retrieve information about transport alerts and disruptions.3MIT
- FlicenseNot gradedqualityDmaintenanceProvides access to the TripGo API for multi-modal trip planning, public transport departures, and transport-related location searches. It enables users to calculate routes and retrieve travel information through the Model Context Protocol.5
- AlicenseBqualityDmaintenanceProvides real-time Transport for London journey data, including routes, alerts, and disruptions, allowing AI assistants to search journeys and get station information.1234ISC
Related MCP Connectors
Real-time transit stops, routes, arrivals, vehicle positions, and schedules via OneBusAway APIs.
Gateway between LLM agents and world data through eight tools and a bundled endpoint catalog.
AI marketplace — flights, tours, activities, transport & more via MCP. No auth required.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/maxim75/tfnsw_trip_planner_mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server