Bonus Blog Post

N/A

Inspiration

Mid-semester exams. 2 AM. Three tabs open — one for studying, one for a timer app that doesn't understand my schedule, and one for ChatGPT that has no idea I have a calculus exam in 6 hours. I wanted one tool that knew my study patterns, could check my actual calendar, play focus music, and give advice that wasn't generic. So I built it during the exams I was supposed to be studying for.

What it does

StudyFlow is an AI study platform where the AI assistant (MentorMind) has real access to your tools — not just chat.

  • Smart Study Timer with Spotify playback control — focus music starts when you start studying
  • MentorMind AI with 4 models (GPT-OSS 120B, Nova Lite/Pro, Claude 3.5 Haiku) and automatic routing based on query complexity
  • Live Google Calendar access — MentorMind reads your schedule and suggests optimal study windows. 10 calendar tools deployed on a Heroku MCP server with multi-user isolation
  • Auth0 Token Vault managing all third-party API tokens (Google Calendar, Spotify) via machine-to-machine injection — users connect once at login, never see a second OAuth popup
  • Coin economy — earn 1 coin/second studying, spend 100/AI query. Forces you to actually study before asking for help
  • Study Groups with real-time chat, leaderboards, and shared AI context
  • BYOK — bring your own API key (OpenAI, Anthropic, OpenRouter) with AES-256-GCM encryption, skip the coin cost entirely

How we built it

16 days. March 30–15, 2026.

Stack: Next.js 14 + TypeScript, Convex real-time database, Heroku Managed Inference, Auth0 Token Vault, custom MCP server on Heroku.

The core innovation is the hybrid executor architecture for AI tool calls:

User message → Chat Completions API (decides which tools to call)
                    ↓
              Tool call returned?
              ├── Calendar namespace → calendar-executor (local MCP + token injection)
              ├── Other namespace   → heroku-executor (Heroku Agents API)
              └── No tools          → Return text response
                    ↓
              Feed results back → Loop (max 10 iterations)

The executor registry (registry.ts) is 39 lines. First matching executor wins — calendar registers first, Heroku catch-all last. Adding a new tool namespace is: write a match function, write an execute function, import before heroku-executor.

Auth architecture is hybrid by design:

  • Auth0 handles third-party token management (Google Calendar, Spotify) via Token Vault — automatic refresh, SOC 2 certified storage, zero manual token logic
  • Convex Auth handles user login (GitHub/Google OAuth) and real-time session management
  • If Auth0 Token Vault fails, system falls back to Convex-stored tokens automatically

This pattern isn't documented anywhere. We designed it because ripping out Convex Auth would break real-time subscriptions, but we needed Auth0's Token Vault for secure third-party token delegation to AI agents.

Challenges we ran into

1. MCP tool names have slashes. OpenAI function names don't.

OpenAI's function calling requires ^[a-zA-Z0-9_-]+$. MCP tool IDs look like google-calendar/list_events. Discovered this at midnight when every tool call silently failed. Fix: sanitize with replace(/\//g, '__') and maintain a reverse map. 4 lines of code, 3 hours of debugging.

2. Token injection rate limiting on multi-tool requests.

MentorMind calls 3-4 calendar tools per turn. Each tool call triggered a fresh token injection to the MCP server. Hit rate limits immediately. Fix: added a 60-second injection cache keyed by userId (injectionCache in mcp-token-injector.ts). One injection per minute regardless of tool call count.

3. Models that don't support the tools parameter.

Nova Lite returns a 400 if you send tools: [] in the request body. Not tools: null, not omitting it — specifically an empty array crashes it. Other models crash if you send tools at all. Fix: getDefaultCompletionOptions() returns model-specific configs. Some models get tools, some don't. Discovered via commit 1f68813 after the AI helper went completely silent for Nova users.

4. Heroku Agents API returns SSE, not JSON.

Expected application/json. Got text/event-stream with event: message\ndata: {...}. The calendar MCP server wraps JSON-RPC responses in SSE format. Built a custom parser that finds the data: line and extracts the JSON-RPC result. Broke twice — once when the server added blank lines between events, once when error responses used a different event name.

5. Spotify API changed their playlist response structure.

response.tracks became response.items with no deprecation notice. Discovered when every user's "Liked Songs" detection broke. The fix was one line (a1db8f4) but finding it required adding error body logging to every Spotify API call first (6d4688e).

Accomplishments that we're proud of

  • Hybrid auth pattern that actually works in production. Auth0 Token Vault for third-party tokens + Convex Auth for user sessions. Zero downtime if either system has issues. No documented precedent for this combination.
  • 10 Google Calendar MCP tools deployed on Heroku with multi-user token isolation, rate limiting, and automatic refresh. MentorMind can read events, check free/busy, create study blocks, and suggest optimal times based on your actual schedule.
  • 39-line executor registry that routes tool calls to the right backend. Adding Spotify tools later took 20 minutes — write matcher, write executor, import in order.
  • Token injection caching that solved rate limiting without any user-facing latency. One cache line, one TTL constant.
  • BYOK with real encryption — AES-256-GCM, not base64 encoding pretending to be security. Users bring their own keys, we never see them in plaintext after storage.
  • Model router that actually adapts — analyzes urgency keywords, study condition (burnout detection), and requirement category to pick the right model. Not just "use the expensive one."
  • Used MentorMind to study for the exams I was building it during. It checked my calendar, saw I had 6 hours before calculus, and suggested 3 focused Pomodoro blocks with breaks. Got a B+.

What we learned

  • Auth0 Token Vault eliminated 90 lines of manual refresh logic. We had refreshAccessToken actions, expiry checks, retry loops. Token Vault replaced all of it with getAccessTokenFromTokenVault() — one function call, automatic refresh, encrypted storage.
  • Hybrid > migration. We kept Convex Auth for what it's good at (real-time user sessions) and added Auth0 for what it's good at (third-party token management). No big-bang migration, no downtime, no user disruption.
  • SSE parsing is never "done." Every MCP server implements it slightly differently. Build a parser that's lenient about whitespace and event names.
  • Cache at the boundary, not inside the tool. Token injection caching at the orchestrator level (before tool dispatch) is simpler and more effective than caching inside each executor.
  • Test with real APIs, not mocks. The Spotify tracksitems change would never show up in a mock. The Nova Lite tools: [] crash would never show up in a mock. Real API testing caught both within hours of deployment.

What's next for Study-Flow

  • Gmail integration — track assignment deadlines from email threads
  • Notion sync — import study notes as RAG context for MentorMind
  • Voice mode — hands-free studying for memorization sessions
  • Adaptive scheduling — MentorMind auto-generates weekly study plans based on calendar gaps and performance trends (infrastructure already built in adaptiveCalendar.ts)
  • Mobile app — on-the-go session tracking
  • Group AI — shared MentorMind instances that understand the whole group's progress

Built with: Claude Code (architecture + implementation), Convex (real-time backend), Auth0 Token Vault (third-party token management), Heroku Managed Inference (AI models + MCP), TweakCN (theme customization), Aceternity UI (animations)

Built With

Share this project:

Updates