Skip to main content
Glama
Fanfulla

MCP Trenitalia

by Fanfulla

MCP Trenitalia

Ciuff is a free, self-hosted MCP server for Italian railway information. It combines official Trenitalia and Italo timetables with their public live-information services.

ciuff.org is the existing project website. The server works over stdio, Streamable HTTP or legacy SSE. It needs no paid API account, subscription, database or cloud service.

Features

  • Search stations and direct journeys across Trenitalia and Italo.

  • Query Trenitalia train status, arrivals and departures.

  • Query Italo train status and station boards.

  • Report timetable coverage, sources and update timestamps.

  • Keep future timetables separate from today's live information.

  • Provide official ticket-site links. Live prices, seat availability and booking are not implemented.

Example questions:

Which direct Trenitalia and Italo trains leave Roma Termini for Milano Centrale tomorrow after 08:00?

What is the current status of Italo 8908?

Do the downloaded timetables cover my travel date?

Related MCP server: SBB Open Data MCP Server

Install

Requires Python 3.12 or newer. Dependencies are open source; network access is needed to download timetables and query live information.

git clone https://github.com/Fanfulla/MCP_Trenitalia.git
cd MCP_Trenitalia
python -m venv .venv

Activate the environment:

# Windows PowerShell
.venv\Scripts\Activate.ps1
# macOS / Linux
source .venv/bin/activate

Then install and download current validated timetables:

python -m pip install -r requirements.txt
python update_data.py

With uv, uv venv and uv pip install -r requirements.txt are alternatives.

Timetable caches are created under data/ and are not distributed in this repository. The first download can take a few minutes. Live tools can still run without the caches; schedule tools report missing or invalid coverage explicitly.

Run and connect

# Local MCP client
python server.py

# Recommended HTTP transport: POST /mcp
python server.py --streamable-http

# Existing SSE clients: GET /sse and POST /messages/
python server.py --sse

--http remains an alias for legacy SSE, preserving the original runtime behavior. Older README versions incorrectly described that flag as Streamable HTTP.

Example stdio client configuration on Windows:

{
  "mcpServers": {
    "MCP Trenitalia": {
      "command": "C:\\path\\to\\MCP_Trenitalia\\.venv\\Scripts\\python.exe",
      "args": ["C:\\path\\to\\MCP_Trenitalia\\server.py"]
    }
  }
}

On macOS/Linux, use absolute paths to .venv/bin/python and server.py. For HTTP clients, select the matching transport and connect to http://127.0.0.1:8000/mcp or http://127.0.0.1:8000/sse.

Tools

The five original names and nested params input envelope remain available.

Tool

Purpose

trenitalia_cerca_stazione

Local station lookup with Viaggiatreno fallback

trenitalia_monitora_partenze

Live Trenitalia departures

trenitalia_monitora_arrivi

Live Trenitalia arrivals

trenitalia_traccia_treno

Live Trenitalia train details with origin station

trenitalia_orari_tra_stazioni

Date-aware direct Trenitalia journeys and today's live enrichment

ciuff_cerca_stazioni

Station search across one or both operators

ciuff_cerca_viaggi

Direct scheduled journeys across one or both operators

ciuff_stato_treno

Public train status for an explicitly selected operator

italo_tabellone

Italo arrivals or departures by station name or Italo code

ciuff_stato_fonti

Local timetable coverage and provenance, not upstream uptime

ciuff_link_biglietti

Official purchase-site links, with prices explicitly unavailable

The six new tools return MCP structured content. Example arguments for ciuff_cerca_viaggi:

{
  "params": {
    "stazione_a": "Roma Termini",
    "stazione_b": "Milano Centrale",
    "data": "2026-09-28",
    "orario_da": "08:00",
    "operatore": "all",
    "limite": 10
  }
}

operatore accepts all, trenitalia or italo for station/journey searches. Train status requires a specific operator and numero_treno. ciuff_stato_fonti takes no arguments. Station IDs belong to their source; use names to search both operators. Ambiguous names return choices instead of selecting the first match.

Sources and freshness

Data

Source

Limits

Trenitalia schedules

National NeTEx feed, CCISS

Static schedules with service calendars and validity periods

Italo schedules

NeTEx feed, CCISS

Direct rail services; combined itineraries are excluded

Trenitalia live information

Viaggiatreno

Undocumented public endpoints, currently accessed over HTTP

Italo live information

Italo In Viaggio

Undocumented public endpoints, without a reliable service-date field

Live verification on 2026-09-27 found:

  • Trenitalia feed published on 2026-09-25, valid 2026-09-26 through 2026-12-12.

  • Italo feed published on 2026-09-26, valid 2026-09-25 through 2027-02-02.

  • Both feeds returned direct Roma Termini to Milano Centrale journeys.

  • Both public live-information adapters returned data.

These are verification snapshots, not guarantees of continued upstream availability. Check ciuff_stato_fonti for your local feed dates.

# Refresh all, or just one provider
python update_data.py
python update_data.py --provider italo
python update_data.py --provider trenitalia

Refresh validates the feed before atomically replacing the previous cache. A failed refresh preserves the old file; expired coverage is still reported as expired. Running servers pick up cache changes without restarting. For unattended refresh, run the command daily with your operating-system scheduler. No scheduler or subscription is installed automatically.

# Check local timetable validity and the live Viaggiatreno and Italo endpoints
python check_sources.py

check_sources.py exercises the same parsers as the server: it fails when a live source stops responding or changes format, or when a local timetable is missing or expired, and warns when fewer than 21 days of validity remain. The repository runs it daily in the free Source health GitHub Actions workflow after downloading both official feeds; a failure opens or updates a "Controllo fonti fallito" issue, which is closed automatically after recovery. GitHub pauses scheduled workflows in public repositories after 60 days without activity.

The parser supports the Italian-profile structures in the verified feeds, including UIC calendar bits, explicit date exceptions, boarding restrictions and overnight offsets. It is not a general NeTEx implementation. Unsupported calendars, unresolved references and ambiguous/nonexistent daylight-saving wall times fail closed. Searches cover direct trains, not transfers or historic telemetry.

Italo output distinguishes request time (observed_at) from the source update time. When the service date cannot be verified, service_date is null and freshness is date_unverified. Such delays are not attached to a dated scheduled journey. Missing delays remain null; they never mean "on time". Stale responses are labeled separately. Cancellation meanings are not guessed from undocumented numeric codes.

Self-hosting

The server defaults to loopback. It includes a health endpoint, allowed-host checks, a per-peer request limit and an optional bearer token. Outbound requests use an in-process cache and connection pool, with bounded concurrency, response sizes and transient retries.

Variable

Default

Purpose

PORT

8000

HTTP listen port

MCP_HOST

127.0.0.1

Bind address; use 0.0.0.0 to expose the service intentionally

LOG_LEVEL

info

Uvicorn log level

MCP_ALLOWED_HOSTS

localhost,127.0.0.1,[::1]

Comma-separated hostnames, without scheme or port

MCP_RATE_LIMIT

60

Requests per minute per connected peer, per process

MCP_API_KEY

unset

Optional token required as Authorization: Bearer ...

Use TLS at your reverse proxy for remote access and add its hostname to MCP_ALLOWED_HOSTS. Forwarded client IP headers are not trusted: behind a proxy, the built-in limit applies to its address. Configure per-user limits at your proxy if needed. /health is token-exempt and reports process/local-cache status, not live upstream health. Requests with a missing or wrong token count towards the per-peer limit. The optional token is static access control, not OAuth.

The existing Procfile preserves legacy SSE. Configure MCP_HOST and MCP_ALLOWED_HOSTS for your host, or change the launch command to python server.py --streamable-http. The project requires no hosting subscription; operating a public host is your responsibility. The existing web/ website remains separate.

Development

python -m pip install -r requirements-dev.txt
python -m pytest -q
python -m compileall -q server.py models.py rail_service.py timetable.py build_timetable.py build_stazioni.py update_data.py check_sources.py viaggiatreno.py italo.py http_client.py http_app.py time_utils.py

Tests use local fixtures and mocked network transports. They cover calendars, midnight/DST, stale data, station ambiguity, retries, malformed responses, structured MCP output, HTTP limits and multi-client SSE cleanup. Live checks are separate from the offline suite. CI runs the offline tests on Windows and Linux; the daily source-health workflow runs the live checks.

The server uses the official MCP Python SDK, not the separate fastmcp distribution. See CHANGELOG.md for migration notes.

License

Project code is MIT licensed. Upstream datasets and provider responses have their own terms and are not relicensed under MIT. Public availability does not establish redistribution rights. Downloaded timetable caches stay local; source metadata is in data/sources.json.

This independent project is unaffiliated with Trenitalia or Italo.

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
    A
    maintenance
    An MCP server for Swiss Federal Railways (SBB) open data, enabling AI models to query real-time disruptions, passenger frequencies, station details, and more without an API key.
    9
    44 PyPI
    2
    MIT
  • F
    license
    Not graded
    quality
    D
    maintenance
    MCP server for real-time German public transport data (HAFAS/VBN network). Enables querying departures, arrivals, journeys, and nearby stops using natural language.
    -