Skip to main content
Glama

transit-mcp-server

511.org SF Bay Open Data 대중교통 API용 MCP 서버입니다. LLM에 실시간 베이 에어리어 대중교통 데이터(운영 기관, 노선, 정류장, 실시간 출발, 차량 위치, 서비스 알림)를 제공하며, BART, Muni, AC Transit, Caltrain, VTA 및 511에 보고하는 모든 운영 기관을 포함합니다.

6개의 도구, 모두 읽기 전용입니다.

요구 사항

Related MCP server: mcp-bart

설치

npm install
npm run build

구성

{
  "mcpServers": {
    "transit": {
      "command": "node",
      "args": ["/absolute/path/to/transit-mcp-server/dist/index.js"],
      "env": { "TRANSIT_511_API_KEY": "your-token-here" }
    }
  }
}

변수

필수

기본값

용도

TRANSIT_511_API_KEY

예

—

https://511.org/open-data/token에서 받은 토큰

TRANSIT_511_BASE_URL

아니요

https://api.511.org

API 호스트 재정의

TRANSIT_511_REQUEST_TIMEOUT_MS

아니요

30000

요청당 타임아웃

TRANSPORT

아니요

stdio

stdio 또는 http

PORT / HOST

아니요

3000 / 127.0.0.1

HTTP 전송 바인드 주소

MCP_PATH_SECRET

호스팅 시

—

엔드포인트를 /mcp/<secret>으로 제공합니다. HOST가 루프백이 아닐 때 필수입니다.

ALLOWED_ORIGINS

아니요

localhost + claude.ai

쉼표로 구분된 출처 허용 목록

할당량이 주요 제약입니다

511은 키당 시간당 60회 요청을 모든 엔드포인트에 걸쳐 공유합니다. 이는 도구 사용 방식을 결정할 만큼 낮습니다.

  • 운영 기관 코드와 정류장 코드는 한 번 확인한 후 재사용하세요. 변경되지 않습니다.

  • operator_id 없이 transit_list_service_alerts를 사용하는 것이 좋습니다. 한 번 호출로 모든 기관을 커버합니다.

  • transit_next_departures를 루프로 폴링하지 마세요. 출퇴근 시간에 10번 확인하면 시간당 예산의 6분의 1을 소모합니다.

transit_list_operators는 511이 모든 응답에 포함하는 RateLimit-Remaining 헤더에서 남은 예산을 읽어 보고합니다. 할당량을 초과하면 429가 반환됩니다. 증가를 요청하려면 transitdata@511.org에 문의하세요.

배포 (Claude 모바일 / claude.ai 커넥터용)

다른 호스팅 MCP 서버와 동일한 형태입니다. openssl rand -hex 32로 경로 시크릿을 생성하고, 플랫폼 대시보드에서 TRANSIT_511_API_KEY와 MCP_PATH_SECRET을 설정하면, 포함된 Dockerfile과 railway.json이 Railway, Render 또는 Fly에서 그대로 작동합니다. 서버는 시크릿 없이 공용 인터페이스에서 시작을 거부합니다. /healthz는 인증 없는 활성 프로브입니다.

그런 다음 claude.ai 브라우저에서: Customize → Connectors → Add custom connector, URL https://your-app.up.railway.app/mcp/<secret>.

도구

네트워크 — transit_list_operators, transit_list_lines, transit_find_stops

실시간 — transit_next_departures, transit_list_vehicles

알림 — transit_list_service_alerts

모든 도구는 response_format: "markdown" | "json"을 받습니다. Markdown이 기본이며 LLM이 읽기에 최적화되어 있습니다. JSON은 전체 구조화된 페이로드입니다. structuredContent는 형식과 관계없이 항상 채워집니다.

예시

"다음 N Judah는 언제인가요?" → operator_id="SF", query="judah"로 transit_find_stops를 호출하여 정류장 코드를 얻은 다음, 해당 코드와 line="N"으로 transit_next_departures를 호출합니다.

"BART가 정상적으로 운행 중인가요?" → operator_id="BA"로 transit_list_service_alerts를 호출합니다.

"출퇴근 길에 문제가 있나요?" → 운영자 없이 transit_list_service_alerts를 호출합니다. 한 번 호출로 모든 베이 에어리어 기관을 훑습니다.

"지금 열차는 어디에 있나요?" → operator_id="BA"로 transit_list_vehicles를 호출합니다.

설계 노트

구조적으로 읽기 전용입니다. 511은 쓰기 엔드포인트를 제공하지 않으며, 모든 도구는 readOnlyHint: true를 포함합니다. 테스트가 이를 확인합니다.

엔드포인트별로 매핑되는 하나의 operator_id. 511은 정적 엔드포인트에서는 이 매개변수를 operator_id라고 부르고, 실시간 엔드포인트에서는 동일한 값에 대해 agency라고 부릅니다. 여기의 모든 도구는 operator_id를 받고 클라이언트가 매핑합니다. 이 분리는 호출자의 문제가 아니라 511의 문제입니다.

두 실시간 엔드포인트는 실제로 다른 봉투를 가집니다. StopMonitoring에는 Siri 루트 래퍼가 없습니다. VehicleMonitoring에는 있습니다. 공개된 사양은 둘 다에 하나를 보여주지만, 사양이 잘못되었으며 문서화된 형태로 파싱하면 출발 정보에 대해 아무것도 반환되지 않습니다. 둘 다 실제 API가 내보내는 대로 파싱되며, 각각을 고정하는 테스트가 있습니다.

도착 정보는 카운트다운을 포함하지만 출발 정보는 아닙니다. ExpectedDepartureTime은 사실상 모든 실제 행에서 null이므로, 이를 기준으로 카운트다운을 만들면 서비스가 없는 정류장으로 표시됩니다. ExpectedArrivalTime이 신뢰할 수 있는 필드입니다.

UTF-8 BOM은 파싱 전에 제거됩니다. 511은 JSON 본문 앞에 U+FEFF를 붙이므로, 완벽하게 유효한 페이로드에서 순진한 JSON.parse가 예외를 던집니다. 인증 실패는 BOM 없는 일반 텍스트이므로, 상태 확인 후에 제거가 이루어집니다.

숫자와 불리언처럼 보이는 값은 종종 그렇지 않습니다. 좌표와 방위는 JSON 문자열로 도착하고, VehicleAtStop은 문자열 "false"이며, null이 의미되는 곳에 ""가 사용됩니다. 무작정 강제 변환하면 누락된 위치가 아프리카 연안의 유효해 보이는 0,0이 되므로, 빈 문자열은 0이 아닌 부재로 처리됩니다.

에포크 제로 센티널은 타임스탬프가 아닙니다. 예정되었지만 차량이 배정되지 않은 운행은 RecordedAtTime이 1970-01-01T00:00:00Z로 보고됩니다. "56년 전에 기록됨"이 아니라 "아직 차량이 배정되지 않음"으로 렌더링됩니다.

GTFS-Realtime 열거형이 디코딩됩니다. 511의 JSON 알림 렌더링은 XML 렌더링이 SignificantDelays라고 말하는 곳에서 "effect": 3을 내보냅니다. 원인과 효과 모두 단어로 다시 매핑됩니다.

511 내부 의사 기관은 필터링됩니다. 5E, 5F, 5O, 5S는 511 Emergency, Flap Sign, Operations, Staff입니다. 이들은 서비스 데이터 없이 운영자 목록에 나타납니다.

모든 것은 태평양 시간입니다. 타임스탬프는 UTC로 도착하고 America/Los_Angeles로 렌더링되므로, 일광 절약 시간은 모델이 매년 두 번 처리하는 대신 여기서 한 번 처리됩니다. 511 자체의 TimeZone 필드가 모든 베이 에어리어 기관에 대해 America/Vancouver를 보고한다는 점에 유의하세요. 이는 알려진 업스트림 데이터 버그이며 의도적으로 무시됩니다.

절단은 항상 명시됩니다. 511은 페이지네이션을 하지 않습니다. 전체 컬렉션을 반환하며, 큰 기관은 수천 개의 정류장을 가집니다. 도구는 클라이언트 측 limit를 받고, 잘린 모든 결과는 얼마나 보류되었는지 말합니다. 조용히 줄어든 목록은 "그게 전부입니다"로 읽히기 때문입니다.

주의 사항

  • 시간당 할당량은 모든 엔드포인트에 걸쳐 60회 요청입니다. 이는 모든 워크플로우의 제약 조건입니다.

  • 운영자 코드는 잘못 추측하기 쉽습니다. VTA는 SC( VT 아님), Capitol Corridor는 AM( CC 아님), Tri Delta는 3D입니다. transit_list_operators는 출력에서 이러한 함정을 인쇄합니다.

  • 정류장 코드는 한 운영자에 속하며 기관 간에 교환할 수 없습니다.

  • transit_find_stops는 이 서버에서 필터링하므로, 좁은 쿼리는 할당량을 절약하지 않습니다. 전체 정류장 목록은 어느 쪽이든 가져옵니다.

  • 실시간 예측은 약 90분 앞까지 확장되며, 511은 노선의 최종 도착 전용 정류장을 출발 피드에서 생략합니다.

  • tripupdates와 vehiclepositions는 JSON 옵션 없이 protobuf 전용이므로 의도적으로 노출하지 않습니다. 이를 지원하려면 SIRI 엔드포인트가 이미 커버하는 데이터에 protobuf 의존성을 추가해야 합니다.

프로젝트 구조

src/
├── index.ts               # entry point, transport selection
├── constants.ts           # enums, limits, operator-code traps
├── types.ts               # interfaces for every 511 entity
├── services/
│   └── transit-client.ts  # fetch wrapper, auth, BOM stripping, quota tracking, errors
├── schemas/
│   ├── inputs.ts          # Zod input schemas
│   └── outputs.ts         # structuredContent schemas
├── formatters/
│   ├── response.ts        # limiting, truncation, Pacific-time rendering
│   └── entities.ts        # per-entity markdown rendering
└── tools/
    ├── network.ts         # operators, lines, stops
    ├── departures.ts      # real-time arrivals and vehicles
    └── alerts.ts          # service alerts

테스트

npm run build
npm test            # 42 checks: handshake, BOM, envelopes, quirks, errors (mocked API)
npm run test:http   # 17 checks: config validation, path-secret gating, method handling, origins

두 스위트 모두 511의 실제 특이점( BOM, 누락된 Siri 래퍼, 문자열화된 불리언과 좌표, 에포크 센티널, 일반 텍스트 오류 본문)을 의도적으로 재현하는 로컬 목(mock)에 대해 실행됩니다. 순진한 클라이언트가 정확히 그런 것들에서 실수하기 때문입니다.

Available Tools

6 tools
transit_find_stopsFind Transit StopsA
Read-onlyIdempotent

Find an agency's stops by name, and get the stop codes the real-time tools need.

This is the bridge between "Downtown Berkeley" and the code transit_next_departures wants. Pass a query: a large agency has thousands of stops, and 511 returns all of them in one unpaginated response.

Args:

  • operator_id (string): agency code from transit_list_operators

  • query (string): substring match on the stop name — strongly recommended

  • limit (number): maximum stops to return (default: 25)

  • response_format ('markdown' | 'json'): output format (default: 'markdown')

Returns: { "count": number, "total": number, "truncated": boolean, "stops": [ { "id": string, "Name": string, "Location": { "Latitude": string, "Longitude": string } } ] }

Examples:

  • "When's the next train from Downtown Berkeley?" -> operator_id='BA', query='downtown berkeley', then pass the id to transit_next_departures

  • "Find Muni stops on Judah" -> operator_id='SF', query='judah'

  • Don't use when: you already have the stop code

Error Handling:

  • Stop codes belong to ONE operator and are not interchangeable between agencies

  • Filtering happens on this server, so a narrow query does not save quota — the full list is fetched either way

  • 511 allows 60 requests per hour across ALL endpoints

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoMaximum results to return (max 200)
queryNoCase-insensitive substring match on the stop name. Strongly recommended — a large agency has thousands of stops
operator_idYesOperator code from transit_list_operators, e.g. 'BA' for BART, 'SF' for Muni
response_formatNoOutput format: 'markdown' for human-readable, 'json' for machine-readablemarkdown

Output Schema

ParametersJSON Schema
NameRequiredDescription
countYes
stopsYes
totalYes
truncatedYes

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, openWorldHint, idempotentHint, and destructiveHint=false. The description adds meaningful behavior: server-side filtering (no quota savings), unpaginated response from 511, and the 60-request/hour rate limit. It also clarifies that stop codes are operator-specific—valuable context beyond the annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is longer but well-structured with clear sections (Args, Returns, Examples, Error Handling). Each section contributes distinct value: the main purpose is front-loaded, examples are concise, and error handling is pertinent. No fluff or redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description is fully self-contained: it includes the return object structure, examples mapping to actual operator IDs, error-handling notes, rate limits, and the relationship to sibling tools. With an output schema present and annotations covering safety, nothing an agent needs to invoke correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the baseline is 3. The description's Args section largely repeats schema descriptions (e.g., 'operator_id' from transit_list_operators, 'query' substring match and 'strongly recommended'). It adds no new per-parameter semantics; the 'strongly recommended' phrasing already appears in the schema. The unpaginated response note is behavioral, not parameter-specific.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly identifies the tool's purpose: 'Find an agency's stops by name, and get the stop codes the real-time tools need.' It explicitly ties the tool to transit_next_departures, distinguishing it from other transitive tools. The purpose is specific and actionable.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides explicit usage context: 'This is the bridge between "Downtown Berkeley" and the code transit_next_departures wants.' It also states a clear when-not: 'Don't use when: you already have the stop code.' Examples illustrate typical queries, making the intended conditions unambiguous.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

transit_list_linesList Transit LinesA
Read-onlyIdempotent

List an agency's routes.

Use this to resolve a line name a user mentions into the id the real-time tools filter on, or to answer "what routes does this agency run".

Args:

  • operator_id (string): agency code from transit_list_operators

  • query (string): substring match on the line name or public code

  • limit (number): maximum lines to return (default: 25)

  • response_format ('markdown' | 'json'): output format (default: 'markdown')

Returns: { "count": number, "total": number, "truncated": boolean, "lines": [ { "Id": string, "Name": string, "PublicCode": string, "TransportMode": string, "Monitored": boolean } ] }

Examples:

  • "What BART lines are there?" -> operator_id='BA'

  • "Is there an N line on Muni?" -> operator_id='SF', query='N'

  • Don't use when: you want stops on a line (use transit_find_stops)

Error Handling:

  • A large agency returns many lines; use query to narrow rather than raising limit

  • 511 allows 60 requests per hour across ALL endpoints

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoMaximum results to return (max 200)
queryNoCase-insensitive substring match on the line name or public code
operator_idYesOperator code from transit_list_operators, e.g. 'BA' for BART, 'SF' for Muni
response_formatNoOutput format: 'markdown' for human-readable, 'json' for machine-readablemarkdown

Output Schema

ParametersJSON Schema
NameRequiredDescription
countYes
linesYes
totalYes
truncatedYes

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The annotations already declare readOnly, idempotent, and non-destructive hints. The description goes further by disclosing the response shape, the truncation flag, the possibility of many results for large agencies, and the 60-request-per-hour rate limit across all endpoints. This adds behavioral context beyond the annotations and contradicts nothing.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-organized with clear sections (Summary, Args, Returns, Examples, Error Handling). It front-loads the purpose and usage, and every sentence adds value—examples, exclusions, rate limits, and return format. Despite covering many aspects, it remains concise and skimmable.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The tool has 4 parameters, an output schema, and sits among 5 siblings. The description covers all essentials: purpose, parameter examples, return structure, error handling, and even the rate limit. There is nothing an agent needs to know to call this correctly that is missing, and the output schema already documents the return shape.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema covers all parameters with detailed descriptions (100% coverage), so the description does not need to duplicate that. It adds a few examples (operator_id='BA', 'SF') and clarifies that query is a case-insensitive substring, but these are minor enhancements. The baseline of 3 is appropriate because the schema already carries the main semantic load.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb ('List') and resource ('an agency's routes'), and immediately explains its practical use (resolving a line name into an id, answering route questions). It explicitly distinguishes itself from a sibling tool ('Don't use when: you want stops on a line (use transit_find_stops)'), which is a clear differentiation.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives explicit 'Use this to...' guidance and an explicit 'Don't use when...' with a named alternative. Examples illustrate common queries, and the error handling section advises when to prefer query narrowing over raising limit. This leaves no ambiguity about when to invoke this tool.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

transit_list_operatorsList Transit OperatorsA
Read-onlyIdempotent

List Bay Area transit agencies and their operator codes.

Start here. Every other tool needs an operator code, and this is what produces them — BART is 'BA', Muni is 'SF', AC Transit is 'AC', Caltrain is 'CT'.

The Monitored flag matters: agencies reporting real-time data support live departures and vehicle positions, while schedule-only agencies do not.

Args:

  • monitored_only (boolean): only agencies publishing real-time data (default: false)

  • limit (number): maximum operators to return (default: 50)

  • response_format ('markdown' | 'json'): output format (default: 'markdown')

Returns: { "count": number, "total": number, "truncated": boolean, "operators": [ { "Id": string, "Name": string, "Monitored": boolean, "PrimaryMode": string, "TimeZone": string } ] }

Examples:

  • "What transit agencies are there?" -> call with no arguments

  • "Which ones have live tracking?" -> monitored_only=true

  • Call this first whenever the user names an agency, to resolve its code

Error Handling:

  • Ignore the TimeZone field: 511 reports "America/Vancouver" for every Bay Area agency, which is a known upstream data bug. Everything here is Pacific time

  • 511-internal pseudo-agencies (5E, 5F, 5O, 5S) are filtered out — they carry no service data

  • 511 allows 60 requests per hour across ALL endpoints, so cache this rather than re-fetching

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoMaximum results to return (max 200)
monitored_onlyNoOnly agencies that publish real-time data, excluding schedule-only ones
response_formatNoOutput format: 'markdown' for human-readable, 'json' for machine-readablemarkdown

Output Schema

ParametersJSON Schema
NameRequiredDescription
countYes
totalYes
operatorsYes
truncatedYes

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true, openWorldHint=true, idempotentHint=true, and destructiveHint=false. The description adds substantial behavioral context beyond those: the Monitored flag semantics, the known TimeZone bug (inaccurate 'America/Vancouver' values), the filtering of pseudo-agencies (5E, 5F, 5O, 5S), and the rate limit (60 req/hour across all endpoints) with caching advice. This is exactly the kind of operational detail an agent needs and the annotations do not provide.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is thorough but efficiently organized into clear sections (Args, Returns, Examples, Error Handling). Every sentence adds value: the opening line is the purpose, the 'Start here' directive is front-loaded, examples are concise, and error handling covers real-world quirks. No redundancy or filler—each element earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a tool with 3 optional parameters and an output schema, the description covers everything needed to call it correctly: it provides default values, return shape (matching the output schema), examples, and critical edge cases (TimeZone bug, filtering, rate limit). Even though the output schema exists, the description's inclusion of the return shape is redundant but not harmful; the error-handling notes are essential and not available anywhere else. The description is fully sufficient for an agent to use this tool without surprises.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so baseline is 3. The description goes beyond the schema by explaining the semantic impact of monitored_only (supports live departures/vehicle positions vs schedule-only), giving concrete usage examples for each parameter, and clarifying the response_format default. It also mentions the default for limit in prose. While the schema already has descriptions, the description adds contextual meaning that helps an agent decide parameter values appropriately.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a clear verb-resource pair: "List Bay Area transit agencies and their operator codes." It immediately differentiates from siblings by noting "Every other tool needs an operator code, and this is what produces them," which is unique among the sibling tools. The specific examples (BART='BA', Muni='SF') further cement the purpose.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly instructs when to use: "Start here." and "Call this first whenever the user names an agency, to resolve its code." It also explains the monitored_only flag's relevance for choosing between live vs schedule-only agencies, effectively guiding the agent on when to apply different parameter values. No alternatives are named, but the tool is clearly positioned as the entry point, so exclusion guidance is unnecessary.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

transit_list_service_alertsList Transit Service AlertsA
Read-onlyIdempotent

Service alerts — delays, outages, detours and planned disruptions.

Answers "is BART running normally", "why is my line delayed" and "anything I should know before I leave". Omit operator_id to sweep every Bay Area agency in a single request, which is also the kinder option against the hourly quota.

Args:

  • operator_id (string): limit to one agency; omit for all operators

  • query (string): substring match on the headline or description

  • active_only (boolean): only alerts whose active period covers now (default: true)

  • limit (number): maximum alerts to return (default: 25)

  • response_format ('markdown' | 'json'): output format (default: 'markdown')

Returns: { "count": number, "total": number, "truncated": boolean, "alerts": [ { "id": string, "header": string, "description": string, "effect": string, "cause": string, "routes": [string], "start": number, "end": number } ] // epoch SECONDS }

Examples:

  • "Any BART delays?" -> operator_id='BA'

  • "Anything wrong on my commute?" -> omit operator_id, read across agencies

  • "Weekend track work?" -> active_only=false, query='weekend'

  • Don't use when: you want a specific stop's arrivals (use transit_next_departures)

Error Handling:

  • No alerts is genuinely good news, not an error — it means normal service

  • Timestamps here are epoch seconds, unlike the ISO strings elsewhere in this API

  • Setting active_only=false surfaces future planned work as well as current problems

  • 511 allows 60 requests per hour across ALL endpoints

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoMaximum results to return (max 200)
queryNoCase-insensitive substring match on the alert headline or description
active_onlyNoOnly alerts whose active period covers now
operator_idNoLimit to one agency; omit for alerts across every Bay Area operator
response_formatNoOutput format: 'markdown' for human-readable, 'json' for machine-readablemarkdown

Output Schema

ParametersJSON Schema
NameRequiredDescription
countYes
totalYes
alertsYes
truncatedYes

TDQS

A5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only indicate read-only, idempotent, and non-destructive behavior. The description adds crucial behavioral nuance: no alerts means normal service (not an error), timestamps are epoch seconds unlike the ISO strings in other API endpoints, active_only=false surfaces future planned work, and rate limits. This goes well beyond the annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Structured with Args, Returns, Examples, and Error Handling sections. The purpose and primary use cases are front-loaded in the first sentence, and every sentence adds value—examples, rate limits, or format distinctions. No redundancy or fluff.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The output schema is present and the description includes a return format example with field types. It covers error handling (no alerts ≠ error), rate limits, timestamp format, and sibling routing. For a 5-parameter tool with no required parameters, this is fully complete for an agent.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

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 substantial meaning: operator_id omission sweeps all agencies and is 'kinder' against quota, active_only=false is tied to 'weekend track work' examples, and query is illustrated with a practical use case. These contextual insights help an agent choose parameter values effectively.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb ('List') and resource ('Transit Service Alerts'), and grounds it with concrete questions it answers ('is BART running normally', 'why is my line delayed'). It explicitly differentiates from the sibling transit_next_departures by naming when not to use it, making the purpose unmistakable.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly states when to use the tool (answering delay/outage questions) and when not to ('Don't use when: you want a specific stop's arrivals (use transit_next_departures)'). Also gives operational guidance, such as omitting operator_id to sweep all agencies and conserve quota—practical context an agent needs.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

transit_list_vehiclesList Transit Vehicle PositionsA
Read-onlyIdempotent

Live positions of an agency's vehicles currently in service.

Answers "where are the trains right now" and "how many buses are running on this line". For "when does one get to me", use transit_next_departures instead.

Args:

  • operator_id (string): agency code from transit_list_operators

  • line (string): only vehicles on this line, matched on name or id

  • limit (number): maximum vehicles to return (default: 25)

  • response_format ('markdown' | 'json'): output format (default: 'markdown')

Returns: { "count": number, "total": number, "truncated": boolean, "vehicles": [ { "line": string, "vehicle": string, "destination": string, "latitude": number | null, "longitude": number | null, "bearing": number | null, "recorded_at": string } ] }

Examples:

  • "How many Muni trains are running on the N?" -> operator_id='SF', line='N'

  • "Where are the BART trains?" -> operator_id='BA'

  • Don't use when: you want arrival times at a stop (use transit_next_departures)

Error Handling:

  • Coordinates arrive as strings and may be empty; those vehicles report "position unavailable" rather than a false 0,0

  • An agency with no real-time feed returns nothing — check Monitored in transit_list_operators

  • 511 allows 60 requests per hour across ALL endpoints

ParametersJSON Schema
NameRequiredDescriptionDefault
lineNoOnly vehicles on this line
limitNoMaximum results to return (max 200)
operator_idYesOperator code from transit_list_operators, e.g. 'BA' for BART, 'SF' for Muni
response_formatNoOutput format: 'markdown' for human-readable, 'json' for machine-readablemarkdown

Output Schema

ParametersJSON Schema
NameRequiredDescription
countYes
totalYes
vehiclesYes
truncatedYes

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already signal read-only, idempotent, and open-world behavior. The description adds valuable, non-obvious behavioral details: coordinates arrive as strings and may be empty, agencies with no real-time feed return nothing (with a pointer to check 'Monitored'), and a 60-requests-per-hour rate limit. This goes well beyond the annotations and prepares the agent for realistic edge cases.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is longer than strictly necessary because it repeats the Args and Returns sections that already exist in the schema. However, it is well-structured with clear sections (purpose, args, returns, examples, error handling) and the most important guidance (purpose and alternative) is front-loaded. Every section adds unique value (examples, error handling, rate limits), so the length is justified despite some redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a list tool with an output schema and read-only annotations, the description covers all essential context: proper use cases, alternatives, parameter semantics, edge cases (missing coordinates, empty feeds, rate limits), and concrete examples. Nothing an agent needs to call it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the schema fully documents each parameter. The description adds some meaning beyond that: it clarifies that 'line' matches on name or id, and provides concrete examples (operator_id='SF', line='N') that illustrate how parameters map to real queries. Defaults for limit and response_format are repeated, but the examples and matching detail provide modest added value.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a clear, specific statement of what the tool does: 'Live positions of an agency's vehicles currently in service.' It names the resource (vehicles) and action (list positions), and explicitly differentiates from a sibling tool ('For "when does one get to me", use transit_next_departures instead'), so an agent can distinguish it without opening schemas.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides explicit when-to-use guidance: answers 'where are the trains right now' and 'how many buses are running on this line', and gives a direct exclusion: 'Don't use when: you want arrival times at a stop' with the alternative named. Examples reinforce correct usage and operator/line selection.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

transit_next_departuresNext Transit DeparturesA
Read-onlyIdempotent

Live arrival predictions for the next vehicles at a stop.

This is the tool for "when is my next train/bus". It returns real-time predictions, not the printed timetable, and reports minutes-from-now alongside Pacific clock time.

Args:

  • operator_id (string): agency code from transit_list_operators, e.g. 'BA', 'SF'

  • stop_code (string): stop code from transit_find_stops. Codes belong to ONE operator and are not interchangeable between agencies

  • line (string): only departures on this line, matched on name or id

  • limit (number): maximum departures to return (default: 10)

  • response_format ('markdown' | 'json'): output format (default: 'markdown')

Returns: { "count": number, "total": number, "truncated": boolean, "operator": string, "stop_code": string, "stop_name": string, "retrieved_at": string, "departures": [ { "line": string, "destination": string, "expected": string, "aimed": string, "minutes": number, "vehicle": string | null, "at_stop": boolean } ] }

Examples:

  • "When's the next N Judah?" -> operator_id='SF', stop_code from transit_find_stops, line='N'

  • "Next BART from Downtown Berkeley?" -> operator_id='BA', the stop's code

  • Don't use when: you want the scheduled timetable rather than live predictions

Error Handling:

  • An empty result usually means service has ended for the night, or the stop is a route's final stop — 511 omits arrival-only terminals from this feed

  • Predictions extend roughly 90 minutes ahead; nothing beyond that appears

  • Rows reading "scheduled only, no live prediction" have no vehicle assigned yet

  • 511 allows 60 requests per hour across ALL endpoints — never poll this in a loop

ParametersJSON Schema
NameRequiredDescriptionDefault
lineNoOnly departures on this line, matched against the line name or id
limitNoMaximum results to return (max 200)
stop_codeYesStop code from transit_find_stops. Codes are specific to one operator
operator_idYesOperator code from transit_list_operators, e.g. 'BA' for BART, 'SF' for Muni
response_formatNoOutput format: 'markdown' for human-readable, 'json' for machine-readablemarkdown

Output Schema

ParametersJSON Schema
NameRequiredDescription
countYes
totalYes
operatorNo
stop_codeNo
stop_nameNo
truncatedYes
departuresYes
retrieved_atNo

TDQS

A5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly, idempotent, and non-destructive hints. The description adds substantial behavioral context: real-time vs static, minutes-from-now plus Pacific clock time, 'scheduled only' rows, a 90-minute prediction horizon, empty results meaning (end of service or arrival-only terminal), and a 60-requests-per-hour rate limit. This goes far beyond the annotations, providing critical operational details an agent needs to interpret results and avoid misuse.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Structured with clear sections (Purpose, Args, Returns, Examples, Error Handling) and front-loaded with the core purpose. Every sentence adds value; error handling is critical for correct agent behavior. It is detailed but not flabby — the length is justified by the operational caveats and edge cases.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a tool with 5 parameters and an output schema, the description covers all essential usage aspects: parameter semantics, error scenarios (empty results, truncated predictions), time horizon, rate limits, and a full output structure in the Returns section. Even though an output schema is provided, the description's explicit sample JSON and explanation of fields further aid the agent. Nothing needed for correct invocation is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Even though schema coverage is 100%, the description enriches every parameter: it provides real examples (operator_id 'BA'/'SF', stop_code from transit_find_stops), warns that stop codes are operator-specific and not interchangeable, clarifies line matching ('matched on name or id'), and explains response_format options. The Args section adds value beyond the schema's terse descriptions, especially for stop_code and line.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Description states a specific verb and resource: 'Live arrival predictions for the next vehicles at a stop' and explicitly positions it as 'the tool for when is my next train/bus'. It distinguishes from the printed timetable and clarifies scope (real-time, not static), making it clearly different from sibling tools that list operators, stops, lines, vehicles, or alerts.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides explicit when-to-use guidance via examples ('When's the next N Judah?' maps to specific parameters), an explicit 'Don't use when' exclusion for scheduled timetable, and references prerequisite tools (transit_list_operators, transit_find_stops) for parameter sourcing. It also includes rate-limit guidance ('never poll this in a loop'), which is directly relevant to usage.

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.

  1. 6 tool updatesv1.0.0
    • First observedtransit_find_stops
    • First observedtransit_list_lines
    • First observedtransit_list_operators
    • First observedtransit_list_service_alerts
    • First observedtransit_list_vehicles
    • First observedtransit_next_departures

TDQS

A4.8/5.0

Scored across 6 tools

Disambiguation5/5

Each tool targets a distinct resource: operators, lines, stops, departures, vehicles, and alerts. Descriptions explicitly cross-reference when to use which (e.g., 'Don't use when' sections), eliminating ambiguity. No two tools overlap in purpose.

Naming Consistency5/5

All tools share the 'transit_' prefix and follow a consistent verb-object pattern: list_operators, list_lines, find_stops, next_departures, list_vehicles, list_service_alerts. Minor variation between 'list', 'find', and 'next' but the style is uniform and predictable.

Tool Count5/5

Six tools are well-scoped for a transit information server, covering discovery (operators, lines, stops), real-time queries (departures, vehicles), and alerts. No tool is redundant, and the count feels neither sparse nor bloated.

Completeness4/5

The tool surface covers the full workflow of querying transit info: discover agencies, lines, stops, then get live departures, vehicle positions, and alerts. A minor gap is the lack of a dedicated scheduled timetable tool, though the departures endpoint includes aimed times. Overall, the domain is well covered.

Maintenance

ActivitySlowing
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers