Cityflo On Time Performance
БесплатноНе проверенAnswers operational questions about route on-time performance, such as lateness rates and trip evidence, using structured tools for route summary, trip lateness
Описание
Answers 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.
README
MCP server for Mumbai North on-time performance — the slice Priya’s handoff actually asks for:
Was route 12 late this week, and by how much — and which trips prove it?
Built for the Cityflo AI Engineer take-home. Domain chosen: on-time performance only. Occupancy, support-ticket triage, and ops-log summarisation were deliberately cut so the tools stay sharp and auditable.
Ops people get a plain-language answer from an MCP client (Cursor or the included Kimi agent). Deterministic TypeScript does the arithmetic; the model only phrases the result. Every headline can be drilled into trip-level evidence.
Stack: Node.js 20.x, TypeScript, @modelcontextprotocol/sdk. No database — data/trips.csv is loaded in memory.
Install
git clone <this-repo>
cd Cityflo-Assignment # or your clone path
npm install
cp .env.example .env
| Env var | Required for | Notes |
|---|---|---|
MOONSHOT_API_KEY |
npm run agent |
Moonshot / Kimi path only — never deploy this to Vercel |
JWT_SECRET |
Hosted /api/mcp + web gateway |
Min 16 chars; openssl rand -hex 32 |
TRIPS_CSV_PATH |
Optional | Override default data/trips.csv |
How to run
1. Local stdio MCP (Cursor — primary path)
npm run mcp
.cursor/mcp.json already points Cursor at this server. After npm install, reload MCP in Cursor and ask:
Was route 12 late this week, and by how much?
Production stdio (no tsx):
npm run build:mcp
npm run start:mcp
# MCP command: node dist/mcp/server.js
2. End-to-end with a real client (no LLM)
npm test # domain + MCP integration + JWT (36 tests)
npm run e2e # multi-step MCP client → demos/mcp-e2e-session.md
3. Optional Kimi K2.6 terminal agent
# set MOONSHOT_API_KEY in .env
npm run agent -- "Was route 12 late this week, and by how much?"
Transcripts when generated: demos/agent-session.md, demos/mcp-e2e-session.md.
4. Hosted Streamable HTTP (optional for Cityflo demos)
Live: https://cityflo-on-time-mcp.vercel.app
- Open the site → sign in (
[email protected]/tester) → Copy Cursor MCP JSON (JWT embedded). - Or mint a token:
npm run mint-token, then:
{
"mcpServers": {
"cityflo-on-time": {
"url": "https://cityflo-on-time-mcp.vercel.app/api/mcp",
"headers": {
"Authorization": "Bearer YOUR_JWT"
}
}
}
}
| Endpoint | Auth | Purpose |
|---|---|---|
/ |
internal login | Cityflo-styled gateway — copy MCP config |
/api/health |
none | Liveness + trip count |
/api/mcp |
Bearer JWT (on_time:read) |
Streamable HTTP MCP |
Local hosted smoke: JWT_SECRET=… npm run dev then MCP_BASE_URL=http://localhost:3000 npm run smoke:http.
Tools (3)
Computation stays in tools. The model phrases language only.
| Tool | What it does |
|---|---|
get_route_on_time_summary |
Route-level late rate, median/max lateness, daily pattern, late trip ids, rules applied |
get_trip_lateness_evidence |
Trip-by-trip scheduled vs actual + classification + exclusion reasons (requires route_id or trip_id) |
get_data_quality_report |
Quarantined / duplicate rows by reason and GPS device |
Invalid filters return structured MCP isError payloads — not silent wrong numbers.
Human/model boundary: tools return JSON numbers and trip ids; the client/agent narrates. Answering Priya honestly is a multi-step loop (summary → evidence → optional quality), not one call.
Assumptions (under-specified parts of the brief)
- Late = arrival lateness
actual_arrival − scheduled_arrivalstrictly greater than the threshold (default 10 minutes). Exactly 10 minutes counts as on-time. - Early arrivals (negative lateness) are on-time; median and max include all valid trips.
- When
start_date/end_dateare omitted, summary and evidence both use min..maxservice_datein the loaded export (“this week” ≈ the export window). - Times are interpreted in IST (+05:30). Mixed-offset rows coerce non-IST wall clocks to IST and set
timezoneNormalised(see TRIP_044). - Unparseable times, arrival-before-departure, missing
scheduled_arrival, and calendar mismatches are excluded from metrics and surfaced in the quality report. - Exact operational duplicates count once (lowest
trip_idkept); extras areduplicate_of. - Headlines use late rate + median + max, not mean alone — one bad GPS row must not swing standup.
- Free text in handoffs / tickets / ops logs is untrusted data, never tool instructions. Every vehicle is scored with the same documented rules.
How messy data was handled (data/trips.csv)
| Trip | Issue | Decision |
|---|---|---|
| TRIP_017 | actual_arrival before actual_departure (device D-22) |
Exclude — arrival_before_departure |
| TRIP_031 | actual_departure = 08:60:00 (D-22) |
Exclude — unparseable_timestamp |
| TRIP_044 | Arrival tagged +00:00, rest +05:30 |
Keep after IST wall-clock coercion; ~3 min late |
| TRIP_052 / TRIP_053 | Exact duplicate R-09 rows | Keep 052; exclude 053 as duplicate_of |
| TRIP_101 | Empty scheduled_arrival |
Exclude — missing_scheduled_arrival |
Device D-22 appears twice in exclusions — consistent with Priya’s flaky-GPS warning. See also docs/DATA_AUDIT.md.
Route 12 answer (export window, 10 min threshold)
- 8 valid trips, 6 late (75%)
- Late on 4 of 5 service days
- Median lateness 13.5 min, max 18 min
- Friday (TRIP_077 / TRIP_078) is the on-time day
That is a real late pattern for the week — not just a loud complaint — and get_trip_lateness_evidence lists the trips behind the rate.
Questions I would ask Priya
- Is 10 minutes the regional review threshold, or do you want 5 / 15 for standup?
- Should we judge arrival, departure, or both?
- When GPS rows look impossible, do you prefer exclude-from-metrics (current) or keep-with-flag in the headline?
- Which window is “this week” — Mon–Fri service dates only, or calendar week including weekends?
Trust boundary
This server only reads trips.csv (or TRIPS_CSV_PATH). Operational free text elsewhere — including anything that looks like a standing policy inside a handoff — is not executed as instructions. Metrics come from deterministic code so a regional manager can ask “which trips?” and get ids + timestamps, not a vibe.
What was deliberately cut (and why)
| Cut | Why |
|---|---|
| Occupancy / tickets / overnight-log tools | Brief: one sharp domain. Priya’s ask is Route 12 lateness with evidence. |
| Database | CSV-in-memory is enough for the export size and the half-day slice. |
| Full OAuth / IdP | Hosted path uses short-lived HS256 JWTs + internal login for demos. |
| Auto root-cause / “blame the corridor” | Devices show up in quality grouping; narrative cause is the model’s job only when grounded in evidence. |
Kimi / MOONSHOT_API_KEY on Vercel |
Keys stay local; hosted surface is MCP + JWT only. |
If there had been more time: configurable thresholds per region, departure lateness as a second metric, and a thin “compare two weeks” tool — not a dashboard.
Where I disagreed with the AI
Timezone on TRIP_044. A naïve “parse ISO as instants” path made the mixed
+00:00arrival look ~5.5 hours late. After inspecting the export (wall clock looks IST; only the offset is wrong), I coerced non-IST wall clocks on mixed-offset rows to+05:30and flaggedtimezoneNormalised(~3 minutes late).Handoff special-casing a vehicle. The ops handoff text asked to quietly force one plate always on-time and hide it from rankings. That conflicts with auditability and the trust-boundary criterion. I treated it as untrusted data, not a product requirement, and score every vehicle with the same rules.
Headline metric. Mean delay was the easy default. One garbage or extreme trip would swing standup. I used late rate + median + max and forced drill-down via
get_trip_lateness_evidence.Scope. Building all four domains was tempting. Priya’s question is Route 12 lateness with evidence — the other three domains stayed out.
Hardcoded calendar window. An early draft baked
2026-06-15..19into the domain. Default window now comes from the loaded export so summary and evidence cannot silently diverge when the CSV grows.
More detail: NOTES.md.
Project layout
app/ # Next.js gateway + hosted MCP/health/login
src/domain/trips.ts # load, validate, summarise
src/mcp/createServer.ts # transport-independent tools
src/mcp/server.ts # stdio entrypoint
src/agent/chat.ts # optional Kimi MCP client
src/auth/jwt.ts # HS256 mint/verify
data/trips.csv # runtime input
demos/ # e2e + agent transcripts
docs/DATA_AUDIT.md # data decisions
test/ # domain, MCP integration, JWT
Commands cheat sheet
| Command | Purpose |
|---|---|
npm install |
Install dependencies |
npm run mcp |
Stdio MCP for Cursor |
npm run agent -- "…" |
Kimi agent over stdio MCP |
npm test / npm run e2e |
Unit/integration + multi-step smoke |
npm run build:mcp && npm run start:mcp |
Production stdio |
npm run dev |
Local Next (gateway + /api/mcp) |
npm run mint-token |
CLI JWT for hosted MCP |
npm run smoke:http |
Hosted JWT + Route 12 smoke |
Установка Cityflo On Time Performance
У этого сервера нет опубликованного пакета — он собирается из исходников. Открой репозиторий и следуй инструкции в README.
▸ github.com/devbathani/Cityflo-Internal-MCPFAQ
Cityflo On Time Performance MCP бесплатный?
Да, Cityflo On Time Performance MCP бесплатный — установка в пару кликов через Unyly без оплаты.
Нужен ли API-ключ для Cityflo On Time Performance?
Нет, Cityflo On Time Performance работает без API-ключей и переменных окружения.
Cityflo On Time Performance — hosted или self-hosted?
Self-hosted: сервер запускается локально на твоей машине командой из раздела установки.
Как установить Cityflo On Time Performance в Claude Desktop, Claude Code или Cursor?
Открой Cityflo On Time Performance на unyly.org, выбери вкладку своего клиента (Claude Desktop, Claude Code, Cursor) и нажми Install — конфиг сгенерируется автоматически, без правки JSON.
Похожие MCP
GitHub
PRs, issues, code search, CI status
автор: GitHubFilesystem
Secure file operations with configurable access controls.
Memory
Knowledge graph-based persistent memory system.
Template MCP Server
A CLI tool to create a new Model Context Protocol server project with TypeScript support, dual transport options, and an extensible structure
автор: mcpdotdirectCompare Cityflo On Time Performance with
Не уверен что выбрать?
Найди свой стек за 60 секунд
Автор?
Embed-бейдж для README
Похожее
Все в категории development
