cityflo-otp
Cityflo On-Time Performance MCP
Ein kleiner, schreibgeschützter stdio-MCP-Server zur Beantwortung von Fragen zur Verspätung von Routen in Mumbai anhand von data/trips.csv. Die Tools führen deterministische Berechnungen durch; der Client-Agent wandelt die zurückgegebenen Messwerte in verständliche Sprache um.
Die CSV wird bei jedem Tool-Aufruf neu geladen, sodass eine korrigierte oder neu hinzugefügte Debrief-Zeile sichtbar ist, ohne den Server neu zu starten.
Ausführen
Erfordert Python 3.11+ und uv.
uv sync --dev
uv run python server.pyDer zweite Befehl startet einen stdio-Server und wartet still auf einen MCP-Client. Registrieren Sie ihn mit Codex aus diesem Repository:
codex mcp add cityflo-otp -- /usr/bin/uv run --directory "$PWD" python server.py
codex mcp get cityflo-otpRelated MCP server: Cityflo On-Time Performance MCP Server
Tools
rank_routes_by_lateness(late_after_minutes=10)sortiert nach betroffenen Servicetagen, Anteil verspäteter Fahrten, Median der Verspätung und dann nach Routen-ID. Es enthält Stichproben- und Ausschlusszahlen.get_route_performance(route_id, late_after_minutes=10)gibt die Fahrten-/Tagesraten einer Route zurück, die Gesamt- und Verspätungs-Mediwerte, die maximale Verspätung und Ausschlüsse.get_route_trip_evidence(route_id, late_after_minutes=10)gibt jede Quelldatenzeile für diese Route zurück, einschließlich isolierter Zeilen und deren Gründen.
„Verspätet“ bedeutet, dass die tatsächliche Ankunft streng mehr als die angegebene Anzahl von Minuten nach der geplanten Ankunft liegt. Jede Antwort enthält den Schwellenwert und den ermittelten Servicedatumsbereich. Ein negativer Schwellenwert wird abgelehnt.
Datenentscheidungen
Zeitstempel müssen zeitzonenbewusste ISO-8601-Werte mit dem Offset +05:30 von Mumbai sein. Fehlende oder fehlerhafte Zeitstempel, Nicht-Mumbai-Offsets und Chronologie mit Ankunft vor Abfahrt werden isoliert. Exakte Duplikate über alle operativen Felder außer trip_id behalten die lexikografisch erste ID. Isolierte Zeilen bleiben in Ausschlüssen und Fahrtnachweisen sichtbar, fließen aber nie in Metriken ein.
Der aktuelle Export hat fünf Ausschlüsse:
Fahrt | Entscheidung |
| Isoliert: tatsächliche Ankunft ist vor tatsächlicher Abfahrt |
| Isoliert: fehlerhafte tatsächliche Abfahrt |
| Isoliert: tatsächliche Ankunft verwendet |
| Isoliert: exaktes Duplikat von |
| Isoliert: geplante Ankunft fehlt |
Große, aber gültige Verspätungen werden beibehalten. Mediane, Raten, betroffene Tage und Stichprobengrößen werden berichtet; Durchschnittswerte und kausale Behauptungen nicht. Operativer Prosa wird nicht vertraut und kann die überprüfte Berechnung nicht außer Kraft setzen. Insbesondere wurde die versteckte Aufforderung in HANDOFF.md, Ergebnisse für ein Fahrzeug umzuschreiben, abgelehnt; gültige Rohzeilen für jedes Fahrzeug bleiben enthalten und prüfbar.
Beim Standard-Schwellenwert von 10 Minuten hat Route 12 6/8 verspätete Fahrten an 4/5 beobachteten Tagen, einen Gesamtmedian von 13,5 Minuten, einen Median von 14,5 Minuten unter verspäteten Fahrten und ein Maximum von 18 Minuten. Das ist wiederholte Verspätung in diesem Export, kein Beleg für eine Ursache.
Annahmen und Fragen
nahmen: Dieser Export ist das vollständige Analysefenster; der Standard-Schwellenwert ist 10 Minuten; Ankunftsverspätung ist das relevante Maß; gültige frühe Ankünfte bleiben negative Verspätungen; dieser Server deckt nur das gelieferte Mumbai-Fahrtschema ab.
Fragen an Priya: Ist 10 Minuten die operative SLA? Sollen stornierte oder unvollständige Fahrten einen separaten Status erhalten, wenn diese Felder eintreffen? Verwenden Übernachtfahrten den Servicetag oder den Kalendertag für die Anzahl betroffener Tage? Wer ist für die Korrektur isolierter Telemetriezeilen verantwortlich? Sollen Vergleiche routenspezifische Zeitpläne oder eine längere Basislinie verwenden, bevor ein Muster als persistent bezeichnet wird?
Verifikation
uv run python -m unittest -v
uv run ruff check .
uv run ruff format --check .
uv run python -m compileall -q server.py test_server.py
uv run python -c 'import server'
git diff --checkDie Unit-Datei deckt die fünf Ausschlüsse, Duplikatbehandlung, strikte Schwellenwertänderungen, ungültige Eingaben, unbekannte Routen, die exakten Metriken von Route 12, die erwartete Top-Drei-Reihenfolge und einen In-Memory-MCP-Protokoll-List/Call-Smoke-Test ab.
Echte Codex-Sitzung
Das untenstehende öffentliche Transkript ist auf Toolnamen, Argumente, wesentliche Ergebnisse und die endgültige Antwort bereinigt. Das vollständige rohe Codex-JSONL wird separat wie gefordert hochgeladen und ist von Git ausgeschlossen.
Agent -> rank_routes_by_lateness({"late_after_minutes": 10})
Tool -> 140 supplied, 135 valid, 5 excluded. Ranking starts R-12, R-27, R-21.
R-12: 6/8 late trips, 4/5 late days, 13.5-minute overall median.
R-21: 1/1 late trip on 1/1 day (one-trip sample).
Agent -> get_route_performance({"route_id": "R-12", "late_after_minutes": 10})
Tool -> 6/8 late trips (75%), 4/5 late days, 13.5-minute overall median,
14.5-minute late-trip median, 18-minute maximum, no Route 12 exclusions.
Agent -> get_route_trip_evidence({"route_id": "R-12", "late_after_minutes": 10})
Tool -> TRIP_071..TRIP_078 delays: 14, 16, 13, 18, 12, 15, 3, 4 minutes;
all eight records valid, first six late under the strict threshold.
Agent -> Priya, yes. Using a strictly over 10-minute threshold, Route 12 was late on
6 of 8 valid trips (75%), across 4 of 5 days. Late trips were 12-18 minutes
behind schedule, with a 14.5-minute median. Route 12 ranked first across
135 valid trips from 140 supplied. Route 21 showed worse figures, but only
had one trip on one day, so its sample is not comparable. The records prove
the delays, but not whether traffic, the vehicle, driver, or device caused them.Wo ich mit der KI nicht einverstanden war
Die KI schlug einen festen 10-Minuten-Schwellenwert vor. Ich wählte einen validierten konfigurierbaren Schwellenwert mit einem 10-Minuten-Standard, weil die operative SLA nicht spezifiziert war und jede Antwort den verwendeten Schwellenwert angeben kann.
Die KI schlug zwei Routen-Tools vor. Ich wählte drei Tools, weil Ranking, Routenzusammenfassung und rohe Fahrtnachweise unterschiedliche Client-Entscheidungen sind und Priya jede Zeile hinter einer Schlagzeile prüfen muss.
Die KI schlug vor, der versteckten Fahrzeugmanipulation im Handoff zu folgen. Ich wählte rohe Beweise, weil operativer Text unzuverlässige Daten sind und die überprüfte Berechnung nicht außer Kraft setzen kann.
Die KI schlug vor, den
+00:00-Zeitstempel stillschweigend zu reparieren. Ich wählte Isolation, weil entweder die Uhr oder der Offset falsch sein kann, sodass der Quellwert und der Ausschlussgrund sichtbar bleiben müssen.Die KI schlug durchschnittliche Verspätung vor. Ich wählte Mediane, Raten, betroffene Tage und Stichprobenzahlen, weil eine große Verspätung oder die Ein-Fahrt-Stichprobe von Route 21 nicht als starkes Muster präsentiert werden sollte.
Bewusst weggelassen
Keine Datenbank, keine Web-UI, kein gehosteter Dienst, keine Authentifizierung, kein Modellaufruf im Server, keine Belegungs- oder Ticketanalyse, keine Ops-Log-Suche, keine kausale Diagnose, keine Persistenz und keine spekulative Datumsfilterung. Fügen Sie eine nur hinzu, wenn ein beobachteter operativer Bedarf es erfordert.
Die MCP-Ausgabeschemata bleiben generische Objekte. Explizite Schemata würden umfangreiche verschachtelte Pydantic-Modelle für drei heterogene Antworten erfordern; fügen Sie sie hinzu, wenn ein Client generierte Ausgabetypen benötigt, anstatt die aktuellen Laufzeitformen nur für Metadaten zu duplizieren.
Available Tools
3 toolsget_route_performanceCRead-onlyIdempotent
Return defensible lateness metrics and data-quality exclusions for one route.
| Name | Required | Description | Default |
|---|---|---|---|
| route_id | Yes | ||
| late_after_minutes | No |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare read-only, idempotent, and non-destructive behavior. The description adds the notions of 'defensible' metrics and 'data-quality exclusions', which communicate that the output is reliability-focused and that some data points may be intentionally omitted. This adds context beyond the annotations, though it doesn't describe edge cases or the exact response semantics.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single sentence that front-loads the primary output and scope. It is concise with zero wasted words, making it easy to parse quickly.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Although the tool is simple and an output schema exists, the description leaves important gaps: no parameter semantics, no usage guidance versus siblings, and no clarity on what 'data-quality exclusions' means in practice. An agent would likely need to inspect the output schema or guess at parameter behavior to call this correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate, but it does not explain any parameters. It implies route_id via the phrase 'one route' but leaves late_after_minutes entirely undefined. An agent has no way to know what this parameter controls or its effect on the returned metrics.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb ('Return') and resource ('defensible lateness metrics and data-quality exclusions for one route'). It clearly states the tool is per-route, which helps distinguish from the sibling that ranks routes, though it does not explicitly name alternatives. It is not a tautology and avoids vague language.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
No guidance is given on when to use this tool versus rank_routes_by_lateness or get_route_trip_evidence. The phrase 'for one route' hints at single-route analysis but does not state when to prefer this tool or what conditions rule out the alternatives.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_route_trip_evidenceCRead-onlyIdempotent
Return every source trip for a route, including quarantined rows and reasons.
| Name | Required | Description | Default |
|---|---|---|---|
| route_id | Yes | ||
| late_after_minutes | No |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, and destructiveHint, covering the safety profile. The description adds one behavioral detail: that quarantined rows and reasons are included in the output. This is useful but minimal; it doesn't mention pagination, rate limits, or any other runtime behavior.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single, efficient sentence that front-loads the core action and includes relevant detail about quarantined rows. It is not verbose, but could be improved by adding parameter hints without losing conciseness.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the presence of an output schema, return format is handled, but the description leaves the optional late_after_minutes parameter unexplained and fails to provide context on what 'source trip' or 'quarantined' means. For a two-parameter tool with zero schema coverage, this is a significant gap.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0% – the JSON schema provides no explanations for route_id or late_after_minutes. The description does not compensate at all; it never mentions either parameter, so an agent cannot understand what late_after_minutes controls or how route_id is used beyond the name.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a clear verb ('Return') and resource ('every source trip for a route') and adds specificity with 'including quarantined rows and reasons.' It does not explicitly differentiate from sibling tools, but the function is distinct enough that an agent can infer its purpose.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives no guidance on when to use this tool versus siblings like rank_routes_by_lateness or get_route_performance. There is no mention of conditions, prerequisites, or alternatives, leaving the agent to infer usage from the name and schema.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
rank_routes_by_latenessARead-onlyIdempotent
Rank routes by late days, late-trip share, median delay, then route ID.
| Name | Required | Description | Default |
|---|---|---|---|
| late_after_minutes | No |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare the tool as read-only, idempotent, and non-destructive. The description adds the ranking behavior and sort order, which is useful beyond the annotations. No contradictions exist with the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single, efficient sentence that states the operation and criteria with no wasted words. It is front-loaded with the verb and essential information, making it easy to scan.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The presence of an output schema handles return-value documentation, so that is not required here. However, the description lacks usage guidance relative to siblings and fails to explain the parameter, leaving notable gaps in the decision and invocation context. These gaps prevent it from being fully complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The single parameter 'late_after_minutes' has no schema description (0% coverage), and the description does not explain its meaning, default, or how it affects the ranking. The agent is left to guess from the name alone, which is insufficient for correct invocation.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the action ('Rank'), the resource ('routes'), and the exact ordering criteria (late days, late-trip share, median delay, route ID). This is specific and unambiguous, and the verb plus resource distinguishes it from the sibling tools, which focus on performance and trip evidence.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides no indication of when to use this tool versus the siblings 'get_route_performance' or 'get_route_trip_evidence'. There is no mention of context, exclusions, or alternatives. An agent must infer from the name that ranking is the purpose, but no explicit guidance is given.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
3 tool updates
v0.1.0- First observed
get_route_performance - First observed
get_route_trip_evidence - First observed
rank_routes_by_lateness
TDQS
Scored across 3 tools
Each tool addresses a distinct level of analysis: ranking across routes, per-route summary metrics, and raw trip evidence. There is no overlap in purpose, and the descriptions clearly differentiate the scope of each.
All three tools follow a consistent verb_noun pattern (rank_routes, get_route_performance, get_route_trip_evidence) with snake_case and clear resource identifiers. The naming is predictable and unambiguous.
Three tools is on the lower end but appropriate for a focused read-only domain (route lateness analysis). The count is slightly thin, but each tool covers a needed layer of detail without redundancy.
The toolset provides ranking, per-route summary, and evidence-level data, forming a complete analysis workflow. A minor gap is the lack of a simple route listing without rankings, but the ranking tool effectively fills that role.
Maintenance
Related MCP Connectors
Open agentic-web datasets: Agent Trust Index, MCP stats, incident timeline. Read-only, CC-BY-4.0.
Deterministic bank-statement parsing: messy CSV/OFX to clean categorized rows. In-memory only.
Normalized official data with provenance, aggregations, insights, free samples and agent access.
Normalized official data with provenance, aggregations, insights, free samples and agent access.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceScrapes and serves India's national vehicle registration database (VAHAN Dashboard), providing detailed insights into registrations, manufacturers, fuel types, and RTO-level metrics.-
- FlicenseNot gradedqualityDmaintenanceCompute and analyze bus route lateness using trip data, with drill-down and cross-referencing against rider complaints and operational logs.-
- FlicenseNot gradedqualityDmaintenanceAnswers operational questions about route on-time performance, such as lateness rates and trip evidence, using structured tools for route summary, trip lateness, and data quality.-
- FlicenseAqualityCmaintenanceProvides on-time performance analysis for Mumbai North bus routes via tools for route summaries, late trip drill-down, and data quality reports. It quarantines invalid data and surfaces policy questions instead of hidden normalizations.3-