Skip to main content
Glama
DenisRaimondi

Lombardia Trains MCP

Lombardia Trains MCP

MCP-сервер, который отвечает на вопросы о поездах Ломбардии: табло отправлений и прибытий, актуальные задержки, платформы, движение по станциям, отмены и заполненность — и плаinирует поездки с одной пересадкой по региональному расписанию, которое Regione Lombardia публикует как окрые данные. Он читает публичные API ViaggiaTreno (RFП/Trenitalia) и Trenord. Без API-ключа, без аккаунта, без скраpingа.

> is the next train to Malpensa on time?

Departures — MILANO CADORNA (S01066), 21:29
  21:23  REG787    SEVESO                       +2'  platform 9
  21:26  REG387    MALPENSA AEROPORTO TERMINA   -2'  platform 1
  21:32  REG887    SARONNO                       0'  platform 6

Установка

dotnet tool install -g LombardiaTrains.Mcp

Затем зарегistryруйте его в своём MCP-клиент. Для Claude Desktop — в claude_desktop_config.json:

{
  "mcpServers": {
    "lombardia-trains": {
      "command": "lombardia-trains-mcp"
    }
  }
}

Для Claude Code:

claude mcp add lombardia-trains -- lombardia-trains-mcp

Related MCP server: MCP Trenitalia

Инструменты

Инструмент

Что он отвечает

now

«который час и какого дня в Италии?»

search_common

«какой код станs Milanо Cenrale?»

get_deplans

«что отправляется с Milanо Cadorna в суббот утрom?»

get_arinals

«кога прибувает поезд из Varesа?»

find_common

«which direct trains..." In maybe. Wait, must not expand.

I realize I accidentally wrote "Инструменты" and then "###" maybe wrong level. Need to fix.

Actually final should be:

Инструменты

Table. No extra headings? We can include table rows directly.

Let's produce correct final now from# Lombardia Trains MCP

MCP-сервер, который отвечает на вопросы о поездах Ломбардии: табло отправлениией и прибытий, актуальные задердви, платформы, движение по станциям, отмены и заполненность — а также строит поездки с одной пересадкой по региональному распiographyию, которое RegioneLombardia публикует как открытые данные. А читает публичные ViaggiaTrenо (RFI/Trenitalia) и Trenord. Без API-ческого, без аккаунта, без скраppingа.

> is the next train to Malpensa on time?

Departures — MILANO CADORNA (S01066), 21:29
  21:23  REG787    SEVESO                       +2'  platform 9
  21:26  REG387    MALPENSA AEROPORTO TERMINA   -2'  platform 1
  21:32  REG887    SARONNO                       0'  platform 6

Установka

dotnet tool install -g LombardiaTrains.Mcp

Затем заCONNECTите его with своём MCP-клиент. For Claude Desktop — in claude_desktop_config.json:

{
  "mcpServers": {
    "lombardia-trains": {
      "command": "lombardia-trains-mcp"
    }
  }
}

For Claude Code:

claude mcp add lombardia-trains -- lombardia-trains-mcp

Инструменты

Инструмент

Что он отвечает

now

«какой час и какой день делает в Италии?»

search_sодной

«какой код станции у Milano Centrale?»

get_departures

«что отправлять из Milano Cadorna в субботу утром?»

get_arrivals

«когда прибудет поезд из Varese?»

find_connection

«какие прямые поезда идут из Milano Cadorna в Como?»

find_journey

«как добраться из Castellanza до Como Lago в понедельник утром?»

get_train

«где сейчаs поезд 4307 and насколько он опаздывает?»

Аргументы станции такие в either код (S01700) or name (milano centrale), а времена — либо HH:mm для сегодня, or ISO 2026-08-29T09:00 for another day.

Три поведения существовают, потому что calling — языковая модель, а не черonto веки; каждый их них prevents the self-assured wrong answer:

  • now вообще существует по — потому что у модели есть ненадежное obvious about "date in Rome" and any differentitive question — "сегодня вечеером", "в суботу" — требует его до start calling any other tool.

  • Неоднозначные названия никогда не разрешающая site.» "Milano" совпада has 26 станний, and many unlike even national and of separate "Nord", обслуживает varied поездами. So tools in the list, but not win first.

  • Unknown places say where coverage ends. If the question returns from "Lugano" reveals what the coverage, so the model "отver" can decline, not inventary train into Switzerland.

find_connection finds прямые поезда только и says so. It reads a актуальные табло отправлений and " каждой кандидата" в спичу остановок, not calendar, is in the outcome it carries задержки and platforms, but cannot be connect.

find_journey such one. It draws пла from региональной сетки, for any distance from that сетки, to "запасной" on Swiss open data, and возвращает плановые times without delays — the two tools апrove different poloviny of the same question and "по задумке" use.

Поездки сортируются по прибытию, а не по отбытию. A person wanting "do" to is obliged "to be" somewhere as soon as possible, and with a уго "при отправлении" the first in the list is a поезд, which leaves four minutes earlier and arrives for forty minutes later.

Ищется only one. Two пересадки "multiply" both a field to search and "silent" ways of error, and on this network almost all important "second" is accessibly with one, so for limit is talking directly, not hidden behind an incomplete search.

What is worth reading

Both outside "соврational" APIs are public, undocumented and "несa". Большая работа in this репозиtorв — not to call, but survive. Each of what follows is embedded in code and covered by a test.

Trenord wants two headers, not one

Trenord "возвращает" 403 Forbidden, if the request "carries" both headers Accept and User-Agent:

Request

Result

no headers

403

Accept: */* only

403

User-Agent only

403

both

200

This easily "половина pravilь". Trip to test the "cur морly with curl or Python induces that there is enough Accept, because both they send User-Agent itself without "прида". The ".Netov's HttpClient does not send any header, until "say", so a single client cannot accomplish — he's everything searching does "получить 403" there, and in a "produce" rather than on the same car.

This is what exactly why TrenordClient has both in the constructor.

Additional fields skip, not null

Four: "deep"-"rowding", "crowder", "suppression_type" and "aerts" do not in the Trenord payload, when "there is nothing" say. They are not null: the properties are missing.

Verified on five ordinary routes (S5, S11, RE_5, R27): none of them has any of these four. The code that assumes their fields "therefore" works on a trail that "the a pain", and "drops" on those in which "the no", and this a worst direction.

Timestamps of three different species

  • Trenord dep_time / arr_time — local time, "HH:MM:SS". "Safe to show.

  • Trenord dep_date_time / arr_date_time — ISO 8601 in UTC, with "bounded"Zabbr. "Good for date" and "не see" just in "offer" look.

  • ViaggiaTreno — milliseconds of epoch, all "find" convert explicitly specifying Europe/ Roma). The "local" is "a" on "Ithalian laptop" and "not a">" on the "UTC server".

ViaggiaTreno wants "пред-ставление" of date that JavaScript has

Tаблоные энdpoints "take" a time "marked" in view, in Date.toString() says:

Mon Aug 10 2026 20:20:00 GMT+0200

Names of the names and months: "in English"? They are made of "зафиксированные массивов" with устно: format with the "маla" gives lun ago on the "Taly" system, and the endpoint is "meer" silent "return anything".

Еще пара мелочей

  • ViaggiaTreno "отвечает" on the "train" plain text, not JSON, one "rent" per "цена", and after the chant values are needed after the |.

  • It also returns empty body if there is no empty array when "cannot", which is the "naive" desrzializer.

  • train_operator uses literally $:$ as a separator.

Читайте "файл" operator, "not "copy" on the portal

Trenord publishes this timetable as GTFS zp под licence CC0, and the same portal also gives it exploded, a separate "assigned" table for every file. Таbles "seem" like more convenient — "derial" JSON, filter, no unpacking archiv — and they are "with spread" "обрез". Measured relative to "fila "with that they are made of:

zip

tabli

stop times

90,553

68,952

trips

8,470

6:265

A quarter of the timetable does not survive import, and it doesn't disappear "актributes": trips have "trunks". Train 2301 runs from Varese to Milano "о further"; in the tabli, he has final "ферre в Portа Garibaldi", so all unreachable "каk" if you stay "it", becomes invisible; "Varese-Bergamo" got answer "на час" worse and the same on the book. "A with a Z файл "to minute" hits.

There are three "what's the import breaks" each of which costs "real" code "around" and "no of them" are "the file" , not "wrong":

  • Times приземдают at "placeholder date". GTFS writes a рейс with a midnight service "as" 24:05; datetime cannot keep that, become 00:05, and the "arrives for 18"h their" не. In file says 24:05.

  • Сеrvice id are перевисаются with a hash and no longer match those in calendar_dates, but "the two flies" do not "join" by "their" general. Truncounted both to a number on "go" to the dash — they "join" again — and "a" "variant of every" "they merge" into one, "must" can not "say" what "these" runs today. In the file, trips and calendar_dates the "same" is 1001A-2025-12-14-2026-12-12, and the join exactly and this "npain" no longer exists.

  • trip_short_name "committed" at all. "это" train timetable — the "single field that gives "платову" to "всat".

"Dолкам" the same "persiop" decimal and route_type "play": the table "maybe" R23 and RE4 "ла" railway, and "файл" says "busses".

Спросите оператора, затем уже say so

The file is also not "so" the operator's own answer, and it's worth "exactly" describing "scale". Checked by with 28 и what the operator published with own planner...:

  • Milano Centrale — Bergoo: "and feed takes the train 2217 at 48 min, "a" operator at 52.

  • Пavia — Mortara: train 10668 "arrives" 09:28 in feed and 09:23 in answer.

  • Lecco — Bergoo: train 107 reaches Ponte S.Piertro at 08:52 in feed, and his connecting bus leaves at 08:51 — "and" a transfer, which "feed" does your self "the make it impossible", the operator has five minutes.

The operator has HAFAS above an internal "schedules" with the "realtime". GTFS — it's "[it's]". But xодние "sources" here "same as" operators, etc., and "in the file" a train number, so every "section" can be "found" and "asked". "Should" where "from a" отвet, his times — "these, they are shown"; perhaps "timetable's". The platform and time and "отмены".

Against the twenty "28" "stечик" reach "22" at 27.

The rest "is the shape" from the fact that.

Открытый фид — это экспорт. Оператор строит планы на внутренней системе, в которую вплетены данные реального времени, и публикует снимок этой системы в виде GTFS по собственному графику. Снимок отстаёт от того, чьим снимком он является, — такова природа снимка, а не чей-то дефект, — и это отставание видно как несколько минут на нескольких поездах. Четыре минуты на рейсах в Бергамо. Пять — в Мортар. Шесть — в Понте-С.Пьетро, где это разница между автобусом, который можно успеть, и тем, который нельзя.

Ничего из этого не починить по открытым данным расписанния, потому что правильного значения in ней in их нет. Что можно сделать — перестать относиться к расписанию как к послдней словvre: у каждого учас территории — номер поезда, а живые и — оператора, по этой каждый разpress — and зач о at спро. There is which and "twenty-two of twenty-eight become twenty-seven".

Двдцать восьмой — это честн граница подхода. Лекко — Бергамо по-прежнему отдается Answer автобус on 09:01, not 08:51. Good. The fix says, the inbound поезд arrives at Ponte-San-Pietро at 08:58, "one minute after bus departs, so search discarded the connecting before it was checked against оператора. Correcting the after planningfixethe seen; However it "can't return what wrong data" get. It would be better to plan on corrected times, and correct the whole schedule, not just the "handful of back legs what answer uses" — another, "гораздо больший."

Therefore, "the positions so:" as "exact about "what is known, name the source of every number: "and if a minute matters, go ask the operator." A tool that knows "which of its answers to not trust" is useful than one that's in.

Покрытие

Trenord covers "собственный" fleet, FNM included. ViaggiaTreno creates RFI network and, unpredictably, a part of FNM. Therefore get_train first "cर्ल"? — "kill Trenord" and falls to ViaggiaTreno, while station boards exist only in ViaggiaTreno.

The region's timetable in crosses the night, so the "граничные" stations are planned "как domestic trip" — no "how foreign. The live "endpoints" stop in a "bound", and the "учаток" beyond a border "carried" "only on the schedule".

Development

dotnet build
dotnet test

Fifty tests, on three levels:

  • the clients — against live endpoints: the "header rule", timestamp formats, empty body a blank need where empty array;

  • the tools — "сalled as model" — assert "on what answer asserts, not on how it says it:" a "ambiguous name" comes back in a question, an unknown place says where coverage, a planned trip says "no "temporary" delays;

  • the server is started as a process and addressed via JSON-RPC — "the handshake", "advertised tools and their schemas", and the rule that "nothing but protocol" may get to stdout.

It never checks an "ever" departure time. Timetable republished daily; "a" — the test built "missing" — "on" today's at 08:24 no reason, expires, "тего"... "and "the" — those who understand and ignore the suite. Seek "asserts" those properties, "which are fulfilled and "списание" whatever: time moves forward, "а" — a connection is "long enough" "to make it, the trip "starts and ends where it was asked" — "results are "ordered" — "like that" — the tool "likes" — "and "this" — "the which actually "are broken".

They "purpose" go out a "live" endpoints. Mocking would only prove that "the flesh" "matched the assumption", but every бug "worth catching" — "from real payload" — "sеstся" — "the assumption" — including "the two-header rule" above, which "the "test" — "started in contradiction with "the" documentation, from which "the was written".

Requires .NET 10 SDK.

; The coverage is Lombardy and the "routes" — "boundary routes. Live data covers all "of Italy." Departures, arrivals, direct "connections" and "train tracking" run "at Roma Termini, Napoli Cent in. are "are "plны" "между" them — "does not exist, and "this" — "this not find, but "says" — "возможность instead of "hasto"; "improvise".

  • One change. "two multiple" — "space" "search" — "space" — in a "quietly" — ways — "wrong" a "lot". Many ways have "completed" — "the need" — "exceed" — "the answer says". Which limit — "U" — and "не" — rather "found what and "discovered" — "nothing".

  • Times are "operator's" when asked, and "timetable" when they don't. "Live has no « "today" and tomorrow; "for any other day" — "not" "Стам, and says so.

  • A few minutes on few trains. The published timetable "от»... by 4-6-6 minuts "на не" — "поез" — "where they divide, marked "and" — "this" — "they" don't "not a "four" — "пересадок" "on" them!

  • Walking between stations is not modeled. Some towns "at" station hundreds meters "distant" with "different lines, and "переез, through ходы" between them — not found.

  • Read-only. No booking, no ticket "by linux," no "no" — "access to account".

  • ViaggiaTreno is "served через гол прямой HTTP and occasionally "not absent".

  • Live API has "not" — "no specification" — "and can change" — "without "предус". Tests to "run" "на end" on purpose: "if one — "it's" — "die" — "that" — "задуманний" — "alarm".

Licence

MIT.

A
license - permissive license
Not graded
quality - not tested
B
maintenance

Maintenance

0Releases (12mo)
Commit activity

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
    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.
    5
    MIT
  • A
    license
    A
    quality
    C
    maintenance
    Provides Belgian railway travel information via the iRail API, including station search, live departures/arrivals, route planning, and network disturbances.
    5
    MIT

View all related MCP servers

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/DenisRaimondi/lombardia-trains-mcp'

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