Skip to main content
Glama
malkreide

SBB Open Data MCP Server

by malkreide

πŸš† sbb-opendata-mcp

πŸ‡¨πŸ‡­ Part of the Swiss Public Data MCP Portfolio

PyPI License: MIT Python 3.11+ MCP Data Source CI

MCP server connecting AI models to Swiss Federal Railways (SBB) open data – passenger frequency, live rail disruptions, infrastructure & real-estate projects, train counts, platform data, rolling stock and station search from data.sbb.ch. No API key required.

πŸ‡©πŸ‡ͺ Deutsche Version

Demo

Demo: Claude queries SBB passenger frequency


Overview

sbb-opendata-mcp gives AI assistants like Claude direct access to public SBB data – no copy-pasting or manual API calls. A question like "How many passengers passed through ZΓΌrich HB every day in 2024?" is answered with real measured data.

The SBB Open Data portal speaks the OpenDataSoft REST API (v2.1). This server translates it into clean Markdown and JSON for the AI model, and adds MCP structuredContent alongside the human-readable text so programmatic clients can consume the underlying records without re-parsing. The server is model-agnostic and works with any MCP-compatible client.

Anchor demo query: "Compare ZΓΌrich HB, Bern and Basel SBB by passenger frequency and platform capacity." β†’ More use cases by audience β†’


Related MCP server: swiss-rail-mcp

Features

  • πŸ“Š Passenger frequency – boardings/alightings by station and year (daily averages)

  • 🚨 Live rail disruptions – traffic messages, updated every 5 minutes

  • πŸ—οΈ Infrastructure projects – station and line construction

  • 🏒 Real-estate projects – SBB property development (daily updates)

  • πŸš† Trains per segment – train counts per route (SBB, BLS, SOB …)

  • πŸ›€οΈ Platform data – length, type, area, step-free access

  • πŸšƒ Rolling stock – capacity and year built

  • πŸ” Station comparison – up to 10 stations across multiple datasets

  • πŸ” Stop search – Swiss DiDok register (all of Switzerland)

  • πŸ“¦ Dataset catalogue – list all ~89 SBB open datasets

  • πŸ”‘ No API key – all data is public and free to use

  • ☁️ Dual transport – stdio for Claude Desktop, Streamable HTTP for cloud deployment


Prerequisites

  • Python 3.11+

  • No API key β€” all data comes from the public data.sbb.ch portal

Install uv (recommended):

curl -LsSf https://astral.sh/uv/install.sh | sh

Installation

From PyPI:

pip install sbb-opendata-mcp

Or with uvx (no permanent installation):

uvx sbb-opendata-mcp

For local development, install from a clone in editable mode:

git clone https://github.com/malkreide/sbb-opendata-mcp.git
cd sbb-opendata-mcp
pip install -e ".[dev]"

Quickstart

# Start the server (stdio mode for Claude Desktop)
sbb-opendata-mcp

Try it immediately in Claude Desktop:

"How many people boarded at ZΓΌrich HB daily in 2024?" "Are there any current disruptions on the Swiss rail network?"


Configuration

Environment Variables

The server needs no configuration to run over stdio. The variables below tune the optional Streamable HTTP transport, logging and observability.

Variable

Effect

Default

MCP_HOST

Bind host for the HTTP transport. Keep 127.0.0.1 locally; only bind 0.0.0.0 inside a controlled container/cloud environment.

127.0.0.1

MCP_PORT

Port for the HTTP transport.

8000

MCP_ALLOWED_HOSTS

Comma-separated host allow-list for DNS-rebinding protection (e.g. your-app.onrender.com,your-app.onrender.com:*).

localhost only

MCP_ALLOWED_ORIGINS

Comma-separated browser-origin allow-list (e.g. https://your-app.onrender.com).

(none)

LOG_LEVEL

Log verbosity (DEBUG/INFO/WARNING/…).

INFO

LOG_FORMAT

json for structured logs; anything else for human-readable text. Always written to stderr.

text

πŸ”’ DNS-rebinding / Origin protection is always on; localhost is allow-listed so local HTTP development works out of the box. Logs go to stderr β€” stdout is reserved for the stdio JSON-RPC channel.

Claude Desktop Configuration

{
  "mcpServers": {
    "sbb-opendata": {
      "command": "uvx",
      "args": ["sbb-opendata-mcp"]
    }
  }
}

Config file locations:

  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json

  • Windows: %APPDATA%\Claude\claude_desktop_config.json

Restart Claude Desktop β€” the server is downloaded automatically on first use.

Other MCP Clients

Works with Cursor, Windsurf, VS Code + Continue, LibreChat, Cline and self-hosted models via mcp-proxy β€” same configuration as above.

Cloud Deployment (Streamable HTTP)

For use via claude.ai in the browser or remote servers (e.g. Render.com). The cloud transport is Streamable HTTP (endpoint /mcp).

Docker (recommended):

# Build + run with explicit resource limits (see docker-compose.yml)
docker compose up --build
# β†’ http://127.0.0.1:8000/mcp

The image is a multi-stage build running as a non-root user; docker-compose.yml adds read_only, no-new-privileges and memory/CPU/PID limits.

Manual / Render.com:

pip install -e .

# Bind publicly (behind a rate-limiting reverse proxy) and configure
# DNS-rebinding / Origin protection for your hostname:
export MCP_HOST=0.0.0.0
export MCP_ALLOWED_HOSTS="your-app.onrender.com,your-app.onrender.com:*"
export MCP_ALLOWED_ORIGINS="https://your-app.onrender.com"
python -m sbb_opendata_mcp.server --http --port 8000

⚠️ Binding: In a network transport the server binds to 127.0.0.1 by default so a locally started server is not exposed to your whole network. Set MCP_HOST=0.0.0.0 only in a container/cloud environment where binding to all interfaces is intended (the Docker image does this for you), and place the server behind a reverse proxy that enforces rate limiting (and authentication, if the endpoint should not be public). See SECURITY.md.


Available Tools

Tool

Description

Data Update

sbb_get_passenger_frequency

Boardings/alightings by station and year (daily avg.)

Annual

sbb_get_rail_disruptions

Live rail traffic messages

Every 5 min.

sbb_get_real_estate_projects

SBB real estate development projects

Daily

sbb_get_trains_per_segment

Train counts per route segment (SBB, BLS, SOB …)

Annual

sbb_get_platform_data

Platform data (length, type, area)

Ongoing

sbb_get_rolling_stock

Rolling stock (capacity, year built)

Ongoing

sbb_compare_stations

Compare up to 10 stations (multi-dataset)

–

sbb_search_stations

Search stops (Swiss DiDok register, all CH)

Ongoing

sbb_list_datasets

List all ~89 SBB open datasets

–

All tools support response_format: "markdown" (human-readable) and "json" (machine-readable), plus pagination. Every tool also returns MCP structuredContent (the underlying records/metadata) alongside the rendered text.

Example Use Cases

Query

Tool

"How many people boarded at ZΓΌrich HB daily in 2024?"

sbb_get_passenger_frequency

"Are there any current disruptions on the Swiss rail network?"

sbb_get_rail_disruptions

"Compare ZΓΌrich HB, Bern and Basel SBB"

sbb_compare_stations

"Which SBB real-estate construction projects are running?"

sbb_get_real_estate_projects

"How many trains run yearly on the ZΓΌrich–Winterthur route?"

sbb_get_trains_per_segment

"Which stops exist in WΓ€denswil?"

sbb_search_stations

β†’ More use cases by audience


Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   Claude / AI   │────▢│   SBB Open Data MCP       │────▢│       data.sbb.ch        β”‚
β”‚   (MCP Host)    │◀────│   (MCP Server)            │◀────│                          β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β”‚                           β”‚     β”‚  OpenDataSoft REST v2.1  β”‚
                        β”‚  9 Tools                  β”‚     β”‚  (public, no API key)    β”‚
                        β”‚  Stdio | Streamable HTTP  β”‚     β”‚                          β”‚
                        β”‚                           β”‚     β”‚  passagierfrequenz       β”‚
                        β”‚  Shared httpx client      β”‚     β”‚  rail-traffic-information β”‚
                        β”‚  (pooled, lifespan-managed)β”‚    β”‚  construction-projects   β”‚
                        β”‚  ODSQL escaping + Pydantic β”‚     β”‚  perron Β· rollmaterial   β”‚
                        β”‚  validation               β”‚     β”‚  zugzahlen Β· dienststellenβ”‚
                        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Project Structure

sbb-opendata-mcp/
β”œβ”€β”€ src/sbb_opendata_mcp/
β”‚   β”œβ”€β”€ __init__.py
β”‚   └── server.py                   # FastMCP server, all 10 tool definitions
β”œβ”€β”€ tests/
β”‚   └── test_server.py              # Unit + live API smoke tests
β”œβ”€β”€ audits/                         # MCP best-practice audit evidence
β”œβ”€β”€ docs/assets/demo.svg            # README demo asset
β”œβ”€β”€ .github/workflows/ci.yml        # GitHub Actions (Python 3.11/3.12/3.13)
β”œβ”€β”€ Dockerfile                      # Multi-stage, non-root runtime image
β”œβ”€β”€ docker-compose.yml              # Local run with resource limits
β”œβ”€β”€ claude_desktop_config.json      # Example Claude Desktop config
β”œβ”€β”€ pyproject.toml
β”œβ”€β”€ CHANGELOG.md
β”œβ”€β”€ CONTRIBUTING.md
β”œβ”€β”€ SECURITY.md
β”œβ”€β”€ EXAMPLES.md
β”œβ”€β”€ LICENSE
β”œβ”€β”€ README.md                       # This file (English)
└── README.de.md                    # German version

Safety & Limits

  • Read-only: All 9 tools perform read-only HTTP GET requests β€” no data is written, modified, or deleted upstream.

  • No personal data: Queries are transient and not stored. The portal returns aggregated statistics, infrastructure and operational metadata. No PII is processed or retained.

  • No API key: Data is public and free. There is no authentication and no secret to manage.

  • Injection-hardened: year/canton are regex-validated and every value interpolated into an ODSQL where clause is escaped via a central helper.

  • Data freshness: Real-time tools (disruptions) reflect the upstream source at query time; statistical datasets update annually/daily (see the tool table).

  • Terms of service: Data is published under the data.sbb.ch licence (NonCommercialAllowed-CommercialAllowed-ReferenceRequired).

  • No guarantees: This server is a community project, not affiliated with SBB. Availability depends on the upstream API.

See SECURITY.md for the full security posture.


Known Limitations

  • Passenger frequency: Updated annually; the latest full year may lag by some months.

  • Rail disruptions: Returns all current Swiss rail messages β†’ use limit and pagination.

  • Trains per segment: Counts are yearly aggregates, not real-time.

  • Station search: Covers the full Swiss DiDok register (all operators), not just SBB.

  • No rate limiting of its own: Place a public HTTP deployment behind a rate-limiting reverse proxy.


MCP Protocol Version

This server speaks two protocol eras over the same endpoint. The client's first request on a connection decides which one applies; a later claim from the other era is refused.

Era

Revision

Who reaches it

initialize handshake

2024-11-05 … 2025-11-25

What today's clients speak. The server answers with the revision asked for, or with the 2025-11-25 ceiling when the request asks for something newer.

Per-request envelope

2026-07-28

A request carrying the 2026-07-28 _meta envelope opens a modern connection.

Both revisions are pinned in tests/test_protocol_version.py and asserted against the installed SDK, so a Dependabot bump of mcp cannot move either one silently. This server builds no ASGI app to send an initialize through, so the gate asserts the SDK constants rather than a measured response β€” the weaker form, named rather than left unsaid.

Note that the SDK's LATEST_PROTOCOL_VERSION is an alias for the modern era, not for the handshake era β€” pinning against it alone would leave the era that current clients actually negotiate free to drift.

Update policy. When the gate fails, do not edit the constant blindly: read the spec changelog between the two revisions, verify the server still behaves, then move the constant, this section, README.de.md and CHANGELOG.md together.


Testing

No API key is required.

# Unit tests (no network required)
PYTHONPATH=src pytest tests/ -m "not live"

# Live API smoke tests (require network access to data.sbb.ch)
PYTHONPATH=src pytest tests/ -m live

# Re-record the fixtures from data.sbb.ch (writes tests/fixtures/PROVENANCE.md)
python scripts/record_fixtures.py

The unit-test payloads are recorded, not invented. Source, retrieval date, selection rule and SHA-256 per file are in tests/fixtures/PROVENANCE.md.

tests/fixtures/dataset_fields.json is not a data excerpt but the contract: the Explore v2.1 API declares each dataset's field names, and a select or order_by on a field it does not have is answered with HTTP 400 β€” not with fewer columns. TestFieldContract holds every field name the server uses against that declaration, so the next rename fails a test instead of a user's request. Until 2026-08-08 three of ten tools were permanently broken for exactly this reason.

Live tests are not run by CI (-m "not live"). Two of those three broken tools had live tests covering them β€” test_live_search_waedenswil and test_live_list_datasets. The coverage existed; the run did not.


Changelog

See CHANGELOG.md


Contributing

See CONTRIBUTING.md


Security

See SECURITY.md (Deutsch) for the security posture and how to report a vulnerability.


License

MIT License β€” see LICENSE


Author

Hayal Oezkan Β· github.com/malkreide


Installation

Run via uv's uvx β€” no clone or manual install needed. Add to your MCP client config (mcpServers for Claude Desktop, Cursor and Windsurf; use a top-level servers key for VS Code in .vscode/mcp.json):

{
  "mcpServers": {
    "sbb-opendata-mcp": {
      "command": "uvx",
      "args": [
        "sbb-opendata-mcp"
      ]
    }
  }
}

Available Tools

10 tools
sbb_compare_stationsA
Read-onlyIdempotent

Vergleicht mehrere SBB-BahnhΓΆfe anhand Passagierfrequenz und Perrondaten.

Kombiniert drei DatensΓ€tze (Passagierfrequenz, Bahnhofnutzer, Perrons) zu einem kompakten Vergleich. NΓΌtzlich fΓΌr Planungsentscheide, PrΓ€sentationen und Standortanalysen.

Args: params (CompareStationsInput): Parameter: - stations (list[str]): Liste von Bahnhofsnamen (2–10), z.B. ['ZΓΌrich HB', 'Bern'] - year (Optional[str]): Vergleichsjahr, z.B. '2024'

Returns: str: Tabellarischer Vergleich der BahnhΓΆfe mit Passagierfrequenz und Perron-Kennzahlen.

ParametersJSON Schema
NameRequiredDescriptionDefault
paramsYes

TDQS

A3.8/5.0
Behavior3/5

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

Annotations already declare readOnlyHint, idempotentHint, and destructiveHint=false, so safety is clear. The description adds that it combines three datasets and returns a table, but doesn't disclose potential failure modes (e.g., unknown station names) or default behavior for year, which is a moderate gap.

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 well-structured with a clear lead sentence, a context sentence, and organized Args/Returns sections. It is somewhat redundant with the schema (listing parameters) but remains compact and scannable.

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

Completeness3/5

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

There is no output schema, but the Returns section specifies a tabular string with passenger frequency and platform metrics, which is helpful. However, the description omits the response_format option and does not address error handling, making it not fully complete for an agent to invoke correctly in all cases.

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 description covers stations and year with examples and constraints, but omits the 'response_format' parameter entirely. While the nested schema provides detailed descriptions, the top-level 'params' has 0% schema coverage, so the description partially compensates but remains incomplete.

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 'Vergleicht mehrere SBB-BahnhΓΆfe anhand Passagierfrequenz und Perrondaten', a specific verb+resource+criteria. It further distinguishes itself from sibling single-dataset tools by stating it 'Kombiniert drei DatensΓ€tze...' to create a compact comparison, clearly establishing its unique role.

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

Usage Guidelines4/5

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

It explicitly lists use cases ('NΓΌtzlich fΓΌr Planungsentscheide, PrΓ€sentationen und Standortanalysen'), providing clear context. However, it does not mention alternatives or when not to use this tool relative to the sibling getters, so it lacks explicit exclusions.

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

sbb_get_infrastructure_construction_projectsA
Read-onlyIdempotent

Ruft laufende SBB-Infrastruktur-Bauprojekte (BahnhΓΆfe, Strecken, Ausbau) ab.

EnthΓ€lt Projektname, Ort, Projektart, Angebotsschritt und Links zu Projektseiten. Geeignet fΓΌr Stadtplanung, Kommunikation und Raumplanung.

Args: params (ConstructionProjectsInput): Parameter: - city (Optional[str]): Ortsfilter, z.B. 'ZΓΌrich', 'Basel' - project_type (Optional[str]): Projektart, z.B. 'ausbau' - limit (int): Max. Resultate - offset (int): Paginierung - response_format (str): 'markdown' oder 'json'

Returns: str: Liste Infrastruktur-Bauprojekte mit Ort, Art und Projektlinks. Schema: {name, location, type, category, link}

ParametersJSON Schema
NameRequiredDescriptionDefault
paramsYes

TDQS

A4.5/5.0
Behavior4/5

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

Annotations already cover the safety profile (read-only, idempotent, non-destructive). The description adds value by detailing the return schema (name, location, type, category, link) and explaining the meaning of parameters, which goes beyond the annotation coverage. It does not contradict 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 well-structured with a concise opening sentence, a note on contents, a usage line, and clearly formatted Args/Returns sections. Every sentence is informative and there is no redundancy or fluff.

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

Completeness4/5

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

Given the lack of an output schema, the description includes a useful return schema. It also documents all parameters and their purpose, covering the essentials. However, it does not explicitly mention default values (limit=20, offset=0, response_format=markdown) which are present in the schema, so it is not fully self-contained but still sufficiently 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?

The input schema has only a top-level 'params' field with no description, and nested properties like limit, offset, and response_format lack descriptions. The description compensates by listing all five properties with types, meanings, and examples (e.g., city 'ZΓΌrich', project_type 'ausbau', limit max results, offset pagination, response_format markdown/json).

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 states the tool fetches running SBB infrastructure construction projects (stations, routes, expansion) and lists the contained fields (name, location, type, procurement step, links). This specific verb+resource combination distinguishes it from siblings like sbb_get_real_estate_projects.

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

Usage Guidelines4/5

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

The description provides clear usage context by stating it is suitable for city planning, communication, and spatial planning. However, it does not explicitly mention when not to use it or name alternative tools, so it lacks exclusions but still offers strong contextual guidance.

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

sbb_get_passenger_frequencyA
Read-onlyIdempotent

Ruft Passagierfrequenzdaten (Ein-/Aussteigende) fΓΌr SBB-BahnhΓΆfe ab.

Datensatz wird jΓ€hrlich aktualisiert. EnthΓ€lt Tagesschnitt (DTV), Werktagesschnitt (DWV) und Nicht-Werktages-Schnitt (DNWV) pro Bahnhof und Jahr.

Args: params (PassengerFrequencyInput): Filterparameter: - station_name (Optional[str]): Bahnhofsname (Teilsuche) - canton (Optional[str]): KantonskΓΌrzel, z.B. 'ZH' - year (Optional[str]): Jahr, z.B. '2024' - limit (int): Max. Resultate (1–100), Standard 20 - offset (int): Offset fΓΌr Paginierung - response_format (str): 'markdown' oder 'json'

Returns: str: Passagierfrequenzdaten mit DTV/DWV-Werten und Paginierungsinfo. Schema: {station, year, daily_avg, workday_avg, non_workday_avg, canton, operator}

ParametersJSON Schema
NameRequiredDescriptionDefault
paramsYes

TDQS

A4.3/5.0
Behavior4/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, covering the safety profile. The description adds valuable context beyond this: the dataset is updated annually, contains specific average metrics, and the return includes pagination information. This enriches the behavioral understanding without contradicting 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 well-structured and concise: a lead sentence on purpose, a brief dataset context, an Args list, and a Returns schema. Every section earns its place without redundancy. It is front-loaded and not overly verbose.

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 complete for a read-only data retrieval tool: it specifies the dataset scope, update frequency, available metrics, all input parameters with defaults, and a return schema (despite no output schema). Combined with strong annotations, the agent has everything needed to select and invoke the tool correctly.

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?

Although the schema already describes each parameter, the description's Args section adds practical examples and constraints (e.g., 'ZH', '2024', partial search for station_name, default limit 20, response_format options). Since schema coverage is contextually marked as 0% (though schema has descriptions), the description effectively compensates by providing detailed parameter semantics.

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 begins with a clear, specific verb-resource pair: 'Ruft Passagierfrequenzdaten (Ein-/Aussteigende) fΓΌr SBB-BahnhΓΆfe ab' (retrieves passenger frequency data for SBB stations). It further specifies the contained metrics (DTV, DWV, DNWV) and distinguishes itself from sibling tools like disruptions or construction projects.

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

Usage Guidelines3/5

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

The description implies usage for passenger frequency queries but does not explicitly state when to use it vs alternatives. No exclusions or alternative tool names are provided. The context is clear, but the guidance is 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.

sbb_get_platform_dataA
Read-onlyIdempotent

Ruft Perrondaten (LΓ€nge, FlΓ€che, Typ) fΓΌr SBB-BahnhΓΆfe ab.

EnthΓ€lt PerronlΓ€nge (m), Netto-/BruttoflΓ€che (mΒ²), Perrontyp und Angaben zur schienenfreien ZugΓ€nglichkeit.

Args: params (PlatformDataInput): Parameter: - station_name (Optional[str]): Bahnhofsname, z.B. 'ZΓΌrich HB' - platform_type (Optional[str]): Perrontyp, z.B. 'Mittelperron' - limit (int): Max. Resultate - offset (int): Paginierung - response_format (str): 'markdown' oder 'json'

Returns: str: Perrondaten mit LΓ€nge, FlΓ€che und Typ. Schema: {station, platform_nr, type, length_m, gross_area_m2, net_area_m2, accessible}

ParametersJSON Schema
NameRequiredDescriptionDefault
paramsYes

TDQS

A4.1/5.0
Behavior4/5

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

Annotations already declare readOnly, idempotent, and non-destructive. The description adds context about the specific data returned (units, accessibility) and the output schema, exceeding basic annotation coverage. No contradictions with annotations.

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 structured with a summary, args, and returns sections. It is somewhat repetitive (schema repeated) but front-loads the purpose and stays within reasonable length for a data-retrieval tool.

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

Completeness4/5

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

Given the lack of an output schema, the description provides a return schema and parameter details, making it self-contained. It does not address edge cases like filtering behavior or pagination caps, but covers essential invocation and output expectations.

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 description coverage is 0%, but the description lists all parameters with types, examples, and German explanations. It adds meaning by defining 'limit' as 'Max. Resultate' and pagination, and clarifies optional fields, compensating well for the schema gap.

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 states the tool retrieves platform data (length, area, type) for SBB stations, using a specific verb ('Ruft ab') and resource. It distinguishes itself from sibling tools by focusing on platform-specific metrics, making the purpose unambiguous.

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

Usage Guidelines3/5

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

The description implies use for platform information via its content but does not explicitly state when to use it over sibling tools or mention alternatives. No exclusion criteria or use-case guidance is provided beyond the inherent purpose.

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

sbb_get_rail_disruptionsA
Read-only

Ruft aktuelle BahnverkehrsstΓΆrungen und -meldungen ab (alle 5 Minuten aktualisiert).

EnthΓ€lt Titel, Beschreibung, Ursache, Start-/Endzeitpunkt und betroffene Linien. Ideal fΓΌr Echtzeit-Monitoring und Kommunikation bei Ereignissen.

Args: params (RailDisruptionsInput): Parameter: - limit (int): Max. Meldungen (1–100), Standard 20 - offset (int): Offset fΓΌr Paginierung - response_format (str): 'markdown' oder 'json'

Returns: str: Liste aktueller StΓΆrungsmeldungen mit Zeitfenstern und Beschreibungen. Schema: {title, description, published, start, end, type, author}

ParametersJSON Schema
NameRequiredDescriptionDefault
paramsYes

TDQS

A4.5/5.0
Behavior4/5

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

Annotations already declare readOnlyHint and destructiveHint, and the description adds valuable context: data is refreshed every 5 minutes, and the response includes cause, affected lines, and time windows. No contradictions with 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 well-structured with a short summary, use-case sentence, parameter list, and return format. Every sentence adds value, and the layout is clean and easy to scan.

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 read-only data-retrieval tool with one nested parameter and no output schema, the description fully covers what the tool returns (list of records with title, description, published, start, end, type, author), the update frequency, and the available parameters. It is complete for its purpose.

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?

The description includes an 'Args' section that explains each parameter (limit, offset, response_format) with default values and allowed options. While the schema also describes these, the description makes the tool usable without needing to inspect the schema, adding clarity.

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 uses a specific verb 'abruft' (retrieves) with a clear resource: current rail disruptions and messages. It explicitly mentions the live update interval (alle 5 Minuten) which distinguishes it from related SBB data tools, making its 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 Guidelines4/5

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

It states 'Ideal fΓΌr Echtzeit-Monitoring und Kommunikation bei Ereignissen' which clearly indicates when to use the tool. It does not explicitly name alternatives, but the sibling tools cover other data domains, so the context is sufficient.

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

sbb_get_real_estate_projectsA
Read-onlyIdempotent

Ruft laufende SBB-Immobilien-Bauprojekte (Wohn- und GeschΓ€ftsbauten) ab.

TΓ€glich aktualisiert. EnthΓ€lt Projektname, Stadt, Bauphase, NutzflΓ€che, Baudaten und Beschreibungen (DE/FR/IT/EN).

Args: params (RealEstateProjectsInput): Parameter: - city (Optional[str]): Stadt, z.B. 'ZΓΌrich', 'Bern', 'Luzern' - phase (Optional[str]): Projektphase, z.B. 'CONSTRUCTION', 'PLANNING' - limit (int): Max. Resultate - offset (int): Paginierung - response_format (str): 'markdown' oder 'json'

Returns: str: Immobilien-Bauprojekte mit Baustart, Einzug und NutzflΓ€che. Schema: {title, city, phase, start_of_construction, move_in, area_m2, description}

ParametersJSON Schema
NameRequiredDescriptionDefault
paramsYes

TDQS

A4.1/5.0
Behavior4/5

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

Annotations already establish read-only and non-destructive behavior. The description adds value by disclosing that data is updated daily and that descriptions come in DE/FR/IT/EN, which are not evident from annotations. It also clarifies the output format (markdown/json) and return schema, giving the agent a fuller behavioral picture.

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 well-structured with a clear header sentence, a data freshness/contents note, and separate Args and Returns blocks. It is not overly verbose, though the Args block duplicates schema property information. Overall, it is efficient and easy to scan, earning a solid score.

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

Completeness4/5

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

The description includes the output schema inline, compensating for the lack of a structured output schema. It covers the key fields (title, city, phase, start_of_construction, move_in, area_m2, description) and mentions daily updates. However, it does not address pagination limitations or error handling, which is a minor gap for a data retrieval tool.

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?

The description provides meaningful examples for city ('ZΓΌrich', 'Bern', 'Luzern') and phase ('CONSTRUCTION', 'PLANNING'), and explains limit as 'Max. Resultate' and offset as 'Paginierung'. While the schema already describes city and phase, the description covers all parameters with usage context, adding value beyond raw schema definitions. The response_format parameter is also clarified with 'markdown' oder 'json'.

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 uses specific verb 'Ruft ab' (fetches/retrieves) with a clearly defined resource: 'SBB-Immobilien-Bauprojekte (Wohn- und GeschΓ€ftsbauten)'. This distinguishes it from sibling tools like infrastructure construction projects by scope (real estate vs. infrastructure). The inclusion of a daily update note and field list further clarifies the specific resource.

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

Usage Guidelines3/5

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

The description implies usage for fetching real estate construction projects but provides no explicit guidance on when to use this tool versus alternatives. It does not state exclusions or mention sibling tools, leaving the agent to infer context. The daily update note offers minimal contextual cue but not enough for clear alternative selection.

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

sbb_get_rolling_stockA
Read-onlyIdempotent

Ruft technische Daten zum SBB-Rollmaterial (ZΓΌge, TriebzΓΌge, Wagen) ab.

EnthΓ€lt Fahrzeugtyp, SitzplatzkapazitΓ€t (1./2. Kl.), Baujahr, LΓ€nge und Gewicht.

Args: params (RollingStockInput): Parameter: - vehicle_type (Optional[str]): Fahrzeugtyp, z.B. 'IC 2000', 'TGV', 'FV-Dosto' - limit (int): Max. Resultate - offset (int): Paginierung - response_format (str): 'markdown' oder 'json'

Returns: str: Rollmaterial-Daten mit KapazitΓ€t, Baujahr und technischen Kennzahlen. Schema: {vehicle_type, built_year, seats_1st, seats_2nd, total_seats, length_mm, weight_t}

ParametersJSON Schema
NameRequiredDescriptionDefault
paramsYes

TDQS

A4.4/5.0
Behavior4/5

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

Annotations already declare the tool as read-only, idempotent, and non-destructive. The description adds a useful return schema and notes pagination behavior, enriching the behavioral context without overstepping annotation coverage.

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 efficiently structured with a clear purpose statement, a content overview, parameter documentation, and return schema. Every sentence adds value, and the format is easy to scan.

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?

With rich annotations and no output schema, the description provides everything needed: input parameter docs, return schema, and purpose. A complete picture for a read-only query tool.

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 description coverage is 0%, but the description thoroughly documents all four nested parameters with types, defaults, and examples (e.g., vehicle types). This fully compensates for the absence of schema descriptions.

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 states the tool retrieves technical data about SBB rolling stock, listing specific content types (vehicle type, seating capacity, year, length, weight). This distinct resource differentiates it from all sibling tools, which focus on other data domains.

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

Usage Guidelines3/5

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

The context of use is clear (need rolling stock technical data), but there is no explicit guidance on when to use this tool versus alternatives, nor any mention of exclusions. Usage is implied rather than stated.

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

sbb_get_trains_per_segmentA
Read-onlyIdempotent

Ruft Anzahl ZΓΌge pro Streckenabschnitt und Verkehrstyp ab.

Deckt SBB, BLS, SOB, DB und weitere Infrastrukturbetreiberinnen ab. EnthΓ€lt Personenverkehr und GΓΌterverkehr, Trassenkilometer und Stromverbrauch.

Args: params (TrainsPerSegmentInput): Parameter: - line_name (Optional[str]): Streckenbezeichnung (Teilsuche) - operator (Optional[str]): Infrastrukturbetreiberin, z.B. 'SBB', 'BLS' - year (Optional[str]): Jahr, z.B. '2025' - traffic_type (Optional[str]): 'Personenverkehr' oder 'Gueterverkehr' - limit (int): Max. Resultate - offset (int): Paginierung - response_format (str): 'markdown' oder 'json'

Returns: str: Zugzahlen pro Streckenabschnitt mit Operator und Traffiktyp. Schema: {segment, line, operator, year, train_count, traffic_type, track_km}

ParametersJSON Schema
NameRequiredDescriptionDefault
paramsYes

TDQS

A4/5.0
Behavior3/5

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

Annotations already declare readOnlyHint, idempotentHint, and destructiveHint=false. The description adds context about data coverage (operators, traffic types, track_km, Stromverbrauch) and the return schema, but does not disclose additional behavioral traits such as pagination behavior or rate limits. It does not contradict annotations.

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 well-structured with an introductory paragraph, a bulleted Args list, and a Returns section. Every part is relevant, though it could be slightly trimmed. Minor typos (e.g., 'Traffiktyp') do not hinder clarity.

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

Completeness4/5

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

With no output schema, the description provides a return schema and parameter meanings, covering all key aspects for a read-only data retrieval tool. It does not explain defaults or enum constraints, but those are present in the input schema. Overall, it is sufficiently complete for the tool's complexity.

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?

Despite the signal of 0% schema description coverage, the tool description manually enumerates all seven parameters within the nested params object with meaningful explanations (e.g., line_name for partial match, operator examples, traffic_type values, limit/offset for pagination, response_format options). This fully compensates for the schema gap.

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 starts with 'Ruft Anzahl ZΓΌge pro Streckenabschnitt und Verkehrstyp ab' – a specific verb (abrufen) and resource (train counts per segment and traffic type). It clearly distinguishes from siblings like sbb_get_passenger_frequency by focusing on train counts and infrastructure operators.

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

Usage Guidelines3/5

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

The description implies usage for retrieving train counts per segment across operators (SBB, BLS, etc.) and traffic types, but it does not explicitly mention when to use this tool over alternatives or any exclusions. There is no reference to sibling tools or specific use-case boundaries.

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

sbb_list_datasetsA
Read-onlyIdempotent

Listet alle verfΓΌgbaren SBB Open Data DatensΓ€tze (data.sbb.ch) auf.

Gibt Dataset-ID, Titel, Anzahl DatensÀtze und Aktualisierungsfrequenz zurück. Nützlich zur Übersicht und Entdeckung neuer DatensÀtze.

Returns: str: VollstΓ€ndige Liste aller SBB Open Data DatensΓ€tze. Schema: {dataset_id, title, records_count, update_frequency, themes}

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A4.5/5.0
Behavior4/5

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

Annotations already cover safety (read-only, idempotent, non-destructive). The description adds value by specifying the return type ('str') and the schema of the returned list, including fields like dataset_id, title, records_count, update_frequency, and themes. This goes beyond annotations and helps the agent understand what to expect.

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 concise, with a clear structure: a brief purpose statement, a line about return fields, and a structured 'Returns' section. Every sentence adds value without 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 simple list tool with no parameters and no output schema, the description is complete. It explains what the tool does, what it returns, and when to use it, fully covering the agent's needs.

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?

Since the tool has zero parameters, there is nothing to explain. The description correctly implies that no input is needed, and the baseline of 4 applies because the description does not obfuscate or add unnecessary parameter detail.

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 states the tool lists all available SBB Open Data datasets from data.sbb.ch, using a specific verb ('listet') and resource ('DatensΓ€tze'). It also explicitly mentions the return fields, distinguishing it from sibling tools that fetch specific data types like passenger frequency or rail disruptions.

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

Usage Guidelines4/5

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

The description provides clear context for use: 'Nützlich zur Übersicht und Entdeckung neuer DatensÀtze' (useful for overview and discovery). It does not explicitly list exclusions or alternatives, but the use case is evident enough to guide an agent.

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

sbb_search_stationsA
Read-onlyIdempotent

Sucht BahnhΓΆfe und Haltestellen der Schweiz (DiDok-Liste des BAV).

Deckt alle ΓΆV-Haltestellen ab (nicht nur SBB). EnthΓ€lt UIC-Nummern, Koordinaten, Kantone und Betreiberinformationen.

Args: params (StationSearchInput): Parameter: - query (str): Suchbegriff (mind. 2 Zeichen), z.B. 'WΓ€denswil', 'ZΓΌrich' - canton (Optional[str]): KantonskΓΌrzel, z.B. 'ZH' - limit (int): Max. Resultate - response_format (str): 'markdown' oder 'json'

Returns: str: Haltestellenliste mit UIC, Kanton und Koordinaten. Schema: {name, uic, canton, operator, coordinates}

ParametersJSON Schema
NameRequiredDescriptionDefault
paramsYes

TDQS

A4.5/5.0
Behavior4/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 valuable behavioral context: the data source (DiDok list), coverage of all stops, parameters like minimum query length, and the return schema. This goes beyond the structured 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 well-structured and front-loaded with a clear one-line summary. The docstring-style Args section is informative without waste, and every sentence contributes to understanding the tool's purpose, parameters, and output.

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?

Given the tool's moderate complexity and lack of an output schema, the description fully covers the input parameters, return type, and content of the results. It provides enough detail for an agent to select and invoke the tool correctly without ambiguity.

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 description coverage is 0% for the top-level 'params' parameter, but the description thoroughly documents all sub-parameters (query, canton, limit, response_format) with examples and meaning. It also explains the return format and fields, adding value beyond the schema's limited descriptions.

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 states the tool searches Swiss train stations and stops using the official DiDok list, with a specific verb (Sucht) and resource. It also distinguishes itself by covering all public transport stops, not just SBB, which differentiates it from sibling tools.

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

Usage Guidelines4/5

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

The description provides clear context about what this tool does and its scope (all Swiss stops, includes UIC numbers, coordinates, etc.), so an agent can infer when to use it. It does not explicitly mention alternatives or when not to use it, but the context is sufficient.

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. Dates show when Glama detected each change.

  1. 10 tool updatesv0.3.4
    • Changedsbb_compare_stations4 fields changed
      • addedInput schema / $defs / CompareStationsInput / properties / response_format
        Added value: +{
        +  "$ref": "#/$defs/ResponseFormat",
        +  "default": "markdown",
        +  "description": "Ausgabeformat: 'markdown' (lesbar) oder 'json' (maschinenlesbar)"
        +}
      • changedInput schema / $defs / CompareStationsInput / properties / year / anyOf
        Previous value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]New value: +[
        +  {
        +    "pattern": "^\\d{4}$",
        +    "type": "string"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • addedInput schema / $defs / ResponseFormat
        Added value: +{
        +  "enum": [
        +    "markdown",
        +    "json"
        +  ],
        +  "title": "ResponseFormat",
        +  "type": "string"
        +}
      • changedOutput schema / (root)
        Previous value: -{
        -  "properties": {
        -    "result": {
        -      "title": "Result",
        -      "type": "string"
        -    }
        -  },
        -  "required": [
        -    "result"
        -  ],
        -  "title": "sbb_compare_stationsOutput",
        -  "type": "object"
        -}New value: +null
    • Changedsbb_get_infrastructure_construction_projects1 field changed
      • changedOutput schema / (root)
        Previous value: -{
        -  "properties": {
        -    "result": {
        -      "title": "Result",
        -      "type": "string"
        -    }
        -  },
        -  "required": [
        -    "result"
        -  ],
        -  "title": "sbb_get_infrastructure_construction_projectsOutput",
        -  "type": "object"
        -}New value: +null
    • Changedsbb_get_passenger_frequency3 fields changed
      • changedInput schema / $defs / PassengerFrequencyInput / properties / canton / anyOf
        Previous value: -[
        -  {
        -    "maxLength": 2,
        -    "minLength": 2,
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]New value: +[
        +  {
        +    "maxLength": 2,
        +    "minLength": 2,
        +    "pattern": "^[A-Za-z]{2}$",
        +    "type": "string"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • changedInput schema / $defs / PassengerFrequencyInput / properties / year / anyOf
        Previous value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]New value: +[
        +  {
        +    "pattern": "^\\d{4}$",
        +    "type": "string"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • changedOutput schema / (root)
        Previous value: -{
        -  "properties": {
        -    "result": {
        -      "title": "Result",
        -      "type": "string"
        -    }
        -  },
        -  "required": [
        -    "result"
        -  ],
        -  "title": "sbb_get_passenger_frequencyOutput",
        -  "type": "object"
        -}New value: +null
    • Changedsbb_get_platform_data1 field changed
      • changedOutput schema / (root)
        Previous value: -{
        -  "properties": {
        -    "result": {
        -      "title": "Result",
        -      "type": "string"
        -    }
        -  },
        -  "required": [
        -    "result"
        -  ],
        -  "title": "sbb_get_platform_dataOutput",
        -  "type": "object"
        -}New value: +null
    • Changedsbb_get_rail_disruptions1 field changed
      • changedOutput schema / (root)
        Previous value: -{
        -  "properties": {
        -    "result": {
        -      "title": "Result",
        -      "type": "string"
        -    }
        -  },
        -  "required": [
        -    "result"
        -  ],
        -  "title": "sbb_get_rail_disruptionsOutput",
        -  "type": "object"
        -}New value: +null
    • Changedsbb_get_real_estate_projects1 field changed
      • changedOutput schema / (root)
        Previous value: -{
        -  "properties": {
        -    "result": {
        -      "title": "Result",
        -      "type": "string"
        -    }
        -  },
        -  "required": [
        -    "result"
        -  ],
        -  "title": "sbb_get_real_estate_projectsOutput",
        -  "type": "object"
        -}New value: +null
    • Changedsbb_get_rolling_stock1 field changed
      • changedOutput schema / (root)
        Previous value: -{
        -  "properties": {
        -    "result": {
        -      "title": "Result",
        -      "type": "string"
        -    }
        -  },
        -  "required": [
        -    "result"
        -  ],
        -  "title": "sbb_get_rolling_stockOutput",
        -  "type": "object"
        -}New value: +null
    • Changedsbb_get_trains_per_segment2 fields changed
      • changedInput schema / $defs / TrainsPerSegmentInput / properties / year / anyOf
        Previous value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]New value: +[
        +  {
        +    "pattern": "^\\d{4}$",
        +    "type": "string"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • changedOutput schema / (root)
        Previous value: -{
        -  "properties": {
        -    "result": {
        -      "title": "Result",
        -      "type": "string"
        -    }
        -  },
        -  "required": [
        -    "result"
        -  ],
        -  "title": "sbb_get_trains_per_segmentOutput",
        -  "type": "object"
        -}New value: +null
    • Changedsbb_list_datasets1 field changed
      • changedOutput schema / (root)
        Previous value: -{
        -  "properties": {
        -    "result": {
        -      "title": "Result",
        -      "type": "string"
        -    }
        -  },
        -  "required": [
        -    "result"
        -  ],
        -  "title": "sbb_list_datasetsOutput",
        -  "type": "object"
        -}New value: +null
    • Changedsbb_search_stations2 fields changed
      • changedInput schema / $defs / StationSearchInput / properties / canton / anyOf
        Previous value: -[
        -  {
        -    "maxLength": 2,
        -    "minLength": 2,
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]New value: +[
        +  {
        +    "maxLength": 2,
        +    "minLength": 2,
        +    "pattern": "^[A-Za-z]{2}$",
        +    "type": "string"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • changedOutput schema / (root)
        Previous value: -{
        -  "properties": {
        -    "result": {
        -      "title": "Result",
        -      "type": "string"
        -    }
        -  },
        -  "required": [
        -    "result"
        -  ],
        -  "title": "sbb_search_stationsOutput",
        -  "type": "object"
        -}New value: +null
  2. 10 tool updatesv0.1.0
    • First observedsbb_compare_stations
    • First observedsbb_get_infrastructure_construction_projects
    • First observedsbb_get_passenger_frequency
    • First observedsbb_get_platform_data
    • First observedsbb_get_rail_disruptions
    • First observedsbb_get_real_estate_projects
    • First observedsbb_get_rolling_stock
    • First observedsbb_get_trains_per_segment
    • First observedsbb_list_datasets
    • First observedsbb_search_stations

TDQS

A4.3/5.0
Disambiguation5/5

Each tool targets a distinct SBB Open Data dataset or operation. Even similar-sounding tools like infrastructure construction vs real estate projects are clearly differentiated by their descriptions and parameters. No two tools appear to do the same thing.

Naming Consistency5/5

All tools follow a consistent sbb_<verb>_<object> pattern. Most use sbb_get_* for data retrieval, with sbb_search_stations, sbb_compare_stations, and sbb_list_datasets as readable variations. Naming is uniform and predictable.

Tool Count5/5

With 10 tools, the server is well-scoped. Each tool covers a meaningful SBB Open Data domain without being overwhelming. The count is within the ideal range for a focused data-access server.

Completeness4/5

The tool set covers major SBB Open Data categories: stations, passenger frequency, platforms, rolling stock, disruptions, train counts, infrastructure, real estate, and a dataset catalog. Minor gaps exist (e.g., no explicit timetable data), but core workflows are well supported and sbb_list_datasets helps discover additional datasets.

Maintenance

ActivityActive
ResponsivenessUnresponsive

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    C
    maintenance
    An MCP server that enables AI assistants to interact with the Netherlands Railways (NS) API for route planning, pricing, and real-time departure information. It provides tools for searching stations, planning trips with connections, and viewing real-time departure boards.
    3
    1
    MIT
  • A
    license
    A
    quality
    D
    maintenance
    A zero-authentication MCP server for Swiss public transport, enabling users to query train connections, disruptions, station facilities, and plan journeys using natural language.
    12
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    An MCP server for real-time Italian railway data, enabling natural language queries about train schedules, delays, departures, arrivals, and live tracking via the Viaggiatreno API.
    6
    MIT

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/malkreide/sbb-opendata-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server