Before every BetaNYC event, we check the trains and elevators on the way there, so nobody who uses a wheelchair gets sent to a station whose elevators are out. We want to know whether the train we're telling people to take is running that day, at that station. Checking by hand is slow and easy to get wrong, so we built an MCP server that lets an AI assistant like Claude do it.
If your question is "is the L running right now," use mta.info or any transit app. They're free and official, and they show what's happening now.
This server is for planning ahead: a future date, a specific station, and an answer you can put in the email to everyone coming. For live arrivals inside an AI assistant, try one of the other NYC subway servers further down.
Each example below is labeled. Verified 2026-09-21 means we ran that call live that day. Saved feed means we ran it against copies of MTA's feeds saved in the repo, dated on the panel. Illustrative shows a call Claude might make, not one we ran.
An alert can mention your station because service there got better.
mta.info/alerts. Filter to the 4, set the date to 09/26.Counting any mention as a disruption would flag 68 St here, because the alert that names it
adds service. This server reads MTA's alert_type to tell the two apart.
get_accessibility_outages({
"stop_id": "414",
"route_id": "4",
"date": "2026-09-26"
})
Elevator feed saved 2026-09-17. Station ADA and equipment inventory snapshots pulled 2026-09-22. Only the last of five outages is shown, and MTA's alternate route text is cut short.
{
"date": "2026-09-26",
"query": "161 St-Yankee Stadium",
"stop_id": "414",
"route_id": "4",
"station_accessibility": { "status": "fully_accessible", "mta_notes": null },
"outage_count": 5,
"date_caveats": [],
"outages": [
…four more elevators…
{
"station": "161 St-Yankee Stadium",
"trainno": "B/D/4",
"equipment": "EL133",
"equipmenttype": "EL",
"serving": "mezzanine to Manhattan-bound 4 platform",
"ADA": "Y",
"outagedate": "11/06/2024 09:00:00 AM",
"estimatedreturntoservice": "09/30/2026 11:59:00 PM",
"reason": "Capital Replacement",
"matched_by": "name",
"match_note": "MTA's equipment inventory places EL133 at 161 St-Yankee Stadium (D11), another station in this complex. The outage feed's station name fits this station too, so it is listed here.",
"inventory": {
"stop_ids": ["D11"],
"ada_compliant": "YES",
"redundant_elevator": "-",
"alternative_route": "To access street level: Take a Manhattan-bound
4 to 125 St. Use elevators to transfer to a Bronx-bound 6. Exit at
Hunts Point Av and transfer to a Washington Heights-bound Bx6-SBS
bus to E 161 St and River Av. …"
}
}
]
}
Once it's installed, you ask Claude a question in plain English, and Claude picks a tool and fills in the arguments. It works best when the question names a train, a station, and a date.
Illustrative Claude chooses the tool, so its call may differ a little from the one shown.
| You ask | The tool Claude would likely call |
|---|---|
| "Check the 6 train and the elevators at 68 St–Hunter College for October 3. It's for our event." | check_route_on_date{"route_id": "6", "date": "2026-10-03", "station": "68 St-Hunter College",
"include_accessibility": true} |
| "What's happening on the 6 train this weekend?" | get_service_alerts, once per day{"route_id": "6", "date": "2026-09-26"} |
| "Our flyer says 125 St. Which station is that?" | resolve_station{"query": "125 St"}Four stations match, so it asks you which one. |
| "What elevator outages are scheduled on the 7 train?" | get_accessibility_outages{"route_id": "7", "upcoming": true} |
check_route_on_date({
"route_id": "6",
"date": "2026-09-19",
"stop_id": "628",
"include_accessibility": true
})
Alerts feed timestamped 2026-09-16, elevator feed saved 2026-09-17, station ADA snapshot pulled 2026-09-22. Some fields are cut.
{
"route_id": "6",
"date": "2026-09-19",
"disrupted": false,
"station": {
"stop_id": "628",
"stop_name": "68 St-Hunter College",
"routes": ["4", "6", "6X"],
"accessibility": { "status": "fully_accessible", "mta_notes": null }
},
"station_level_detail": true,
"alert_count": 1,
"alerts": [{
"alert_type": "Planned - Part Suspended",
"effect": "reduced",
"header_text": "No [6] between Hunts Point Av and 125 St",
"human_readable_active_period": "Sep 18 - Oct 19, Fri 9:30 PM to Mon 5:00 AM",
"affected_stops": [
{ "stop_id": "614", "stop_name": "Longwood Av" },
…five more Bronx stations…
],
"affects_this_station": false,
"relevant_to_station": false
}],
"accessibility_outages": {
"outage_count": 0,
"outages": [],
"note": "… No outage is listed here. A missing outage is not proof
the station is usable: the feed can lag, and an outage MTA hasn't
entered won't show. Confirm at
https://www.mta.info/elevator-escalator-status before travel."
},
"disclaimer": "Unofficial. BetaNYC is not the MTA …"
}
disrupted is false for this
station. Guests coming from the Bronx on the 6 would still hit the gap, and MTA's alert
text says free shuttle buses cover it. MTA lists the station as fully accessible and listed
no elevator outage there that day. The outage feed can lag, so that isn't proof the
elevators work. A flyer should still tell people to check mta.info before traveling.Every parameter and every field in every answer is in the tool reference. The elevator, escalator, and ADA data, and where it falls short, are in docs/accessibility.md.
You need Node 18 or newer, and no API key.
git clone https://github.com/BetaNYC/mta-mcp.git cd mta-mcp npm install # also builds
For Claude Code, in a project's .mcp.json:
{
"mcpServers": {
"mta-mcp": {
"command": "node",
"args": ["${HOME}/Code/mta-mcp/dist/index.js"]
}
}
}
For Claude Desktop, in claude_desktop_config.json. Claude Desktop doesn't expand
${HOME}, so use the full path to your copy:
{
"mcpServers": {
"mta-mcp": {
"command": "node",
"args": ["/absolute/path/to/mta-mcp/dist/index.js"]
}
}
}
Restart the app and ask something from Try asking, like "Check the 6 train and the elevators at 68 St–Hunter College for October 3."
Using Claude Code and want to use fewer tokens per conversation? The same tools also come as a skill, with no MCP server to run. See skills/README.md.
| Not this | Why |
|---|---|
| "When is the next 6 train?" | No arrivals or trip updates, for the subway or buses. The subway arrival feeds are protobuf-only, and Bus Time needs an API key. The servers below do live subway arrivals. |
| "Are Times Sq and Port Authority connected?" | Stations linked only by transfer, under different names, are not modeled. 60 such pairs exist. Asking about one name will not surface alerts filed against the other. |
| "Can I get step-free to the platform today?" | Only in part. You get the station's ADA status and any elevator outages MTA has listed, with its alternate route. The ADA status is a dated snapshot and the outage feed can lag, so an empty answer doesn't mean the station is usable. Check MTA's elevator and escalator status page. |
| "Is my station definitely fine?" | MTA tags stations only when it considers the change significant. Every response carries
station_level_detail, which is true only when every matching alert named
its stations. When it's false, a clean answer for your station isn't a
guarantee. |
alert_type values we saw in a live
pull on 2026-09-16. MTA can send others. An unrecognized value counts as a disruption until
someone adds it to the map.Want bus or LIRR alerts, or found something wrong? Open an issue.
For most subway questions, one of these is a better fit. Several are further along than ours, and all of them do live arrivals.
| Project | Language | What it does that this one does not |
|---|---|---|
| where_is_my_train_mcp
sasabasara · also on Smithery |
TypeScript | The broadest of these. Live arrivals with crowding where available, fuzzy station search, elevator status, transfers, and nearby-station lookup by latitude and longitude. |
| nyc-subway-mcp-server
hardparking |
TypeScript | Real-time arrivals, live vehicle positions, and a line-status overview. Runs over HTTP as well as stdio. |
| metro-mcp
Aarekaz |
TypeScript | Covers DC Metro as well as NYC. Anonymous, read-only, deployed on Cloudflare Workers, so there is nothing to install. |
| mta-mcp
nkasmanoff · same name as ours, no relation |
Python | Next-train arrivals by station and direction. Small and readable, which makes it a good first thing to look at if you are learning how these fit together. |
Use this one when your question has a date in it. It checks a future day at one station, and it tells service that got worse there from service that got better.
Our other seven MCP servers install from npm. This one runs from a local build because of
MTA's data feed terms, which say
users of an app have to get MTA's data from a non-MTA server. A published package would have
every user's machine fetch straight from api-endpoint.mta.info, with no server of ours
in between. MTA's wording and our reasoning are in
docs/terms-compliance.md.
| Your question | Where it goes |
|---|---|
| A tool returns the wrong shape, a schema is wrong, this server crashes | Our issue tracker For an alert-matching question, include the entity_id
from the response so we can find the alert in the raw feed. |
| A feed field is undocumented, an alert looks wrong, MTA's API behaves oddly | MTA Developer
Google Group MTA points developers to this public group. You'll get a better answer there than in our tracker, and it helps everyone else building on the same feeds. |
BetaNYC builds and maintains this project. We're New York's civic technology and open data community, and we work to improve lives in New York through civic design, technology, and data. Our members, BetaBuilders, talk through tools like this one on the BetaNYC Discord while they're still rough.
Attending a class or registering for a flagship event earns 90 days of access at no cost. Giving $5 a month gets you in too, and funds School of Data, Mapping for Equity, Open Data Week, CityCamp NYC, and the weekly newsletter. If cost is the obstacle, say so. Learn more about BetaBuilders.
The newsletter, public events, classes, and this server don't require a membership. More about us: who we are, our work, the events calendar, NYC School of Data, CityCamp NYC, and github.com/BetaNYC, where our seven npm-published MCP servers live. If these tools are useful to you, please donate.
Data from the MTA service alerts feed, free to use under MTA's terms. Station names from MTA's published static GTFS. MTA's own implementation notes are at nymta/gtfs-documentation.
We wrote most of this server and this page with Claude. Panels labeled Verified or Saved feed show real calls. The panel labeled Illustrative does not.