On this page
1 · What you do from your end Operator
Short version: you don't touch any code or config. Your part is decision + presence:
- Pick a low-traffic window (early morning is ideal) and say go. cp5 must run before cp7, and after cp4 (done).
- Have Code (Claude Code) on hand — the flip is a
pure-mcpredeploy, which is Code's lane (or a ComposioSUPABASE_DEPLOY_FUNCTIONcall). You don't run it. - Be signed in and ready to test right after the flip: load the app, open Pure Chat, add a test ticket, open a couple of data pages. ~3 minutes of clicking.
- Keep the Supabase dashboard reachable in case we want the manual toggle instead of a redeploy (Edge Functions pure-mcp Details "Verify JWT").
ANTHROPIC_API_KEY and auth providers are already set (verified 6/27). Rollback is one action and reverts in seconds.2 · Current state grounded 7/7
| Edge Function | verify_jwt | Role |
|---|---|---|
pure-mcp (v53) | false | The authenticated MCP server — the cp5 target |
pure-chat-api | false | Public path the live site uses for chat / board.add |
poppy-mcp | false | Poppy assistant — public-ish |
pure-passkey | false | WebAuthn passkey enroll/verify |
mcp-report-extract | true | Already gated — proves the flip works cleanly on this project |
pure-chat-api, a separate function — not pure-mcp directly. So gating pure-mcp does not, by itself, break public chat/board. The "split the public path" work the plan worried about is largely already true.3 · The nuance that changes everything
verify_jwt = true does not mean "require a logged-in user." The anon key is itself a valid Supabase-signed JWT, so it still passes. What the flip actually does:
- Rejects requests with no
Authorizationheader or an invalid/expired token, at the gateway — before your function code runs. - Lets the function trust that the bearer is a verified token, so it can safely derive the caller's identity from it.
So the real access boundary is inside pure-mcp: does it act as the service role (bypasses RLS — full power) or as the caller's JWT (RLS applies — cp2–cp4 kick in)? That is the single most important thing Code confirms in pre-flight.
4 · Pre-flight checks Code
Before flipping, Code reads the pure-mcp source (supabase/functions/pure-mcp/index.ts) and confirms:
- Key mode: does it create its Supabase client with
SERVICE_ROLE_KEYor with the incomingAuthorizationheader? Note which — it decides whether RLS applies post-flip. - Caller inventory: grep the deployed site + Poppy for
functions/v1/pure-mcp. Confirm every caller sendsAuthorization(anon or user). The chat path usespure-chat-api(safe), but confirm no page callspure-mcpwith no header. - Public tools: list which
pure-mcptools are meant to be reachable anonymously (public reads,chat.send,board.add). If any are, they must stay on a public function (pure-chat-api/ a public route) — never behind the gated endpoint. - Break-glass: confirm the service-role admin/MCP path is unaffected (it authenticates with the service key, not a user JWT).
pure-mcp directly with only the anon key and no Authorization header at all, split that call onto pure-chat-api first. Do not flip until caller inventory is clean.5 · The flip, step by step
Record current pure-mcp version (v53) so rollback is exact. Note verify_jwt=false.
Verify public chat/board stays on pure-chat-api (verify_jwt=false). Leave poppy-mcp public if Poppy is used anonymously; otherwise gate it in a later pass.
Set verify_jwt=true on pure-mcp — either the dashboard toggle, or redeploy config via Composio:
Run the verification matrix below. If any red cell, roll back immediately (Step R).
Mark cp5 done on the tracker + changelog, note new version number.
6 · Verification matrix
| Test | Expected after flip | Who |
|---|---|---|
| Signed-in user loads app + data pages | Works (JWT forwarded authenticated RLS) | Op |
| Pure Chat sends a message + adds a ticket | Works (uses pure-chat-api, unaffected) | Op |
| Admin / MCP service-role write | Works (service key bypasses) | Code |
Direct pure-mcp call with no Authorization | 401 at gateway (this is the point) | Code |
Direct pure-mcp call with anon key | Still reaches function (anon JWT valid); RLS applies per cp3/cp4 | Code |
| Logged-out visitor on a public page | Public reads work via public path; no console 401 storm | Op |
7 · Rollback seconds
Step R: set verify_jwt=false on pure-mcp (dashboard toggle or redeploy config) — or redeploy the snapshotted v53. Everything returns to the pre-flip state instantly; no data change was made.
8 · Go / no-go gate
- GO if: pre-flight caller inventory is clean, public path confirmed on
pure-chat-api, Code is present, Operator is signed in to test, and the window is low-traffic. - NO-GO if: any live public page calls
pure-mcpwithout an Authorization header, or Code hasn't confirmed the service-role-vs-caller-JWT mode, or nobody is available to test + roll back.