rail-interop-mcp
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@rail-interop-mcp plan route Katowice to Ostrava for container train"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Rail Interop Planner
MCP-інтерфейс до реєстру інфраструктури ERA RINF (Польща, Чехія) плюс два шари, яких немає в наявних інструментах перевірки сумісності маршруту (зокрема в офіційному ERA Route Compatibility Check): погодне попередження і рекомендація, як саме змінити поїзд, щоб маршрут став прохідним. Два MCP-сервери: власний rail-interop-mcp (маршрут, сумісність поїзда, погодний ризик) і наявний OpenWeather MCP (прогноз в опорних пунктах маршруту), об'єднані агентом на LangGraph.
Індивідуальна лабораторна робота курсу KSE Agentic AI Summer School, тема «MCP Integration». Автор: Тихон Дукарев.
Python 3.12 · uv · MIT
Архітектура
Користувач (CLI) → Агент LangGraph → MCP-клієнт ─ streamable-http ─→ rail-interop-mcp (окремий процес, Python) → data/rinf.sqlite (ERA RINF, PL+CZ)
└─ stdio ───────────→ mcp-openweather (окремий процес, Go) → api.openweathermap.orgflowchart LR
U[Користувач CLI] --> A[Агент LangGraph]
A --> C[MCP-клієнт]
C -- streamable-http --> S1["rail-interop-mcp\nвласний сервер"]
C -- stdio --> S2["OpenWeather MCP\nнаявний сервер"]
S1 --> D[("data/rinf.sqlite\nERA RINF, PL+CZ")]
S2 --> W[("OpenWeather API")]Агент бачить дані лише через MCP: жодного прямого доступу до data/rinf.sqlite чи до OpenWeather API з коду агента. Власний сервер стартує першим у своєму терміналі (uv run rail-interop-mcp --transport streamable-http, 127.0.0.1:8765/mcp); агент підключається за адресою з RAIL_MCP_URL, і той самий процес видно в MCP Inspector незалежно від агента. Сервер stateless: інструменти приймають маршрутний запит або явний список section_ids, жодного сесійного стану чи побічних ефектів; граф і індекси завантажуються один раз при старті (близько 0,1 с на 7883 точки). Обидва процеси друкують кожен виклик інструмента: сервер у stderr, агент - у консоль (discovery обох серверів, аргументи й скорочений результат кожного виклику).
Related MCP server: MCP LangChain Weather Agent
Як це працює: чотири питання
Агент відповідає на практичне питання «чи проїде цей конкретний поїзд цим маршрутом», ставлячи кожній ділянці маршруту чотири перевірки проти реєстру RINF:
Чи збігається ширина колії? Колісні пари поїзда (1435 мм) проти колії кожної ділянки: розбіжність - жорстка заборона.
Чи витримає колія вагу? Навантаження на вісь поїзда проти межі ділянки (типово 20-22,5 т): перевищення руйнує колію.
Чи влізе поїзд за габаритом? Профіль GA/GB/GC поїзда проти просвіту ділянки (мости, тунелі).
Чи не задовгий поїзд? Довжина проти ліміту менеджера інфраструктури (PL 750 м / CZ 740 м) - м'яке попередження.
Параметри, яких реєстр не знає (наприклад, ETCS у польській частині заповнений лише на 4,4%), чесно позначаються unknown - це прогалина даних, а не дозвіл і не заборона. Поверх статичного реєстру агент кладе два динамічні шари: план тяги (які локомотиви і де їх міняти через зміну системи струму) і погодний ризик на день запиту (вітер для порожніх вагонів, спека, мороз проти температурного класу ділянок) - при перевищенні порога агент сам перебудовує маршрут.
Quick start
Передумови: uv, Python 3.12 (uv ставить сам), Go 1.24+ (для збірки OpenWeather MCP - brew install go або офіційний tarball), ключ OpenWeather (безкоштовний план, активація 10-60 хв) і ключ OpenRouter для LLM агента. Бінарник наявного сервера: go install github.com/mschneider82/mcp-openweather@e032683574a0723591445462ef7104d360ad0889 (закріплений коміт, його звіряє doctor).
uv sync
cp .env.example .env # заповнити OWM_API_KEY, OWM_MCP_BIN, OPENROUTER_API_KEY
# Перевірка середовища (toolchain, ключі, зовнішні сервіси, без секретів у виводі)
uv run --python 3.12 --no-project scripts/doctor.py
# Термінал 1: власний сервер, окремий процес
uv run rail-interop-mcp --transport streamable-http
# Термінал 2: агент
uv run rail-agent --scenario A
# Тести (235, без мережі й ключів)
uv run pytest
# Discovery незалежно від агента (Термінал 1 має бути запущений)
npx -y @modelcontextprotocol/inspector --cli http://127.0.0.1:8765/mcp --method tools/listДемо-сценарії
Кожен сценарій - готовий профіль поїзда (data/orders/*.yaml) плюс маршрут; звіт українською пишеться в out/. Точні визначення - rail_agent/scenarios.py.
Сценарій | Команда | Маршрут | Результат (реальний прогін) |
A |
| Katowice - Ostrava, контейнерний поїзд | 81,4 км, PL-CZ через EU00072, увесь шлях |
B |
| Katowice - Breclav, той самий поїзд | 265,4 км, перехід |
B2 |
| той самий маршрут, порожні платформи, знижений поріг вітру як демо штормового попередження IM | реальний прогноз вітру (3,9-8,0 м/с) перевищує знижений поріг 3,0 м/с → |
C |
| той самий маршрут, поїзд 25 т/вісь | спершу |
Failure demo
Реалістичний збій наявного сервера і контрольована деградація (docs/EXISTING_SERVER.md розділ 5), без падіння всього потоку:
Сценарій | Команда | Що відбувається |
D1 |
| шлях до бінарника OpenWeather MCP навмисно зламаний → з'єднання не встановлюється, discovery показує |
D2 |
| погода для Katowice підмінена на неіснуюче місто |
Джерело числа маршруту в будь-якому звіті можна простежити до сирого запису ERA:
uv run python scripts/trace_section.py c0fcd67d79Інструменти
Інструмент | Що робить | Тип | Контракт |
| знаходить операційні пункти PL/CZ за назвою (діакритика ігнорується) | пошук з обмеженим контрактом | |
| обчислює маршрут по інфраструктурному графу ERA RINF (Dijkstra) | обчислення, первинне джерело | |
| перевіряє поїзд проти маршруту (габарит, осьове навантаження, довжина, просвіт) | валідація | |
| перетворює прогноз на маршруті на структурований ризик і рекомендацію | оцінка ризику | |
| призначає локомотиви з парку ( | планування | |
| поточна погода і прогноз на 5 діб для міста | наявний зовнішній сервіс |
Усі 5 назв вище дослівно збігаються з tools/list живого сервера (перевірено через MCP Inspector і тестом tests/test_server_contract.py::test_tool_contracts_doc_names_match_tools_list).
Бонус: вебінтерфейс
Локальна вебапка поверх того самого агента, без жодних змін у rail_agent/ чи rail_mcp/: форма з фільтрами (країна -> станція з пошуком по всіх 7883 точках -> пресет поїзда) або запит вільним текстом, живий прогрес по вузлах графа через SSE (умовні кроки adjust/replan видно як вставні), карта Leaflet з маршрутом (розфарбовка за енергосистемою або за сумісністю), лінійна схема, картки сумісності/тяги/погоди і журнал викликів інструментів.
# Термінал 1: власний сервер (як у Quick start)
uv run rail-interop-mcp --transport streamable-http
# Термінал 2: вебсервер бонусного інтерфейсу
uv run rail-web
# Браузер: http://127.0.0.1:8080Це необов'язкове доповнення: основний спосіб роботи з проєктом - CLI вище. Фронтенд - vanilla JS + vendored Leaflet 1.9.4 (BSD-2), без node і кроку збірки; єдина зовнішня залежність у браузері - тайли OpenStreetMap (потрібен інтернет; перемикач «схема» працює і без них).
Структура репозиторію
rail_mcp/ власний MCP-сервер: схеми, доменна логіка, main.py
domain/ чисті функції без залежності від MCP (graph, search, rules, weather_rules, traction, errors)
build/ збірка датасету з ERA SPARQL у data/rinf.sqlite
rail_agent/ агент LangGraph: граф, вузли, конфіг обох MCP-з'єднань, CLI
rail_web/ бонус: вебінтерфейс (FastAPI + SSE, static/ з vendored Leaflet 1.9.4)
data/ датасет (rinf.sqlite), довідники з джерелами (включно з locomotives.yaml), README.md
scripts/ doctor.py, smoke_weather.py, gen_tool_contracts.py, trace_section.py
tests/ 235 тестів: домен, контракт сервера (реальний stdio-виклик), агент, веб, дані
docs/ TOOL_CONTRACTS, contracts_extra.yaml, EXISTING_SERVER, DESIGN_RATIONALE
out/ звіти агента (ігнорується git)Design rationale
Кожен із 5 власних інструментів на межі MCP тому, що дані й правила сумісності (пороги, класифікація габариту, погодні ризики) мають жити біля датасету, а не в промпті: модель отримує вже структурований вердикт, не сирі рядки RINF. Компроміси, обмеження і причина, чому OpenWeather - єдиний потрібний наявний сервер для цього потоку, розписані в docs/DESIGN_RATIONALE.md (разом з розділом про співвідношення з офіційним ERA Route Compatibility Check).
Дані й ліцензії
Реєстр інфраструктури ЄС (RINF), Європейське залізничне агентство, знімок Польщі й Чехії від 2026-08-18, ліцензія CC BY 4.0. Атрибуція («Data: European Union Agency for Railways, Register of Infrastructure (RINF), CC BY 4.0») додається до кожної відповіді власних інструментів і до звітів агента. Погодні дані - OpenWeather, атрибуція «Weather data provided by OpenWeather». Джерело, дата знімка, точні числа й команда відтворення (uv run build-dataset --from-raw) - data/README.md.
Обмеження
RINF - реєстр інфраструктури, не розклад руху:
find_routeдає фізичний профіль маршруту, не час у дорозі й не наявність вільних вікон.ETCS майже відсутній у польській частині знімка (4726 з 4946 секцій без запису) -
etcs_levelтам здебільшогоunknown, це властивість джерела, не помилка сервера.Довідники
load_categories.yaml,train_length_limits.yaml,weather_thresholds.yaml- вторинні джерела (EN 15528, Network Rail, RAIB), не офіційний реєстр ERA; кожен файл має посилання на джерело.plan_traction- жадібна евристика (тримає поточний локомотив, поки можливо), не доведений глобальний оптимум і не пошук по графу станів; фіксований демо-парк із двох локомотивів (data/locomotives.yaml); допуски локомотивів по країнах (габарит кузова, маса на вісь по типу локомотива) не моделюються.Погода: вітер відомий лише на день відправлення (наступні дні мають
wind_ms=null); опорний пункт зводиться до найближчого великого міста зі словника (rail_agent/city_names.py), не координат - задокументоване обмеження контракту наявного сервера.Об'їзд закритої довільної ділянки і багатоітераційний цикл перепланування свідомо не реалізовані (один прохід кожного); зроблено лише перепланування, тригероване погодним ризиком (сценарій B2).
Проєкт не намагається замінити офіційний ERA Route Compatibility Check - різниця й межі застосування розписані в
docs/DESIGN_RATIONALE.md(розділ про prior art).
Захист
Сценарій демонстрації на 12 хвилин буде в docs/DEMO_SCRIPT.md; коміт для захисту буде позначений тегом v1.0.0.
Ліцензія
Код - MIT, LICENSE. Дані ERA RINF - CC BY 4.0 (Європейське залізничне агентство). Погодні дані - OpenWeather. Дякую курсу KSE Agentic AI Summer School за завдання.
Available Tools
5 toolsassess_weather_riskA
Turn a weather forecast at points along a route into a structured risk assessment.
Call find_route first (for `route` or its section_ids) and the existing OpenWeather MCP
server's `weather` tool for forecasts at find_route's waypoints, before calling this.
Exactly one of `route` or `section_ids` is required, same as check_train_compatibility.
Inputs: input (required). Returns: factors, overall, attribution, replan_recommended, +2 more
check_train_compatibilityA
Check whether a train fits the infrastructure of a route (gauge, axle load, clearance, length).
Call find_route first and pass its route as `route`, or pass `section_ids` to check a specific
segment (e.g. after adjusting a route). Exactly one of the two is required.
Inputs: input (required). Returns: summary, verdict, violations, attribution, +1 more
find_routeA
Compute a route between two operational points over the ERA RINF infrastructure graph.
Call resolve_operational_point first to get valid op_id values. Call this before
check_train_compatibility or assess_weather_risk: both need the route this returns.
Inputs: input (required). Returns: route, attribution
plan_tractionA
Assign locomotives from a fleet to a route's runs, greedily minimising changes.
Call find_route first and pass its route as `route`, or pass `section_ids`, same as
check_train_compatibility. Give at least one locomotive via `fleet_ids` (ids from
data/locomotives.yaml) or `custom_locomotives`. A run with no locomotive able to cover
it (unknown/non-electrified energy system, or unmatched signalling) is uncovered, not
an error.
Inputs: input (required). Returns: uncovered, assignments, attribution, change_points
resolve_operational_pointA
Find operational points (stations, junctions, border points) by name in Poland or Czechia.
Call this first to turn a place name from the user into an op_id for find_route. Diacritics
are ignored. An empty candidate list is a valid answer (the place was not found), not an error.
Inputs: input (required). Returns: candidates, attribution
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 5 tools
Each tool targets a distinctly different aspect of the rail planning workflow: place resolution, route computation, infrastructure compatibility, weather risk, and traction planning. Their inputs and outputs are clearly separated, with no overlapping responsibilities or ambiguous boundaries.
All tool names follow a strict verb_noun pattern in snake_case: resolve_operational_point, find_route, check_train_compatibility, assess_weather_risk, plan_traction. The verbs are specific and the nouns clarify the object, making the naming entirely predictable.
With 5 tools, the server covers the core end-to-end rail interoperability workflow without redundancy. Each tool is necessary and contributes to a different step, so the count is well-calibrated for the stated purpose.
The tools form a complete lifecycle: resolve places to op_ids, find a route, validate train compatibility, assess weather risk, and plan traction. No obvious missing operations are apparent for the server's domain, and each tool's output feeds naturally into the next step.
Related MCP Connectors
The Ferryhopper MCP server is a connector for LLMs and AI Agents in maritime travel that exposes ferry routes, schedules, and booking options. It enables AI assistants to search ports and connections across 33 countries and 190+ ferry operators, provide real-time ferry itineraries with indicative prices, and assist users with planning island-hopping or multi-leg journeys by processing natural language queries about ferry times, passenger counts, and travel durations.
Furgonetka MCP Server is an extension for LLMs (such as Claude) that integrates AI assistants with Poland's most popular courier brokerage platform. The server enables models to interact directly with services from various couriers (including InPost, DPD, DHL, UPS, and Poczta Polska) through a single, unified interface. With this integration, your AI stops just "writing about logistics" and starts actually managing it.
Geocoding, routing, isochrones, traffic, weather, and place search for AI agents. 19 MCP tools.
Persistent memory, knowledge graph, task management and more for AI agents via MCP.
Related MCP Servers
- AlicenseAqualityDmaintenanceAn MCP server that exposes the Deutsche Bahn public transport API to any MCP-compatible client (Claude Desktop, Cursor, Cline, Continue, etc.). Five tools cover station search, departures, journey planning, trip details, and nearby stations.61MIT
- FlicenseNot gradedqualityDmaintenanceA weather MCP server that geocodes city names and fetches live weather from Open-Meteo, enabling a LangGraph agent to answer weather queries.-
- AlicenseAqualityDmaintenanceAn (unofficial) MCP server for the Deutsche Bahn Timetables API — station search, planned departures, and real-time changes (delays, platform changes, cancellations) as tools for Claude and other MCP clients.42MIT
- AlicenseAqualityDmaintenanceMCP server for Indian Railways data, enabling AI agents to search trains, get schedules, live status, PNR info, and more without an API key.1110 npmMIT