Stride MCP is a sequel I did not want to write until I had to.
I wrote about the first version of Stride as an AI running coach that stitched together Strava, Whoop, and Google Calendar into something that felt, on a good day, like a coach who actually read your diary. Sharing it felt electric. Roughly fifty people signed up in the space of about a day, and LinkedIn filled up with pings that said the same thing in different words: Strava would not connect. Not because my code forgot a redirect URI or because PostgreSQL shrugged at me during dinner. Because new Strava API applications arrive with an athlete quota that is aggressively small, and fifty curious humans slammed into that ceiling like a polite brick wall.
The product story flipped in an hour from "maybe this has legs" to "the API provider is silently rate-limiting me by headcount unless I plead for expansion." Friends who normally send memes suddenly sounded like SOC 2 auditors. My friend Sean, who takes running seriously in the way engineers take uptime seriously, summed it up in one pragmatic sentence after he hit the failure: everybody needs Strava eventually, which means somebody has to lose the multiplayer game of shared keys versus shared quotas.
Stride MCP is the escape hatch. Try it at app.runstri.de.
It is intentionally less romantic than the coaching concept. Users bring their own Strava developer application. They paste their own Client ID and Secret into my dashboard (encrypted at rest). They OAuth into Strava with their app, so quota is their problem in the nicest possible way: a free developer app tied to their training data, routed through assistants they already trust to read messy human language.
That is the customer promise. The engineering promise, if I am honest, was different: I wanted to understand Model Context Protocol end to end, ship something that Claude.ai and ChatGPT would both talk to, and learn Railway by paying the small tax of real deploy pain instead of imagining it.
The problem
Two problems, really, braided together.
Product: A shared Strava application is convenient for onboarding and dreadful for unpredictability at scale. The exact cap number moves with Strava policy, but the shape of the panic does not move at all: you advertise a connector, strangers click "authorize," and Athlete Slot N plus one gets a shrug emoji from the OAuth server you do not fully control.
Personal: The first Stride validated interest. It did not validate that I understood how assistants call tools over HTTPS in 2026, or how OAuth needs to behave when Claude is acting like a peculiar browser that also wants programmatic access, or why "works on localhost" reliably lies to you about TLS, cookies, and CORS once the hostname changes.
Stride MCP swaps the bottleneck. Instead of routing everyone through Tom's quota, Tom routes everyone through Tom's plumbing and punts quota to each human's Strava dashboard.
Sometimes the morally correct architecture is petty in the spreadsheet and beautiful in reality.
What I was actually testing
The side-bet was understanding MCP end to end, shipping two production services on Railway with Prisma, and confirming that BYO keys was architecture, not a workaround.
What I built
Two services, one repo. apps/web is the Next.js dashboard where users sign in, paste their Strava credentials, and complete OAuth. apps/mcp is a Hono server that implements MCP over Streamable HTTP at POST /mcp. Shared packages handle the database (Prisma + Postgres), encryption (AES-256-GCM), and a thin Strava client.
The tools are deliberately boring: get_athlete, list_activities, get_activity. Boring tools keep rate limits quiet.
The engineering bits
OAuth: how the assistant finds Stride and gets access
The mental model is small:
- User proves identity to Stride (Google).
- User connects Strava with BYO credentials (Strava OAuth using their client).
- User adds the MCP URL in Claude or ChatGPT.
- Assistant registers and runs OAuth against Stride.
- Stride maps the successful login to a connector access token the assistant stores.
- Assistant calls
POST /mcpwithAuthorization: Bearer ....
BYO quota
Users paste their own Strava Client ID and Secret. Stride encrypts them, each user completes Strava OAuth under their own app, and rate limits become their problem in a good way.
MCP request path: question to tool to Strava to answer
When a user asks "what was my longest run last month," the assistant does not phone me. It calls list_activities with arguments, my server resolves userId from the bearer token, pulls Strava tokens for that user only, calls Strava REST, returns JSON. The model turns JSON into human sentences.
Railway: two services, two Dockerfiles, two hostnames
Production is two Railway services from one repo:
- Web image built from
apps/web/Dockerfile - MCP image built from
apps/mcp/Dockerfile
Custom domains hang off GoDaddy DNS to app.runstri.de and mcp.runstri.de.
Prisma on Alpine needed the classic fix: apk add openssl in both Dockerfiles so database clients stop acting mysterious at runtime.
The sharp edges that wasted my evening
GET /mcp returning 405 broke reachability checks in a way that feels silly only after you fix it. Assistants and browsers do lightweight probes. If your router says "Method Not Allowed" where the product expects a tiny JSON hello, you look offline even when POST works. I added a GET /mcp JSON info response that advertises streamable-http and points humans at POST semantics.
CORS mattered because Claude.ai issues browser-side requests to the MCP host. A server-only mental model will lie to you. Open CORS for the MCP surface with explicit allowed methods and headers (Authorization, session headers the MCP stack uses) saved me from chasing ghosts in server logs that only the browser could see.
Spec gaps versus client behavior showed up as whack-a-mole: one client tolerates sloppy metadata ordering, another does not; one probes GET, another assumes SSE; documentation updates faster than intuition. Treat the golden path as empirical: reproduce with the exact product, sniff headers, compare WWW-Authenticate reality to the cheerful diagram in your notebook.
Three patterns worth a closer look
1. Treat MCP and OAuth like a miniature API gateway
Your MCP surface is just another HTTPS API with sharper typing. Middleware that resolves identity before tools run is non-negotiable. I validate the Bearer token against stored connector token rows, derive userId, and only then register tools for that session. Anything that reaches a tool already has a clean identity. Tools themselves stay ignorant of auth plumbing.
2. Metadata-first debugging
When a connector silently fails, work backward from discovery documents rather than forward from vibes. Protected resource metadata, authorization server URLs, matching resource strings, consent screens: if any link in that chain rattles, the assistant never reaches Strava regardless of tool quality. Add a curl recipe for every discovery endpoint to your debug playbook before you need it at eleven at night.
3. BYO quota as sociology
Technical people reach for abstraction when policy reaches for quotas. Giving every user their own Strava developer app trades onboarding friction for survivability at small scale without waiting on approvals from a distant API program. Fifty signups hitting one cap is misery. Fifty signups each holding their own key is bureaucracy distributed humanely across humans who already tolerate Strava quirks. It also means my app never has a conversation with Strava about "intended use at scale." Their program office stays out of my deploy pipeline.
What's next
Stride MCP proves the handshake: assistants, authenticated remote tools, real Strava payloads, users who actually converse with their mileage.
The next lifts are predictable and fun: narrower tools with cheaper Strava API answers, sharper guardrails around rate limiting, richer prompts in the connector docs so newcomers land their Strava callbacks on the first try, maybe a quieter onboarding path while keeping BYO doctrine intact.
Try it if any of this sounds like your rabbit hole:
- Spin a free Strava API app under your own account (clipboard steps and callback domain vigilance matter).
- Sign in at app.runstri.de and paste your Strava credentials.
- Complete Strava OAuth in the dashboard.
- Drop
https://mcp.runstri.de/mcpinto Claude or ChatGPT connectors.
If you were one of those fifty enthusiastic humans from the launch hour: thank you for the messages. Stride MCP exists because strangers cared enough to report a wall honestly. Plug in your own developer app once, curse the bureaucratic clipboard dance once, run your questions afterward as many times as you like.
Tell me how it behaves on your strangest long run weeks. Sean already has opinions about mine.