Building a remote MCP server with ~100 tools and OAuth: six pitfalls worth knowing
AdPitiful4816 · reddit · 2026-10-03
The team behind Your Next Tours (an app letting tour guides broadcast live audio to their group) shipped a remote MCP server so guides can plug Claude, ChatGPT or Cursor into their account — drop an itinerary PDF in chat and the model builds the tour program, departure and guest list via tools. Endpoint: Streamable HTTP, stateless; auth via OAuth 2.1 + PKCE with self-hosted Ory Hydra.
Their hard-won lessons for anyone building MCP servers:
- Answer GET with 405, not 404. Stateless servers have no SSE stream; 404 makes Cursor and Gemini CLI report "Failed to open SSE stream" and give up. Return 405 with Allow: POST.
- Unauthenticated must be a real 401. Claude only starts the OAuth flow on a 401 carrying WWW-Authenticate: Bearer resourcemetadata=...; the same header on a 200 is ignored. Reject non-UUID sub claims before they hit the database, or a 400 stops re-authorization.
- Some clients read scopes from the AS, not you. Gemini CLI ignores RFC 9728 resource metadata scopes and uses scopessupported from the AS's openid-configuration. Keep both lists identical, and don't put your full scope catalog in the AS — consent pre-checks everything requested, including scopes exposing guest PII.
- Write tools must state annotations explicitly. A missing destructiveHint means true per spec; they boot-assert on missing annotations. Claude and ChatGPT directory reviews check these per tool.
- Tell the model who it's talking to. After scope/role/plan filtering, models invented reasons for missing tools. Now account, org, role, plan and granted scopes go in initialize.instructions.
- Models fill empty forms with fiction. Asked to "build my company website", the model invented everything without asking. Now getwebsiteoverview returns open questions plus rules against inventing prices, licences, reviews or addresses.
Scope design: every tool (reads included) requires a scope; trip edits can never notify guests — announcement emails are a separate scope; guest lists are masked by default with explicit, logged full-data access.
More from coding & agent
- GPT learns to pass tests, not to engineer: the RL reward-mismatch behind ugly code — xiaohu · 2026-10-03
- Dev wires a daily Hermes agent to triage Sentry errors, but it keeps 'forgetting' context — pauljasperdev · 2026-10-03
- Runway MCP one-shots a corporate training video in 15 minutes, typically $10k to make — tlakomy · 2026-10-03
- Building an AI Research System for a One-Person Firm: Progressive Determinism Architecture — otionflow · 2026-10-03
- Dev deletes custom CLI after discovering SmartSub v3.9.0 already shipped CLI + MCP — lxfater · 2026-10-03
- Meta reportedly building Agent Engine codenamed Forge for its API platform — testingcatalog · 2026-10-03