metrotransit-mcp
Provides Google Gemini tool declarations and handlers for accessing Metro Transit departures, routes, stops, and service alerts.
Provides OpenAI function definitions and handlers so OpenAI agents can retrieve Metro Transit departures, routes, stops, and alerts.
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., "@metrotransit-mcpwhat are the next departures at stop 51408?"
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.
metrotransit-mcp
A unified Model Context Protocol (MCP), Command Line Interface (CLI), and Agent Capabilities Protocol (ACP) toolkit for Metro Transit in the Minneapolis–Saint Paul metropolitan area.
Connect your AI assistants (Claude Desktop, Cursor, Antigravity, custom agents) or query directly from your terminal for real-time bus & light rail departures, station search, route schedules, and live alerts.
Zero API keys or signups required — built on Metro Transit's open public REST API.
What's Included
🔌 MCP Server: Stdio server implementing the official Model Context Protocol for Claude, Cursor, Antigravity, and other MCP clients.
💻 Interactive CLI: Beautiful terminal tool for departures, routes, directions, stops, and incident reports.
🤖 ACP (Agent Capabilities Protocol): Ready-to-use function calling declarations and execution handlers for OpenAI, Anthropic Claude, and Google Gemini agents.
📜 Downloaded OpenAPI / Swagger Specs: Full OpenAPI 3.0.4 definitions for NexTrip v2, Alerts v1, Trip Planner v1, and Schedule v1 included in
spec/.
Related MCP server: BusTime MCP
1. CLI Usage
You can run commands directly using npx metrotransit-mcp <command> or by installing globally (npm i -g metrotransit-mcp).
# List all routes or search by name/number
metrotransit routes
metrotransit routes green
metrotransit routes 94
# Show route travel directions
metrotransit directions 902
# List stops for a route in a specific direction (0 = EB/NB, 1 = WB/SB)
metrotransit stops 902 0
# Search for a station on a route
metrotransit search 902 "U.S. Bank"
metrotransit search 902 "Nicollet"
# Live countdown departure board by Stop ID (posted at bus stops & platforms)
metrotransit departures 51408
# Live countdown departure board by Route + Direction + Place Code
metrotransit departures 902 0 5SNI
# Check active detours, service advisories, and closures
metrotransit alerts
metrotransit alerts 902
metrotransit alerts 94 --keyword detour
# Inspect downloaded OpenAPI / Swagger specs
metrotransit spec2. Model Context Protocol (MCP) Setup
Run via NPX
npx metrotransit-mcp(When launched by an MCP client or without arguments on a piped stdio, it automatically starts the MCP server).
Claude Desktop Configuration
Add to your claude_desktop_config.json:
macOS / Linux
{
"mcpServers": {
"metrotransit": {
"command": "npx",
"args": ["-y", "metrotransit-mcp"]
}
}
}Windows
{
"mcpServers": {
"metrotransit": {
"command": "cmd.exe",
"args": ["/c", "npx", "-y", "metrotransit-mcp"]
}
}
}Cursor / Antigravity / Other MCP Clients
{
"mcpServers": {
"metrotransit": {
"command": "node",
"args": ["/path/to/metrotransit-mcp/dist/index.js", "mcp"]
}
}
}MCP Tools Provided
list_routes– List or search all Twin Cities transit routes.get_route_directions– Get directional travel options (Eastbound/Westbound, Northbound/Southbound).get_route_stops– Get all stations/stops and place codes for a route.search_stops– Fuzzy search stations along a route.get_departures– Live GPS countdowns, departure times, and stop alerts by 4–5 digit Stop ID or Route + Place Code.get_service_alerts– Check active detours, stop closures, or incident advisories.
3. Agent Capabilities Protocol (ACP)
Need to equip a custom agent with Metro Transit tools without MCP?
Run:
# Output OpenAI function definitions
metrotransit acp --format openai
# Output Anthropic tool definitions
metrotransit acp --format anthropic
# Output Google Gemini tool declarations
metrotransit acp --format geminiOr import directly in TypeScript / JavaScript:
import {
getOpenAITools,
getAnthropicTools,
getGeminiTools,
executeAgentTool,
} from "metrotransit-mcp";
// 1. Pass tool definitions to your model
const tools = getOpenAITools();
// 2. Execute when tool is called
const result = await executeAgentTool("metrotransit_get_departures", {
stop_id: 51408,
});4. OpenAPI / Swagger Specs
The repository includes the official OpenAPI 3.0.4 schemas directly in the spec/ folder:
spec/nextrip-v2.json: Real-time vehicle positions, arrival countdowns, and routes.spec/alerts-v1.json: Incident alerts, construction reroutes, and detours.spec/tripplanner-v1.json: Transit itinerary planning and geocoding.spec/schedule-v1.json: Static timetable schedules and planned stop details.
Development & Testing
# Install dependencies
npm install
# Build
npm run build
# Run unit tests
npm test
# Test CLI
node dist/index.js departures 51408License
MIT © Amin
Available Tools
6 toolsget_departuresA
Get real-time departure predictions, vehicle countdowns, and stop alerts for a Metro Transit stop or station. You can query either by a 4-5 digit Stop ID, or by Route ID + Direction ID + Place Code.
| Name | Required | Description | Default |
|---|---|---|---|
| stop_id | No | The 4-to-5 digit Stop ID (posted on bus stop signs and train platforms, e.g. 51408 for Nicollet Mall Station). | |
| route_id | No | Route ID (e.g. '902' for Green Line). | |
| place_code | No | Station place code (e.g. '5SNI', 'TF1', 'WARE', from get_route_stops). | |
| direction_id | No | Direction ID (0 or 1). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
There are no annotations, so the description carries the behavioral disclosure burden. It does disclose that the tool returns real-time predictions, countdowns, and alerts, which conveys read-only behavior. However, it does not clarify that no parameters are marked required in the schema despite needing at least one query mode, nor does it describe error behavior or what happens if conflicting parameters are supplied.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two sentences, front-loads the core purpose, and adds the key query-mode distinction without any filler. Every sentence earns its place, and the structure makes the tool's behavior immediately understandable.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description covers the tool's purpose and the two query modes, but it does not explicitly state that at least one mode is required, despite the schema listing zero required parameters. There is no output schema, so the description's brief mention of predictions, countdowns, and alerts partially compensates, but the missing invocation constraint leaves a meaningful gap for correct usage.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds meaningful grouping by explaining that parameters can be combined as either a Stop ID or a Route ID + Direction ID + Place Code. This adds relational meaning beyond the individual parameter descriptions in the schema, although it stops short of explaining mutual exclusivity or required groups.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb ('Get') with a clear resource ('real-time departure predictions, vehicle countdowns, and stop alerts') and scopes it to 'a Metro Transit stop or station.' It is clearly distinct from the sibling tools like get_route_stops or get_service_alerts, so an agent can identify what this tool is for without ambiguity.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explains the two accepted query modes ('Stop ID' or 'Route ID + Direction ID + Place Code'), which gives practical input guidance. However, it does not explicitly say when to prefer this tool over siblings, nor does it mention exclusions or conditions such as needing get_route_stops to obtain a place code. Usage is implied rather than fully spelled out.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_route_directionsA
Get valid travel directions for a specific route (e.g., Eastbound/Westbound, Northbound/Southbound) and their direction IDs.
| Name | Required | Description | Default |
|---|---|---|---|
| route_id | Yes | Route ID (e.g. '902' for Green Line, '901' for Blue Line, '94', '4'). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden. 'Get' implies a read operation, but the description does not disclose rate limits, error behavior for invalid route IDs, whether data is cached, or any other behavioral traits.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single, front-loaded sentence that conveys the operation, scope, and output with no wasted words.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple one-parameter lookup, the description is largely complete: it states the input, the resource, and what is returned (directions and direction IDs). No output schema exists, so this return information is valuable, though it could mention how the returned direction IDs are intended to be used.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, and the schema already documents route_id with examples. The description adds no parameter-level detail beyond the schema, which is acceptable given full coverage.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific verb and resource: 'Get valid travel directions for a specific route' and clarifies the output as direction IDs. This clearly distinguishes it from sibling tools like get_route_stops, get_departures, and list_routes.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies when to use the tool: when you need valid directions for a specific route. However, it does not explicitly state when not to use it or name alternatives, leaving the usage context implicit rather than explicit.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_route_stopsA
Get all scheduled stops for a route in a specific direction, including their place codes and station descriptions.
| Name | Required | Description | Default |
|---|---|---|---|
| route_id | Yes | Route ID (e.g. '902', '901', '94'). | |
| direction_id | Yes | Direction ID (0 or 1, obtained from get_route_directions). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden of behavioral disclosure. It states the operation is 'Get all scheduled stops', implying a read-only action, and mentions the return includes place codes and station descriptions. However, it does not disclose potential limitations (e.g., no real-time updates, no pagination), authentication requirements, or what happens if no stops exist. It is minimally transparent but not misleading.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single sentence that front-loads the action and includes the key output detail (place codes and station descriptions). Every word earns its place; there is no filler or redundant phrasing.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's simplicity (2 parameters, no output schema, no annotations), the description is largely sufficient. It tells the agent what the tool returns (stops with place codes and descriptions) and the necessary parameters are fully defined in the schema. The only missing piece is explicit usage guidance relative to siblings, but that is not critical for correctly calling this tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, meaning the input schema already fully documents both route_id and direction_id, including examples and the source of direction_id. The description adds no extra parameter semantics beyond what the schema provides, so it meets the baseline for high coverage without adding value.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states a specific verb ('Get') and resource ('scheduled stops for a route in a specific direction'), and even specifies the output content ('place codes and station descriptions'). This distinguishes it from siblings like get_route_directions (which returns directions) and get_departures (which returns departure times), so an agent can easily tell what this tool does.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description does not explicitly state when to use this tool versus alternatives or any exclusions. It implies usage by naming 'route' and 'direction', but the prerequisite that direction_id comes from get_route_directions is only mentioned in the schema, not the description. There is no guidance on when not to use it, so the usage context is only implied.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_service_alertsA
Get active service alerts, detours, stop closures, and disruptions across the Metro Transit network, optionally filtered by route ID or keyword.
| Name | Required | Description | Default |
|---|---|---|---|
| keyword | No | Optional keyword to filter alerts (e.g. 'Vikings', 'closure', 'detour'). | |
| route_id | No | Optional route ID to filter alerts (e.g. '902', '901', '94'). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden. It mentions 'active' alerts but does not disclose response format, pagination, data freshness, authorization requirements, or what happens when no alerts match. The behavior beyond the basic 'get' is underexplained.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single, front-loaded sentence that conveys the purpose and filters without redundancy. Every word contributes value.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The tool is simple with two optional parameters and no output schema, but the description does not describe the return structure or any edge-case behavior. An agent knows when to call it and what to pass, but not what to expect back, which is a notable gap.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, with both parameters having clear descriptions. The description adds minimal extra value by noting the filters are optional, but does not introduce new semantic details beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states a specific action (Get) on a specific resource (service alerts, detours, stop closures, disruptions) across the network, with optional filters. This distinguishes it from sibling tools that focus on routes, stops, and departures.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies usage for alert-related queries but does not explicitly mention when to use this tool over siblings or provide exclusions. The context of the sibling names makes it inferable, but no direct guidance is given.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_routesA
Get all Metro Transit routes in the Minneapolis-St. Paul metro area (METRO Blue/Green/Gold/Orange/Red/A/B/C/D/E lines and bus routes). Supports optional filtering by search query.
| Name | Required | Description | Default |
|---|---|---|---|
| query | No | Optional search string to filter routes by name or number (e.g. 'green', 'blue', 'orange', '94', 'e line'). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden. The verb 'Get' and the phrase 'Supports optional filtering' disclose read-only behavior and filter support, but the description does not mention response structure, route identifiers, or edge cases like empty results. That is acceptable for a simple listing tool but not rich disclosure.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single front-loaded sentence: it states the core action first, then the optional filtering behavior. The enumeration of line names and bus routes is somewhat redundant with 'all routes' but remains compact and useful for clarifying scope.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The tool is simple: one optional parameter, no required arguments, and no nested objects. The description supplies the geographic scope, route categories, and filter capability, which is enough to invoke it correctly. The lack of an output schema means response field details are not described, but that is a minor gap for a basic list-all-routes tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, and the input schema already documents the optional query parameter with examples. The description only restates that filtering is supported, adding no meaning beyond the structured schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb ('Get') and resource ('all Metro Transit routes'), with geographic scope and route categories. Brother tools like get_route_directions, get_route_stops, and get_departures are clearly narrower, so list_routes is easily distinguishable as the route-catalog tool.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies usage when a full or filtered route list is needed, and the optional query hint gives some context. However, it never explicitly says when to use this tool versus siblings such as search_stops, and it provides no when-not-to-use guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_stopsA
Search for stops/stations along a specific route by keyword or station name (e.g., search 'Stadium' or 'Nicollet' on the Green Line).
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | Text to search in the stop name/description. | |
| route_id | Yes | Route ID (e.g. '902', '901', '94'). | |
| direction_id | No | Direction ID (0 or 1). Default is 0 if omitted. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden of behavioral disclosure. It discloses that the search is route-scoped, but does not specify whether results are limited to that route, what happens with no matches, or the return format. It does not contradict anything but adds minimal behavioral context beyond the core action.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
One sentence with a concrete example, no filler. The core purpose is front-loaded and the example aids comprehension. Extremely efficient.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Tool is simple, but without an output schema, the description should hint at what is returned. It does not mention that it returns a list of matching stops or any field details. Also does not clarify direction_id behavior beyond the schema. Adequate for basic usage but leaves some expectations unstated.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema covers 100% of parameters, so baseline is 3. The description adds an example for query but does not elaborate on query semantics beyond 'keyword or station name' or the role of direction_id. It provides marginal extra value over the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Clearly states the verb 'search' with resource 'stops/stations', scoped to 'along a specific route', and method 'by keyword or station name'. Provides a concrete example and implicitly differentiates from sibling get_route_stops which likely lists all stops. The purpose is unambiguous and actionable.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Does not explicitly state when to use this tool versus alternatives such as get_route_stops. The description implies that it is for keyword-based lookup, but there is no guidance on when not to use it, or how it compares to listing all stops. An agent must infer the appropriate context from the sibling names.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
6 tool updates
v1.1.0- First observed
get_departures - First observed
get_route_directions - First observed
get_route_stops - First observed
get_service_alerts - First observed
list_routes - First observed
search_stops
TDQS
Scored across 6 tools
Each tool targets a distinct transit resource (routes, directions, stops, departures, alerts), but get_route_stops and search_stops overlap in purpose—one returns all stops while the other filters them by keyword. Descriptions are clear enough to differentiate, though minor boundary ambiguity exists.
All tool names follow a consistent snake_case verb_noun pattern (list_routes, get_route_directions, get_departures, search_stops). No mixed conventions or vague verbs, making the set highly predictable.
Six tools is well-scoped for a transit information server, covering route discovery, stop lookup, departures, and alerts without unnecessary bloat. Each tool earns its place in the workflow.
The core transit query surface is covered: routes, directions, stops, departures, and alerts. Minor gaps exist such as no route-by-ID lookup or stop details endpoint, but agents can achieve common tasks with the provided operations.
Maintenance
Related MCP Connectors
SEPTA MCP — Philadelphia SEPTA real-time transit (www3.septa.org/api, keyless)
MBTA MCP — Boston real-time transit via the MBTA v3 API (api-v3.mbta.com)
Real-time transit stops, routes, arrivals, vehicle positions, and schedules via OneBusAway APIs.
CTA MCP — Chicago Transit Authority real-time trains ('L') + buses
Related MCP Servers
- FlicenseAqualityCmaintenanceEnables querying self-hosted OpenTripPlanner for accurate transit routes via MCP, supporting both stdio and HTTP.3-
- FlicenseAqualityCmaintenanceWraps the CTA Bus Tracker API to provide live access to bus routes, stops, predictions, vehicle locations, patterns, and detours via MCP clients.11-
- AlicenseNot gradedqualityAmaintenanceEnables querying stops, routes, real-time arrivals, vehicle positions, and schedules from OneBusAway transit APIs via MCP, supporting STDIO or Streamable HTTP.45 npm1Apache 2.0
- FlicenseNot gradedqualityBmaintenanceMCP server exposing live MBTA V3 transit data, with tools for routes, stops, arrivals, alerts, and vehicle positions.-