DEV Community

Gnana-Shishir-Kumar
Gnana-Shishir-Kumar

Posted on

EZRide Intel — I Built an AI Assistant for Boston's Hidden Free Bus Using Notion MCP

Notion MCP Challenge Submission 🧠

This is a submission for the Notion MCP Challenge

What I Built

Most people in Boston and Cambridge have no idea that a completely free public shuttle has been running since 2002 — no fare, no ID, no registration. It connects North Station in Boston all the way to Cambridgeport via Kendall Square and MIT, and it's open to everyone.

It's called EZRide. And almost nobody knows it exists.

I built EZRide Intel — an AI-powered transit assistant that makes this hidden public resource discoverable, with Notion as the sole database layer. No PostgreSQL, no Firebase, no JSON files at runtime. Every read, every write, every analytics query goes through Notion MCP.

What it does:

  • 🚌 AI Transit Assistant — answers questions about routes, stops, schedules, and fares using data served live from Notion
  • 📊 Ridership Analytics Dashboard — historical ridership analysis from 2015-2025 with Chart.js visualizations, all data sourced from a Notion Analytics database
  • ⚠️ Live Alert Management — active stop closures shown in the sidebar, resolvable with one click that updates Notion in real time via pages.update
  • 🗺️ Trip Planner — saves formatted trip plans directly to Notion as rich pages using blocks.children.append
  • 🔍 Notion Global Search — searches across all EZRide databases simultaneously using the Notion search API
  • 🕐 Recent Searches — sidebar shows live questions pulled from the Notion Query Log DB, updated after every chat interaction

Video Demo

https://youtu.be/LBt1OOiA-vg

Show Me the Code

https://github.com/Gnana-Shishir-Kumar/ezride-intel

How I Used Notion MCP

Notion MCP is not a side integration in this project — it is the entire data layer. Here's the full architecture:

Charles River TMA data (charlesrivertma.org)
        ↓
   ingest.py (one-time seed script)
        ↓
  Notion Workspace (5 databases via MCP)
  ├── Routes DB      — 4 service patterns with stops, times, directions
  ├── Stops DB       — 16 stops with neighborhoods and service notes  
  ├── Alerts DB      — active stop closures, resolvable via pages.update
  ├── Query Log DB   — every user question + AI answer + timestamp
  └── Analytics DB   — ridership data 2015-2025 (11 years)
        ↕
   agent.py — reads all 5 DBs → Gemini generates answer → logs back to Notion
        ↓
   Flask web app (localhost:5000)
Enter fullscreen mode Exit fullscreen mode

Notion MCP tools used:

databases.query — the core of the RAG pipeline. Every user question triggers live queries to Routes, Stops, Alerts, and Analytics databases. The results become Gemini's context window — so the AI's knowledge comes entirely from Notion at runtime.

pages.create — used in two ways: the ingest script seeds all 16 stops, 4 routes, 2 alerts, and 11 years of analytics into Notion on setup. Then at runtime, every user question is logged as a new page in the Query Log DB.

pages.update — powers the human-in-the-loop alert resolution. When a transit alert is resolved, clicking "Mark Resolved" in the UI calls pages.update to change the Status property from Active → Resolved in Notion live. No page refresh needed.

blocks.children.append — the Trip Planner creates a full rich Notion page with headings, callout blocks, and bulleted stop lists when a user saves a trip plan. The page appears instantly in their Notion workspace.

search — the global search bar queries across all EZRide databases simultaneously using Notion's search API, returning matching stops, routes, and analytics records.

Why Notion as the database matters

Most projects use Notion as a UI layer on top of a "real" database. In EZRide Intel, Notion is the database. There is no fallback. If you disconnect the Notion integration, the AI has no context, the dashboard has no data, and the query log has nowhere to write.

This means:

  • Non-technical users can edit stop data, add alerts, or update schedules directly in Notion — no code changes needed
  • The Query Log becomes a living analytics dashboard in Notion itself — you can see what people are asking in real time
  • Alerts can be managed by a transit operator directly in Notion, and the web app reflects changes instantly

The civic problem this solves

EZRide averaged 500,000 passengers per year before COVID — yet Cambridge city councillors have said publicly that even bus drivers don't know the routes are open to the public. People get turned away at the door. The awareness gap is real.

EZRide Intel makes the service discoverable through natural language. Ask it anything:

  • "Is EZRide really free?" → Yes, 100% free, no ID required
  • "What stops are near MIT?" → Main/Vassar and Vassar/Mass Ave for weekdays
  • "How did COVID affect ridership?" → Annual riders dropped from 508,000 in 2019 to 142,000 in 2020 — a 72% decline
  • "Are there any current stop closures?" → Broadway/Galileo closed Mon-Fri, use Kendall Square (71 Ames St)

Data sources

All route, stop, and schedule data sourced from the Charles River TMA official site. Historical ridership anchor points from official statements: 2012 daily average of 2,500 riders and pre-COVID annual ridership of ~500,000 sourced from Streetsblog Massachusetts and Wikipedia. Intermediate years reconstructed as realistic synthetic data following known trends.

Tech Stack

  • Backend: Python + Flask
  • AI: Google Gemini 2.5 Flash via google-generativeai
  • Database: Notion (via notion-client Python SDK)
  • Frontend: Vanilla HTML/CSS/JavaScript + Chart.js
  • Data ingestion: Custom Python seed script (ingest.py)
  • Pattern: RAG (Retrieval Augmented Generation) — Notion data as context window

Top comments (0)