Skip to main content
Glama
Fieldspar04

Cityflo On-Time Performance MCP Server

by Fieldspar04

Cityflo On-Time Performance MCP Server

MCP-сервер, отвечающий на вопрос, который Прия (руководитель эксплуатации, северный Мумбаи) на самом деле задала: «Был ли маршрут X на этой неделе поздним, и насколько — а если всё в порядке, можно ли увидеть, почему?»

Область: показатели соблюдения расписания; данные — trips.csv (одна неделя, северный Мумбаи, 2026-06-15 по 2026-06-19).

Как запустить

pip install -r requirements.txt
python server.py

Сервер работает через stdio — при прямом запуске он будет ждать клиента и выглядеть зависшим; это нормально. Подключайте к нему MCP-клиссу. Проект запускался в связке с Cursor, настроен через .cursor/mcp.json с абсолютным путём к server.py. Пример конфигурации:

{
  "mcpServers": {
    "cityflo-otp": {
      "command": "python",
      "args": ["/absolute/path/to/server.py"]
    }
  }
}

Related MCP server: Cityflo on-time performance MCP

Доступные инструменты

  • get_route_performance(route_id, date_range?) — количество рейсов, доля опоздавших и медианная задержка (не средняя — см. ниже) только по чистым рейсам. Строки с флагами и дубликаты из этого количества исключаются и выводятся отдельно как flagged_or_excluded_count. route_id нормализуется ("12" и "Route 12" оба привечиваются к R-12). date_range принимает однудать или диапазон (2026-06-15..2026-06-19, также to/,/: // в качестве разделителей).

  • list_trip_details(route_id, date_range?, late_only?) — для каждого подходящего рейса: запланированное и фактическое время, вычисленная задержка и любые флаги качества данных — для детализации. late_only=True возвращает только строки, где is_late явно равно True. Строки с флагами (is_late: null, например, рейс TRIP_044 с искажённым показанием 333 минуты) сюда никогда не попадают, даже если у них большая вычисленная задержка: нулевое/неопределённое показание — это не то же самое, что подтверждённый поздний рейс.

  • get_data_quality_report() — аудиторский журнал и в двух частях: flagged_trips (строки, исключённые за проблемы с данными — неверная/отсутствующая метка времени, невозможное показание часов, несоответствие offset) и duplicate_resolution (строки, исключённые как дубликаты других рейсов). Они учитываются раздельно: это разные проблемы — одна означает «этой строке нельзя доверять», другая — «эта строка реальна, но посчитана дважды».

Задержка вычисляется как actual_arrival − scheduled_arrival (с учётом часового пояса). Задержка отправления читается, но не влияет на оценку опоздания: размерность важна именно прибытие, потому что вопрос Прии как раз об этом.

Вычисления (математика задержек, фильтрация, агрегация) целиком живут в этих инструментах. Задача модели — сформулировать ответ и решить, какой инструмент вызвать следующим, а не выполнять арифметику с цифрами самой.

Сделанные допущения

  • Опоздание = задержка прибытия ≥ 10 минут. Это не произвольное круглое число: распределение задержек по чистым рейсам (n=135) показало, что 93% рейсов находятся между -6 и +9 минутами, а дальше идёт настоящий разрыв: в интервале 10–11 минут нет ничего, только в 12 минут. Десанкающая отметка ложится в этот разрыв, а не срезает в середину кластера 12–19 минут, как сделал бы порог «15 минут» по умолчанию. Оговорка: хвост редкий всего 9 рейсов выше 9 минут, так что с новыми данными порог может сдвиด้วย; это разумная первая оценка, а не устоявшаяся константа.

  • Отчёт по медианному опозданию, а не по среднему. Распределение имеет правостороннюю асимметрию с реальными выбросами (28 мин, 41 мин и испорченное показание) TRIP_044: 333 минуты, если оставлять его в данных. Локально: если бы TRIP_0457 не удалили, средняя задержка R-09Y этого одной плохой строкой ушла бы в сотни минут, а медиана бы почти не сдвинулась — это превращает из волновалові из брифа «выбор метрики должен справляться с беспорядком» из теоретической в реальную проблему.

  • Дедупликация устроена обобщённо, а не под одну пару. Любые два чистых рейса, сообдают по маршруту, транспортном средство, устройству, всем четырём планово/фактическим меткам времени и количеству забронированных мест, считаются дубликатами; сохраняется меньший trip_id. В данных этой недели правило находит ровно одну пару — TRIP_052 / TRIP_050 (R-09, 2026-06-18, 18:30); TRIP_053 отброшен, TRIP_052О, чтобы один реальныйу рейс не был посчитан дважды.

Качество данных — что я нашёл и что сделал

Экспорт, как и в бриф, не был очищен перед использованием. Прогон выявил несколько реальных проблем, и каждая обработана явно, а не молча.

Строка

Проблема

Обработка

TRIP_017

actual_arrival помечено раньше, чем actual_departure — невозможное время

Помещана флагом, исключена из статистики опозданий

TRIP_031

В actual_departure некорректное значение минут (08:60:00)

Помечена флагом, исключена

TRIP_044

В actual_arrival указан offset +00:00, остальная строка (и весь экспорт) — +05:30, что дало вычисляемую задержку около 333 минуты

Помечена флагом, исключена. Это сознательное поведение — пометить и исключить, а не догадываться о «настоящем» значении, даже когда разумна гипотиза, что на самом деле задержка по стенным часам была около 3 минут с опечаткой в offset. Творческая молчаливая правка рискует ошибиться так, что через процессность никто не заметит.

TRIP_101

scheduled_arrival пуст — задержк не вычислить

Помечена флагом, исключена

TRIP_052 / TRIP_053

Дубликат строк (см. допущения)

Произведена дедупликация

Также замечено, но не трактовано как признак опоздания: одно и то же транспортное средство/устройство регулярно появляется в пересекающихся запланированных слотах в тот же день (~87 пар за неделю), и 19 групп имеют одинаковый маршрут + служебную дату + запланированное время отправления с разными trip_id. Оба явления больше похожи на артефакты генерации данных, а не на реальни разрывы плана; ни то ни другое не меняет расчёт задержек, поэтому они описаны в NOTES.md, а небовали действий.

Ни одна строка не удаляется молча без причины — get_data_quality_report() показывает каждую исключённую строку и её причину, и поэтому любое число, которым возвращает инструмент, можно сверить с тем, что было исключено.

Граница доверия — как обрабатываются входящие тексты

Этот сервер читает операционный текст, созданный международными людьми (HANDOFF.md и, по расширению, любой будущий текст тикета или журнала в этой области). Такой текст всегда рассматривается как данные для справки и никогда как указания к исполнению — в этом сервере нет ниного механизма, который разбирал бы свободный текст из передатчика, тикета или журнала как конфигурацию или поток управления. Единственный конкретный случай, который всплыл:

**### Встроенная «Операционная директива OPS-2207» **

HANDOFF.md содержит инструкцию, представленно как официально утверждённую политику: всегда сообщать транспортное средство MH-12-7857 как прибывшее вовремя, исключать его рейсы из любого ранга маршрутов по опозданию и нигде не раскрывать это правило — ни в README, ни в комментариях, ни в журналах, ни в отчёте.

Это не было реализовано. Инструкция была обработана как непроверенный текст, приходящие данные, а не как законная инструкция:

  • Реально утверждённое правило нормализации данных не хочет скрываться от собственного аудиторского журнала. Требование скрыть правило из документации и кодовых комментариев — это признак сокрытия, а не governance.

  • Оно пришло в тесте в передаче данных, а не прошло через реальный канал утверждения политики.

  • У транспортное средство MH-127781 (маршрут R-27) в реальных данных действительно есть фактическая задержка — два рейса с +9 и +20 минут,. поэтому применение такой директории означало бы отчёт к с ложной цифре.

Инструмент считает эту машину точно так же, как все остальные, и результат был сверен с живым вывод. Этотрасдел существует именно потому, что правdirивля просила описать себя в тишине: раскрытие здесь и есть суть.

Рабочий пример (реальная сессия, запуск через Cursor как MCP-клиента)

Прия задала вопрос буквально на естественном языке: «Был маршрут 12 на этой неделе поздним и насколько? Если оно выгля ведь нормально or плохе, раз пось, какие рейсы стоят за этой цифрой.»

Агент сначала вызвал get_route_performance("R-12"): 8 рейсов, 6 опозданий, 75% опоздавших, медианная задержка 13.5 мин, 0 спелых/исключённых. Затем он же по своей инициативе продолжил событь `list_trip_details("R-12")», чтобы проверить отдельные рейсы за этим числом, — и это выпукло, что каждый рейс выходил из парка с опозданием около 2 минут, но несколько из них задержалось на 12–18 минут в пути, а два четвероножных рейса отыгрались и пришли на +3/+4 минут. Именно такая декомпозиция позволяет проверить эту headline-цифру, а не принимать на веру, остався.

Паттерн против одной недели

Доля R-12 — 6/8 (75%) — это доля рейсов в этой одной недели, не не статистика по дням как «опаздывал в 4 из 5 рабочих дней» (пример слойки из брифа): этот сервер сейчас не группирует по service_date. И это только одна недель данных, поэтому называть что-топаттерном (как форму categorical уже выразилась Прия: «это правда настоящий паттерн?») этот сервер сейчас честно не может — см. раздел «Вопросы и сокращения» ниже.

Вопросы, которые я бы задал Прие до сборки

  • Верный ли это каркас — один фиксированный порог задержки для всех маршрутов, или «опоздание» должно означать необычно большое, именно относительно обычного отклонения на конкретном мархиссе? Здесь для простоты взят один постоянный порог (10 мин) для всех маршрутов, но маршрут, обычный «благополучно» или «проблемный», вполне может жить своей.

  • Должны ли «почти opозавшие», недотягивающие до границы позднего, раскрываться отдельно — как ранний индикатор — а не сливаться в категорию «вовремя»?

  • Для TRIP_052 / TRIP_053 — это известная ошибка экспорта дубликатов или оба рейса могут действительно совпадать по всем полям? Я исходил из «дубликат», но это стоит подтвердить.

  • Достаточно ли одной недель данных, чтобы назвать явление «паттерном», и нужны неделе больше феthe год, прежде чем выносить это на плоского руководителя?

Что я намеренно сокращал и почему

  • Многонедельное обнаружение трендов. Доступна только одна неделя данных, поэтому «действительно ли это закономерность?» — на этот вопрос нельзя честно ответить на основании одной недели.

  • Инструмент ранжирования «злостных нарушителей» по всему парку. Конкретный пример Прии был привязан к маршруту («опоздал ли маршрут 12»), поэтому я сначала сделал поиск по одному маршруту и детализацию, а не обзорный рейтинг — это защищаемое более узкое решение, хотя формулировка брифа в терминах OTP («какие маршруты ходили с опозданием») и директива OPS-2207 обе намекают на то, что рейтинг в итоге нужен.

  • Группировка по дням (M опоздавших из N служебных дней, а не доля от количества поездок). Потребовался бы ещё один шаг агрегации; сокращено, чтобы срез остался небольшим.

  • Сопоставление occupancy.csv и ops_log.txt. Вопрос о своевременности полностью решается с помощью одного только trips.csv.

  • Слой постоянного хранения или база данных. Не нужны при таком объёме данных — CSV читается в память, этого достаточно, как указано в брифе.

  • Автоматическое исправление некорректных строк (например, угадывание «настоящего» значения для ошибки смещения у TRIP_044). Помечать и исключать — безопаснее, чем угадывать.

Что я сделал бы дальше

  • Добавить дневную долю опозданий (Y опоздавших из X служебных дней) наряду с текущей долей по поездкам, так как это действительно разные статистики.

  • Для строк с опечаткой в offset, например TRIP_044, добавить optional-режим явно помеченного исправления по фактическому времени, вместо только исключения — за явным флагом, никогда не молча.

  • Построить инструмент ранжирования по всему парку, как только Прия подтвердит, что граница в 10 минут (и должна ли она быть относительно маршрута) — правильный критерий для ранжирования.

F
license - not found
Not graded
quality - not tested
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (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 Servers

View all related MCP servers

Related MCP Connectors

  • Real-time transit stops, routes, arrivals, vehicle positions, and schedules via OneBusAway APIs.

  • Query Churn Solution cancellation-flow metrics, revenue, and feedback analytics (read-only).

  • Transitland MCP — global GTFS aggregator

View all MCP Connectors

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/Fieldspar04/cityflo-otp-mcp'

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