@cyanheads/onebusaway-mcp-server
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., "@@cyanheads/onebusaway-mcp-serverShow me real-time arrivals for stop 1_75403"
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.
Public Hosted Server: https://onebusaway.caseyjhand.com/mcp
Overview
Real-time transit data and schedules from OneBusAway. It defaults to the Puget Sound instance (King County Metro, Sound Transit, Pierce Transit, Community Transit, and more) and works with any other OneBusAway instance. Find stops and routes, track live arrivals and vehicle positions, and pull full-day schedules, vehicle blocks, and service alerts. Runs as a stdio process, a local Streamable HTTP server, or the public hosted endpoint above.
Tools
Tool | Description |
| List the transit agencies on the instance, with IDs, contact info, and coverage area |
| Find stops near a lat/lon, optionally filtered by stop code |
| Resolve a stop name or code to a stop ID |
| Fetch one stop by ID |
| Find routes near a lat/lon, optionally filtered by name or number |
| Resolve a route name or number to a route ID |
| Fetch one route by ID |
| List every route an agency operates |
| Real-time arrivals and departures at a stop, with schedule deviation, vehicle positions, and active alerts |
| Stop details, real-time arrivals, and full detail for every alert at the stop, from one upstream request |
| Full service alert detail by situation ID |
| Real-time status and stop sequence for a trip |
| Every trip one vehicle runs in a service day, in order, with stop times |
| Real-time positions of an agency's active vehicles, optionally for one route |
| Full-day departure schedule for a stop, by route and direction |
| Full-day schedule for a route: every trip and its stop sequence |
Resources
Resource | Description |
| Stop metadata: name, coordinates, served routes, wheelchair accessibility |
| Route metadata: short name, description, agency, schedule URL |
The same data is available to tool-only clients through onebusaway_get_stop and onebusaway_get_route.
Related MCP server: mcp-opiny
Capability reference
onebusaway_list_agencies tool
No input; returns every agency with
id, contact info,timezone, andcoverageCenter/coverageSpanlimitExceededflags an upstream-capped list, with no pagination to fetch the rest
onebusaway_find_stops tool
lat/lonrequired;radiusin meters, default 300, max 1600; optionalquerymatches the stop code printed on the signEach stop carries
id,code,direction,routeIds, andwheelchairBoarding(ACCESSIBLE/NOT_ACCESSIBLE/UNKNOWN);limitExceededmeans more stops exist within the radius
onebusaway_search_stops tool
query(stop name fragment or stop code) required;maxCountup to 100, default 10Same stop shape as
onebusaway_find_stops;limitExceededmeans more stops matched thanmaxCount
onebusaway_get_stop tool
Single
stopId; returnsname,code, coordinates,direction,routeIds, andwheelchairBoardingUnknown IDs fail as
stop_not_found, with recovery viaonebusaway_find_stopsoronebusaway_search_stops
onebusaway_find_routes tool
lat/lonrequired;radiusin meters, default 500, max 1600, or alatSpan+lonSpanbox (both set) in its place; optionalqueryby route name or numberEach route carries
shortName,longName,agencyId, GTFStype(0=tram … 5=cable_car),color, and scheduleurl;limitExceededmeans more routes exist in the area
onebusaway_search_routes tool
query(route name or number) required;maxCountup to 100, default 10Returns
shortName,longName,agencyId, and GTFStype;limitExceededmeans more routes matched thanmaxCountFails as
endpoint_unavailableon instances whose route-search endpoint returns 404, Puget Sound among them; useonebusaway_find_routesoronebusaway_list_routes_for_agencyinstead
onebusaway_get_route tool
Single
routeId; returnsshortName,longName,description, agency, GTFStype,color, and scheduleurlUnknown IDs fail as
route_not_found, with recovery viaonebusaway_find_routesoronebusaway_search_routes
onebusaway_list_routes_for_agency tool
agencyIdrequired; unknown agencies fail asagency_not_foundEvery route with
shortName,longName, GTFStype,color, andurl;limitExceededflags an upstream-capped list with no pagination
onebusaway_get_arrivals tool
stopIdrequired; the window isminutesBefore(integer 0–60, default 5) /minutesAfter(integer 0–240, default 35), with longer horizons left toonebusaway_get_schedule_for_stop; unknown stops fail asstop_not_foundEach arrival carries
predicted(false = schedule-only),scheduleDeviationin seconds (positive = late, meaningful only when predicted),predictedArrivalTime,vehiclePosition,stopsAway, andtripIdActive alerts arrive in
situations[]: those on the stop itself plus those linked from each arrival'ssituationIds, each once
onebusaway_get_stop_context tool
Same input as
onebusaway_get_arrivals, and the samestop_not_found/rate_limitedfailures; one call issues one upstream requestReturns
stop(theonebusaway_get_stopfields minusrouteIds),arrivalsin theonebusaway_get_arrivalsshape, andalertsin theonebusaway_get_alertshape — every alert on the stop or on an arrival in the window, including stop-wide alerts no arrival in the window carriesWhen the upstream response omits the stop,
stopis null; a referenced alert missing from the response is left out; either way anoticenames the tool to fetch it with
onebusaway_get_alert tool
Single
situationId, fromonebusaway_get_arrivals(situations[].idorarrivals[].situationIds); unknown IDs fail assituation_not_foundReturns a TPEG
reasoncode,severity,consequenceMessage,affects(agency, route, stop, or trip scope),consequenceswith diversion stop IDs, andactiveWindows
onebusaway_get_trip tool
tripIdrequired;serviceDateMs(non-negative integer, midnight local) only for a trip on a previous service day;includeSchedule(default true) adds the stop sequence with GTFS times anddistanceAlongTripMetersstatuscarriesphase(e.g.in_progress,layover_before),predicted,position,scheduleDeviation, andnextStop;blockId(null when the trip has none) feedsonebusaway_get_blockFails as
trip_not_foundwhen the trip isn't active for the service date; a completed trip's times come fromonebusaway_get_schedule_for_route
onebusaway_get_block tool
Single
blockId, fromonebusaway_get_trip; unknown IDs fail asblock_not_foundThe vehicle's trips for the service day in order, each with
distanceAlongBlock,accumulatedSlackTime(layover seconds), andblockStopTimes;activeServiceIds/inactiveServiceIdsshow which service calendars apply
onebusaway_get_vehicles tool
agencyIdrequired, unknown agencies fail asagency_not_found; optionalrouteIdis filtered client-side after all of the agency's vehicles are fetchedEach vehicle carries
position,orientation,phase,scheduleDeviation,tripId,nextStop, andpredicted(reporting real-time GPS);limitExceededflags an upstream-capped list with no pagination
onebusaway_get_schedule_for_stop tool
stopIdrequired; optionaldateas a realYYYY-MM-DDcalendar date, default (omitted or blank) today in the agency's timezone; unknown stops fail asstop_not_foundDepartures grouped by route and direction, each with
scheduledDepartureTimeandtripIdStatic schedule only; live predictions come from
onebusaway_get_arrivals
onebusaway_get_schedule_for_route tool
routeIdrequired; optionaldateas a realYYYY-MM-DDcalendar date, default (omitted or blank) today; unknown routes fail asroute_not_foundEvery trip that day with
tripId,tripHeadsign,serviceId, and its stop sequenceStatic schedule only; live predictions come from
onebusaway_get_arrivalsat a stop
onebusaway://stop/{stopId} resource
Stop record as
application/json, the same shapeonebusaway_get_stopreturnsstopIdcomes fromonebusaway_find_stopsoronebusaway_search_stops
onebusaway://route/{routeId} resource
Route record as
application/json, the same shapeonebusaway_get_routereturnsrouteIdcomes fromonebusaway_find_routesoronebusaway_search_routes
Features
Built on @cyanheads/mcp-ts-core: stdio and Streamable HTTP transports, pluggable auth (none / jwt / oauth), swappable storage (in-memory, filesystem, Supabase, Cloudflare KV/R2/D1), structured logging with optional OpenTelemetry tracing.
OneBusAway-specific:
Wraps
onebusaway-sdkwith typed error classification (NotFound,RateLimited,ValidationErrorfor an upstream 400,ServiceUnavailable)Defaults to the Puget Sound instance (
api.pugetsound.onebusaway.org), whereONEBUSAWAY_API_KEY=TESTworks for development;ONEBUSAWAY_BASE_URLpoints it at any other OneBusAway instanceStop and route IDs are agency-prefixed,
{agencyId}_{localId}(stop1_75403, route1_100259); agency IDs are the bare prefix (1for Metro Transit,40for Sound Transit)One shared pacer, sized by
ONEBUSAWAY_RATE_LIMIT_*, queues every upstream request against the API key's budget; a call that gets no slot within the wait cap fails as retryablerate_limitedwithdata.retryAfter, on any toolTransit data only, no trip planning; server-level instructions walk agents through the ID format and the common lookup chains
Agent-friendly output:
predictedon every arrival, trip, and vehicle separates GPS-tracked data from schedule-only projectionsMachine-readable times:
scheduleDeviationin seconds; arrival, stop-schedule, and update timestamps in Unix milliseconds; trip, route-schedule, and block stop times in GTFS seconds from midnightChainable IDs:
stopIdfrom the stop tools feeds arrivals,tripIdfeedsonebusaway_get_trip,blockIdfeedsonebusaway_get_block,situationIdsfeedonebusaway_get_alert, andagencyIdfeeds vehicles and route listingTyped error contracts whose recovery hints name the next tool to call, plus a
noticeon empty or truncated results
Getting started
Public Hosted Instance
A public instance is available at https://onebusaway.caseyjhand.com/mcp — no installation required. Point any MCP client at it via Streamable HTTP:
{
"mcpServers": {
"onebusaway-mcp-server": {
"type": "streamable-http",
"url": "https://onebusaway.caseyjhand.com/mcp"
}
}
}Self-Hosted / Local
Add the following to your MCP client configuration file. ONEBUSAWAY_API_KEY=TEST works on the Puget Sound instance without registration.
{
"mcpServers": {
"onebusaway-mcp-server": {
"type": "stdio",
"command": "bunx",
"args": ["@cyanheads/onebusaway-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info",
"ONEBUSAWAY_API_KEY": "TEST"
}
}
}
}Or with npx (no Bun required):
{
"mcpServers": {
"onebusaway-mcp-server": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@cyanheads/onebusaway-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info",
"ONEBUSAWAY_API_KEY": "TEST"
}
}
}
}Or with Docker:
{
"mcpServers": {
"onebusaway-mcp-server": {
"type": "stdio",
"command": "docker",
"args": [
"run", "-i", "--rm",
"-e", "MCP_TRANSPORT_TYPE=stdio",
"-e", "ONEBUSAWAY_API_KEY=TEST",
"ghcr.io/cyanheads/onebusaway-mcp-server:latest"
]
}
}
}For Streamable HTTP, set the transport and start the server:
MCP_TRANSPORT_TYPE=http MCP_HTTP_PORT=3010 ONEBUSAWAY_API_KEY=TEST bun run start:http
# Server listens at http://localhost:3010/mcpPrerequisites
Bun v1.4.0 or higher (or Node.js v24+).
A OneBusAway API key.
TESTworks on the Puget Sound instance for development; for production use or other instances, register at the relevant agency's developer portal.
Installation
Clone the repository:
git clone https://github.com/cyanheads/onebusaway-mcp-server.gitNavigate into the directory:
cd onebusaway-mcp-serverInstall dependencies:
bun installConfigure environment:
cp .env.example .env
# edit .env — set ONEBUSAWAY_API_KEY if neededConfiguration
Variable | Description | Default |
| OneBusAway API key. |
|
| Base URL of the OneBusAway instance. |
|
| Upstream requests allowed per window, shared by all callers. |
|
| Width of the sliding rate window, in ms. |
|
| Longest a call waits for a slot before failing as |
|
| Transport: |
|
| HTTP server port. |
|
| HTTP session mode: |
|
| Authentication: |
|
| Log level ( |
|
| Directory for log files (Node.js only). |
|
| Storage backend: |
|
| Enable OpenTelemetry. |
|
See .env.example for the full list of optional overrides.
Running the server
Local development
Build and run the production version:
# One-time build bun run rebuild # Run the built server bun run start:http # or bun run start:stdioRun checks and tests:
bun run devcheck # Lint, format, typecheck, security, changelog sync bun run test # Vitest test suite bun run test:coverage # Test suite with coverage, held to the framework thresholds bun run lint:mcp # Validate MCP definitions against spec
Docker
docker build -t onebusaway-mcp-server .
docker run --rm -e ONEBUSAWAY_API_KEY=TEST -p 3010:3010 onebusaway-mcp-serverThe Dockerfile defaults to HTTP transport, stateless session mode, and logs to /var/log/onebusaway-mcp-server. OpenTelemetry peer dependencies are installed by default — build with --build-arg OTEL_ENABLED=false to omit them.
Project structure
Directory | Purpose |
|
|
| Server-specific env var parsing and validation with Zod. |
| Tool definitions ( |
| Stop and route resource definitions ( |
| OneBusAway service: wraps |
| Vitest tests for the tools, resources, service, and config. |
Development guide
See CLAUDE.md for development guidelines and architectural rules. The short version:
Handlers throw, framework catches — no
try/catchin tool logicUse
ctx.logfor request-scoped logging,ctx.statefor tenant-scoped storageRegister new tools and resources in the
createApp()arrays insrc/index.tsWrap external API calls: validate raw → normalize to domain type → return output schema; never fabricate missing fields
Contributing
Issues are welcome. Run checks and tests before submitting:
bun run devcheck
bun run testLicense
Apache-2.0 — see LICENSE for details.
Transit data from the default Puget Sound OneBusAway API, operated by Sound Transit and King County Metro, is governed by the Sound Transit Transit Data Terms of Use, and users of the hosted endpoint receive it under those terms. Key obligations:
Clause 2: usage metrics are available on request.
Clause 3: data is fetched live from the OneBusAway API and is not modified or cached beyond the request cycle.
Clause 4: you agree to pass substantially similar terms through to any users you provide this data to.
Clause 7: this server does not use Sound Transit trademarks in its name or branding.
This server cannot be deployed
Maintenance
Related MCP Connectors
Query SEC EDGAR filings, XBRL financials, and company data through MCP. STDIO & Streamable HTTP.
Swiss Transport MCP — wraps Transport Open Data API (free, no auth)
Host your MCP tool over streamable HTTP in one command.
OpenAQ MCP — global air-quality measurements via the OpenAQ v3 API.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceMCP server that provides tools for querying live transit data (stops, departures, routes, vehicles, alerts) from any WP GTFS Pro site, enabling AI assistants to answer rider questions.3 npmGPL 2.0
- FlicenseNot gradedqualityCmaintenanceEnables interaction with the Opiny API through MCP, supporting both local STDIO and remote HTTP Stream transports.-
- AlicenseAqualityDmaintenanceEnables querying self-hosted OpenTripPlanner for accurate transit routes via MCP, supporting both stdio and HTTP.3218 npmMIT
- AlicenseNot gradedqualityAmaintenanceExposes the FBI Crime Data Explorer API — crime estimates, agency offense rates, and LEOKA officer safety data via MCP. Supports STDIO or Streamable HTTP transport.93 npm1Apache 2.0