Skip to main content
Glama
zavorateam

Moscow Transport MCP

by zavorateam

moscow-transport-mcp

Python FastAPI Model Context Protocol Tests Integration Tests

Moscow Transport MCP — интеллектуальный гибридный шлюз для AI-агентов (MCP) и микросервисов (REST), агрегирующий данные пассажирского транспорта Москвы и Московской области в реальном времени.

Шлюз непрерывно склеивает данные из трёх независимых систем, устраняет расхождения, выбирает нужные павильоны при многостороннем движении и предоставляет агентам детерминированные инструменты для планирования поездок, мониторинга автопарка и информирования пассажиров.


🧭 Архитектура и источники данных

                     ┌────────────────────────────────────────────────────────┐
                     │            AI-АГЕНТ (Claude / Cursor / LLM)            │
                     └───────────────────────────┬────────────────────────────┘
                                                 │ (MCP / REST)
                                                 ▼
┌──────────────────────────────────────────────────────────────────────────────────────────────┐
│                                   Moscow Transport MCP                                       │
│                                                                                              │
│   ┌───────────────────────────┬───────────────────────────┬──────────────────────────────┐   │
│   │   1. Discovery & Search   │   2. Fleet & Amenities    │   3. Fusion & Dispatch       │   │
│   │   (Поиск остановок, BBox, │   (GPS, скорость, кондей, │   (Сверка табло, расчет ETA, │   │
│   │    умный выбор платформы) │    низкий пол, госномер)  │    live vs static график)    │   │
│   └─────────────┬─────────────┴─────────────┬─────────────┴──────────────┬───────────────┘   │
└─────────────────┼───────────────────────────┼────────────────────────────┼───────────────────┘
                  │                           │                            │
                  ▼                           ▼                            ▼
        ┌────────────────────┐       ┌───────────────────┐        ┌───────────────────┐
        │Московский транспорт│       │  РНИС Мособласть  │        │  Яндекс.Транспорт │
        │ (ГУП Мосгортранс)  │       │  (Балашиха и МО)  │        │                   │
        └────────────────────┘       └───────────────────┘        └───────────────────┘
  1. Московский транспорт (ГУП «Мосгортранс» / data.mos.ru):

    • Локальный реестр bus_stops_all.geojson (12 500+ остановок Москвы с распаковкой properties.attributes).

    • Официальный API stop_v2 и qr-stop (секундные прогнозы прибытия по датчикам телеметрии).

  2. РНИС Московской области (Минтранс МО):

    • Прямой доступ к телеметрии бортов (3 500+ онлайн-автобусов в реальном времени).

    • Поиск остановок по географическому BoundingBox (stop_point.list).

    • Официальные табло остановок МО (stop_point.routes) с оставшимися остановками и ETA.

    • Паспортные характеристики бортов: наличие кондиционера, низкий пол/пандус, электронные табло, валидаторы.

  3. Яндекс.Транспорт (Masstransit API):

    • Живой трекинг физических бортов, расчет курса (азимута), скорости и координат.

    • Независимый геокодинг и топология маршрутов.


Related MCP server: MBTA MCP Server

⚡ Ключевые возможности

  • Интроспекция для LLM (get_filter_options): Агент может заранее запросить реестр перевозчиков, марок ТС и доступных опций, исключая галлюцинации в фильтрах.

  • Умный выбор павильона (Platform Disambiguation): Если у остановки несколько платформ в разные стороны (например, «Метромост» в центр и от центра), шлюз автоматически выберет павильон, через который проходит запрошенный маршрут.

  • Бесшовное объединение Москвы и Подмосковья: Если остановки нет в московском GeoJSON, шлюз на лету находит её в РНИС МО (по UUID или BBox).

  • Сверка прогнозов (Reconciliation): Сравнение официального времени прибытия оператора с фактическим положением борта на карте с приоритизацией достоверного источника.

  • Non-destructive Data Policy: Никакие данные не отбрасываются. Если у борта отсутствует госномер или статус кондиционера, возвращается null, а живые координаты и скорость сохраняются.


🛠️ Набор инструментов агента (Tooling / API)

Инструмент

REST Эндпоинт

Назначение

get_filter_options

GET /filter-options

Автокомплит и списки доступных перевозчиков, марок, удобств.

search_stops

POST /stops, GET /stops

Поиск остановок по названию, маршруту, координатам, BBox, павильону.

get_stop_board

POST /schedule, GET /schedule

Живое табло остановки (все прибывающие рейсы, прогноз, is_realtime).

get_bus_eta

POST /eta, GET /eta

Точечный ETA конкретного автобуса со сверкой источников.

search_online_buses

POST /buses, GET /buses

Поиск бортов на карте (GPS, скорость, кондей, низкий пол, радиус).

get_route_details

GET /routes/{route}

Трасса маршрута: цепочка остановок и активные автобусы на нитке.

get_vehicle_card

GET /vehicle

Досье на конкретный борт по госномеру или UUID.

get_system_status

GET /count

Мониторинг онлайна телеметрии и загруженных справочников.


Быстрый старт

1. Клонирование и установка зависимостей

git clone <repo-url>
cd transport-mcp

python3 -m venv .venv
source .venv/bin/activate

pip install -r requirements.txt

Требования к окружению: Python 3.10+, fastapi, uvicorn, httpx, pydantic, pytest, pytest-asyncio, mcp (опционально для MCP-сервера).

2. Конфигурация окружения (.env)

Создайте файл .env в корне проекта (или скопируйте .env.example):

# Сервер
HOST=0.0.0.0
PORT=8000
LOG_LEVEL=DEBUG

# Путь к московскому реестру остановок
STOPS_GEOJSON_PATH=bus_stops_all.geojson

# РНИС МО (Московская область)
RNIS_BASE_URL=https://portal.rnis.mosreg.ru/busajax/request
RNIS_CACHE_TTL_SECONDS=900
RNIS_REQUEST_INTERVAL=0.5

# Московский транспорт
MOSCOW_STOP_V2_URL=https://api.moscowapp.mos.ru/v8.2/stop_v2
MOSCOW_QR_STOP_URL=https://api.moscowapp.mos.ru/v8.2/qr-stop

# Яндекс.Транспорт (опционально)
YANDEX_CSRF_TOKEN=6c4fbb2d14d555fb31c4d420225cb2120dc8fa4f:1789035145
YANDEX_SESSION_ID=1789035145230215-15377882495539827877-balancer-l7leveler-kubr-yp-klg-220-BAL
YANDEX_S_VEHICLES=1226992667
YANDEX_S_STOPS=3155859244
YANDEX_COOKIE=

# Параметры алгоритмов оркестратора
DEFAULT_LAT=55.2518
DEFAULT_LON=37.7173
DEFAULT_SEARCH_RADIUS_KM=6.0
DEFAULT_AVERAGE_SPEED_KMH=18.0
RECONCILIATION_THRESHOLD_SECONDS=180

3. Запуск сервера

Вариант А: REST API (для тестирования через curl / веб)

python server.py --http

Документация Swagger/OpenAPI доступна по адресу: http://localhost:8000/docs

Вариант Б: MCP-сервер (режим stdio для AI-агентов)

python server.py

🤖 Подключение к AI-агентам (MCP Setup)

Claude Desktop

Добавьте блок в файл конфигурации claude_desktop_config.json:

{
  "mcpServers": {
    "transit-agent": {
      "command": "/путь/к/проекту/.venv/bin/python",
      "args": ["/путь/к/проекту/server.py"],
      "env": {
        "PYTHONPATH": "/путь/к/проекту"
      }
    }
  }
}

Cursor / Windsurf

В настройках FeaturesMCP Servers добавьте сервер:

  • Type: command

  • Command: python server.py (с указанием виртуального окружения).


Примеры запросов (curl)

1. Интроспекция фильтров

# Получить список перевозчиков, содержащих слово "авто"
curl -s -G 'http://localhost:8000/filter-options' \
  --data-urlencode 'category=carriers' \
  --data-urlencode 'query=авто' | jq .

2. Поиск остановок

# Москва: найти павильоны «Метромост»
curl -s -X POST 'http://localhost:8000/stops' \
  -H 'Content-Type: application/json' \
  -d '{"query": "Метромост"}' | jq .

# Область: радиусный поиск остановок в МО через РНИС BBox
curl -s -X POST 'http://localhost:8000/stops' \
  -H 'Content-Type: application/json' \
  -d '{"lat": 55.7971, "lon": 37.9398, "radius_km": 2.0}' | jq .

3. Табло остановки

# Живое табло остановки «пл. Славы» в Балашихе
curl -s 'http://localhost:8000/schedule?stop_id=a6466a64-eb47-11e7-90c9-136fdbe30654' | jq .

4. Точный ETA автобуса

# Запрос ETA для маршрута 22к в Балашихе с привязкой ближайшего борта
curl -s -X POST 'http://localhost:8000/eta' \
  -H 'Content-Type: application/json' \
  -d '{"route": "22к", "stop_id": "a6466a64-eb47-11e7-90c9-136fdbe30654"}' | jq .

# Запрос по маршруту 49 на Верхних котлах
curl -s -X POST 'http://localhost:8000/eta' \
  -H 'Content-Type: application/json' \
  -d '{"route": "49", "stop_name": "Верхние котлы"}' | jq .

5. Поиск активных автобусов на карте

# Показать только автобусы с кондиционером на маршруте 110
curl -s 'http://localhost:8000/buses?route=110&air_conditioned_only=true' | jq .

# Поиск бортов в радиусе 5 км с автоматической сортировкой по возрастанию расстояния
curl -s 'http://localhost:8000/buses?lat=55.7971&lon=37.9398&radius_km=5&limit=5' | jq .

6. Досье конкретного автобуса

curl -s -G 'http://localhost:8000/vehicle' \
  --data-urlencode 'state_number=у342ат790' | jq .

🧪 Тестирование

Unit-тестирование (pytest)

Проект покрыт подробными тестами, проверяющими логику геометрии, rate-лимитеры, нормализацию идентификаторов и сверку расписаний:

pytest -s

Конфигурация pytest.ini:

[pytest]
asyncio_mode = auto
log_cli = true
log_cli_level = DEBUG
log_cli_format = %(asctime)s [%(levelname)-8s] %(name)s: %(message)s
log_cli_date_format = %H:%M:%S
addopts = -ra -q
pythonpath = .

Сквозное тестирование агента (agent_test.py)

Для проверки работоспособности на живой боевой телеметрии разработан скрипт agent_test.py, который просто имитирует REST запросы на одинаковых случайновыбранных данных:

# Запуск сквозного прогона (36 сценариев)
python agent_test.py

# Подробный вывод каждого запроса и тела ответов
python agent_test.py -v

# Экспорт всех curl-команд в исполняемый bash-скрипт run_curls.sh
python agent_test.py --dump-sh

📂 Структура репозитория

├── config.py                      # Типизированная конфигурация на Pydantic Settings
├── bus_stops_all.geojson          # Реестр остановочных пунктов Москвы (data.mos.ru)
├── stops_repository.py            # Поисковый индекс остановок (Spatial, ID, StationName)
├── transport_service.py           # Оркестратор и бизнес-логика инструментов агента
├── server.py                      # Точка входа: FastAPI + MCP сервер
├── agent_test.py                  # Автоматизированный E2E-сьют проверки curl-сценариев
├── pytest.ini                     # Конфигурация запуска тестов
├── requirements.txt               # Зависимости проекта
├── clients/                       # Изолированные клиенты внешних транспортных API
│   ├── __init__.py
│   ├── moscow_transport_client.py # Клиент stop_v2 и qr-stop Московского транспорта
│   ├── rnis_client.py             # Клиент РНИС МО (каталог, GPS, stop_point.list/routes)
│   └── yandex_client.py           # Клиент Яндекс.Карт (Masstransit API)
└── tests/                         # Набор модульных тестов
    ├── test_moscow_transport_client.py
    ├── test_rnis_client.py
    ├── test_stops_repository.py
    ├── test_transport_service.py
    └── test_yandex_client.py

Лицензия

MIT License. Свободно для использования, модификации и интеграции в AI-агентов.


Перспективы

  • Сделать нормальный transport_service.py, так как текущая реализация неэффективно работает со всеми тремя источниками

Related MCP Connectors

Related MCP Servers