Skip to main content
This is the by-hand path. It’s also the reference for checking an agent’s work — every command and expected response is spelled out, so you can compare against what the agent reported.If you’d rather hand the mechanical parts to a coding agent, the prompt cards are on Add OAuth to a Xano MCP server, along with the flow diagram and the “do I even need OAuth?” table. Start there — this page assumes you’ve already decided you do.

What the spec requires

A token in the URL won’t work on Claude surfaces. Add a connector URL with the token in it and Claude sends you to an OAuth consent page that can’t complete — it runs an OAuth handshake for every custom connector, and a Xano MCP server has no authorization server to hand it off to. Since the 2025-06-18 revision an MCP server is an OAuth resource server: clients discover the authorization server via /.well-known/oauth-protected-resource (RFC 9728), and the spec explicitly prohibits access tokens in the URI query string. The Worker in this guide is the shim that fills that gap.What Claude enforces today, per Authentication for connectors:
  • A 401 — not a 200. Claude does not honor a WWW-Authenticate header on a 200 response. The challenge must carry resource_metadata pointing at your protected resource metadata document.
  • RFC 9728 probing. With no explicit resource_metadata pointer, Claude tries /.well-known/oauth-protected-resource/<your-mcp-path> first, then /.well-known/oauth-protected-resource.
  • PKCE, always. Claude sends a code_challenge with code_challenge_method=S256 on every authorization request.
  • DCR is the slow path. Dynamic client registration still works, but Claude registers a new client on every fresh connection; CIMD is preferred for high-traffic servers.
OAuthProvider satisfies all four out of the box — Step 4’s curl checks confirm it on your deployment.
MCP 2026-07-28 is the current revision. Published on 28 July 2026, it makes the protocol stateless and is rolling out across Claude products. Three changes touch this guide, so track them rather than treating this page as final:
  • Mcp-Session-Id is gone, along with the initialize handshake. The proxy’s session round-trip becomes a no-op for 2026-07-28 clients (harmless), but any Xano-side logic keyed to a session must move to explicit tool arguments.
  • Last-Event-ID and SSE resumability are removed. A broken stream is re-issued as a new request instead of resumed.
  • DCR is deprecated in favor of Client ID Metadata Documents (CIMD). Dynamic client registration has been demoted across three revisions: a SHOULD in 2025-06-18, downgraded to a MAY in 2025-11-25 when CIMD was introduced, and deprecated in 2026-07-28. It keeps working for backward compatibility — the spec’s deprecation window is a minimum of twelve months, and Claude still supports it — but new deployments should plan for CIMD.
Everything else on this page — RFC 9728 discovery, the 401 challenge, PKCE, header-only tokens — is unchanged by 2026-07-28.

Step 1 — Turn on user authentication in Xano

1

Set each tool's Authentication to user authentication

Open your MCP server → Connected Tools → set the Authentication column to user authentication on every tool you want gated.Xano then validates Authorization: Bearer <user JWT> natively and populates $auth. No custom token-checking function is needed.
2

Retire any auth checks you wrote yourself

Skip this if your tools had no authentication before — the toggle is all you need.Otherwise, native auth replaces whatever you built, and leaving it in place can reject the users you’re onboarding. Check three places, not just the stack:
  • The tool’s stack — a function.run call to a custom token-validation function, a token read by hand from an input or header, or a precondition gating on a shared secret.
  • Middlewaremiddleware can be applied to AI tools, so the check may live there rather than in the stack.
  • An MCP server trigger — a connection trigger that validates toolset.token.
Remove only the parts that authenticate. A trigger or middleware often does other work too — filtering which tools a client sees, logging, rate limiting — and that should stay. If any tool’s logic uses the old token value downstream, swapping it for $auth changes behavior; decide that case deliberately.
3

Know what the toggle does and does not gate

This setting gates tool calls only. An unauthenticated initialize still returns 200. To test whether auth is on, call a tool — a successful initialize proves nothing.The setting lives in the dashboard, is not represented in XanoScript, and survives xano workspace push of your tool files.
4

Verify auth is enforced

Call a read-only tool against the stream URL with no Authorization header. Expected response:
If you get real data instead, that tool’s Authentication is still Disabled.
Any tool left Disabled is callable by anyone who reaches your Xano MCP URL directly — the Worker is not in that path. Gate every tool.

Step 2 — Collect your two URLs

Both are covered on the parent page, including where to find them in the dashboard or from the CLI. The shapes, for reference:
Use the streaming endpoint. SSE-only endpoints are deprecated and being sunset; new integrations should use streaming exclusively.

Step 3 — Deploy the Worker

The Worker is four small files. @cloudflare/workers-oauth-provider does all the OAuth heavy lifting: metadata documents, /token, /register, PKCE enforcement, token issuance and rotation, and the 401 challenge.
1

Authenticate and create KV storage

2

Deploy to learn your Worker host

3

Set three secrets

Everything instance-specific lives in secrets, not code — the same Worker fronts a different Xano MCP by changing these two URLs.
Handling credentials. In this flow the Worker receives the user’s Xano password in order to exchange it at /auth/login. Before using it beyond your own testing:
  • Serve the login page over HTTPS only, accept credentials by POST only, and never place them in a query string.
  • Never log the request body, and never persist the password — forward it and drop it.
  • Rotate COOKIE_SECRET if it is ever exposed; it signs the OAuth state.
  • Prefer a passwordless variant where you can: swap /auth/login for /auth/magic_link or your IdP’s /auth/* endpoint. The only contract the Worker needs is to end with a valid Xano user JWT in props.xanoJWT.
  • Have Security review this before exposing it to users other than yourself.

Step 4 — Test with the MCP Inspector (optional)

Skip to Step 5 if you’d rather go straight at it with the real client. The Inspector is worth the five minutes, though: it separates “the Worker is broken” from “the client is misconfigured,” which is otherwise hard to tell apart. Either way, initialize succeeding is not a passing test — a tool call returning rows is.
1

Check discovery and the 401 challenge

The 401’s WWW-Authenticate header must carry resource_metadata=…. That header is what tells an OAuth client where to go next; without it the client just fails.
2

Open a log tail in one terminal

3

Run the Inspector in another

In the Inspector UI:
  1. Transport TypeStreamable HTTP
  2. URLhttps://xano-mcp-oauth.<subdomain>.workers.dev/mcp
  3. AuthenticationOAuth
  4. Connect → you are redirected to the Worker login page; sign in with a Xano user-table account.
  5. List Tools → run a read-only tool.
4

Read the tail

A healthy run looks like this:
Tool Result: Success with real rows means the request reached Xano carrying your per-user JWT. That is the pass condition.

Step 5 — Connect a client

Add a custom connector pointing at:
No token, no query string. The client runs the registration → login → PKCE → token handshake itself, then lists and calls your tools. If it fails here and you skipped Step 4, run the Inspector now — it will tell you which side is at fault.

Troubleshooting

Search this table for the literal error text you’re seeing. Useful commands:
There’s a prompt card for this — Diagnose a failing proxy hands the whole table to an agent along with your symptom, and has it gather the evidence first.

Icons and display name

There is no icon setting on Cloudflare — clients resolve it differently:
  • Claude surfaces fetch the connector origin root (/) as HTML and parse <link rel="icon">. Serve HTML at / with a PNG icon link.
  • MCP Inspector reads serverInfo.icons from the initialize response.
The display name comes from resourceMetadata.resource_name in src/index.ts.
Connector icons are cached per domain and can be sticky — a removed and re-added connector may keep showing the fallback avatar. A fresh hostname (rename the Worker or bind a custom domain) forces a cold fetch.

Limitations

  • 24-hour JWT. The Xano user JWT expires in 24h while the OAuth grant lasts longer, so upstream calls start 401ing and the user re-logs-in. To smooth this out, add a Xano POST /auth/refresh (auth="user") and call it from OAuthProvider’s tokenExchangeCallback, writing the fresh JWT into newProps.
  • No consent screen as built. This treats a successful login as consent. A public or multi-tenant deployment needs an explicit consent step with CSRF protection in /authorize before completeAuthorization — there’s a prompt for that on Add a consent screen.
  • Gate every tool. Only tools set to user authentication are protected.
  • One MCP server per Worker as written. To front several, select XANO_MCP_STREAM_URL by request path and use apiHandlers (a route → handler map) instead of a single apiHandler.

Next steps

Add OAuth to a Xano MCP server

The overview, the flow diagram, and the prompt cards that do all of this for you.

Connecting Clients

Header-based and URL-based auth for clients that don’t need OAuth.