Skip to main content
By the end of this page, Claude Web, Claude Desktop, or any other OAuth-only client will connect to your Xano MCP server through a plain /mcp URL — no token in the URL, and every request carrying the signed-in user’s own identity. Getting there is mostly mechanical: four small files, a few wrangler commands, and some log-reading. So you don’t have to do it by hand. Each section hands its work to a coding agent as a ready-made prompt — you supply two URLs and a couple of clicks in Xano, and the agent does the rest. Everything between here and there is context: who this is for, how the pieces fit, and the two URLs to have ready. Skip to the first prompt if you’d rather start building and backfill the reasoning later.
Rather build it yourself, or want something to check the agent’s work against? Every command and expected response is written out in Manual setup.

Who is this for?

Two things decide it: what your client can send, and whether you need each user to arrive as themselves rather than as one shared token. Your Xano server doesn’t come into it.
A header token is shared, not per-user. Every client configured with it sends the same credential, so Xano sees one identity no matter who is actually asking. $auth can’t tell your users apart, tools can’t scope data to the caller, and revoking access for one person means rotating the token for everyone who has it.That’s a reasonable basic gate for you and your team on your own machines. It stops being one the moment you ship an MCP server to people who should each see only their own data, or you want the agent to have context about which user it’s acting for. That’s what the OAuth path on this page buys you — no matter what your client is capable of sending.
Xano MCP servers don’t expose an OAuth authorization server — there’s no /authorize, no /token, and no discovery document for a client to find. What they do have is per-tool authentication: set a tool’s Authentication to user authentication and Xano validates a Xano user-table JWT on the Authorization header natively, populating $auth. That’s the mechanism this whole page is built on. Xano issues those JWTs perfectly well — that’s security.create_auth_token behind your own /auth/login. They just aren’t reachable through an OAuth handshake. The Worker supplies that missing front end: it speaks OAuth to the client, exchanges the sign-in for a Xano user JWT, and forwards that upstream. 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. The MCP spec also prohibits access tokens in the URI query string, and has since the 2025-06-18 revision; the current 2026-07-28 revision keeps that ban. Either way, a token in a URL is one shared credential that lands in logs, proxies, and browser history.
Anthropic’s connector docs describe a Request headers section for entering a fixed API key or bearer token. It’s a gated beta, and it isn’t in the Add custom connector dialog most accounts see. Even with it enabled, the credential is entered once by an org administrator and shared by everyone — a broad multi-user gate, not per-user identity. Anthropic’s own guidance: “If each person needs to sign in with their own account, use OAuth instead.”
The full picture — RFC 9728 discovery, why the challenge must be a 401 and not a 200, PKCE, DCR versus CIMD, and what the current MCP 2026-07-28 revision changed, including DCR being deprecated in favor of Client ID Metadata Documents — is in Manual setup.You don’t need any of it to follow this page. @cloudflare/workers-oauth-provider satisfies all of it out of the box, and the verification prompt below confirms it on your deployment.

How it works

Two hops, no URL tokens:
  • Client → Worker: a Worker-issued OAuth access token.
  • Worker → Xano: that user’s own Xano user-table JWT.
The client never sees the Xano JWT, and each user’s traffic carries their own, so Xano authenticates and scopes per user natively via $auth.
McpAgent runs on Durable Objects, which require a paid Workers plan. A stateless reverse proxy keeps the MCP session on Xano — the Worker only round-trips the Mcp-Session-Id header — so this runs on Cloudflare’s free plan.

What you need

A Xano MCP server with at least one tool, a Cloudflare account (free plan is enough), and Node.js 18+wrangler runs through npx. The prompts on this page are written for a coding agent working against your Xano workspace files, so you also want the Developer MCP and the Xano CLI set up in that agent, with xano workspace pull already run — that local path is what the first prompt asks you to paste. Plus the two URLs below. These are the only values an agent can’t discover for you, so collect them before you start.
string
required
Where: Connect this backend at the top left of the page → MCP Server URLs → the icon next to your server. Expand the row and take the streaming URL, not the SSE one.Note that mcp appears twice. Copy it rather than assembling it by hand — a wrong shape 404s instead of erroring usefully.
string
required
Where: API in the sidebar → open the group holding POST /auth/login → copy the full URL of any endpoint in it and drop everything after the /api:{canonical} segment.That endpoint must return { authToken } from security.create_auth_token. No trailing slash.
Both URLs share the same {instance-host} — the hostname of your Xano instance, like x8ki-letl-twmt.n7.xano.io. Only the path differs. If you ever need it on its own, open Instance Settings from the instance selection screen; the host is everything between https:// and the first / in the URLs shown there.In the stream URL, the {canonical} segment is your MCP server’s ID, and the /mcp/stream that follows it is literal — which is why mcp appears twice.Both canonicals also live in your pulled workspace files, if you’d rather not click through the dashboard:
The instance host isn’t in the pulled files — read it off your CLI profile:
Assembling the stream URL this way is only safe if you keep the shape exactly as shown above. If you’re unsure, copy it from Connect this backend instead.

The work, and who does it

The build splits cleanly in two, and it’s worth knowing which is which before you let an agent loose — they touch completely different things. Work through the two sections in order — the Cloudflare side assumes Xano is already gating tool calls.

In Xano — gate your tools

Xano is what actually decides whether a tool call is allowed — the Worker only forwards a JWT to it. So this side comes first: get your tools onto native user authentication. Get it wrong and the Worker will happily proxy calls to tools that never check anything. How much there is to do depends on where you’re starting. If your tools have no authentication yet, this is a dashboard toggle and nothing else. If you built your own checks — a validation function in each tool’s stack, middleware on your tools, or an MCP server trigger reading a token off the connection — native authentication replaces them, and leaving them in place can lock out the very users you’re about to onboard. This is also the first of the prompt cards. Each one says what its prompt does; Copy prompt puts the full instruction on your clipboard — 20 to 40 lines, with the exact commands and what counts as passing.

Audits how your tools authenticate today, proposes what native user authentication replaces, and verifies enforcement.

Open in Cursor
What it does: takes stock before it touches anything. It reads each tool’s stack plus any middleware and MCP server trigger, reports what authenticates your calls today — including “nothing,” if you’re starting fresh — and only then proposes what native user authentication makes redundant, as a diff for you to approve. Then it calls a read-only tool with no Authorization header to confirm Xano rejects it.
One part of this is a click, not a prompt. Setting each tool’s Authentication to user authentication lives in the Xano dashboard under Connected Tools. It has no XanoScript representation, so an agent can’t set it and xano workspace push won’t overwrite it — you have to do it yourself.The prompt tells you which tool is still ungated, which is the part that’s tedious by hand. Any tool left Disabled is callable by anyone who reaches your Xano MCP URL directly; the Worker isn’t in that path. Gate every one.

On Cloudflare — build and deploy the Worker

Four small files, deployed to your own Cloudflare account. @cloudflare/workers-oauth-provider does the OAuth heavy lifting: metadata documents, /token, /register, PKCE enforcement, token issuance and rotation, and the 401 challenge. Dynamic client registration — the /register endpoint — is deprecated as of the 2026-07-28 spec revision in favor of Client ID Metadata Documents, but it’s retained for backward compatibility through at least a twelve-month window and Claude still supports it out of the box. It’s the right thing to have, and to check for, today.

Scaffolds the four-file Worker and drives wrangler end to end — KV namespace, deploy, secrets.

Open in Cursor
What it does: writes src/index.ts, src/authorize.ts, src/proxy.ts and wrangler.jsonc, then runs the whole wrangler sequence — login, create the KV namespace, deploy to learn your workers.dev host, set the three secrets, redeploy. It will stop and ask when wrangler login needs your browser. Your two URLs go in as secrets, not code, so the same Worker can front a different Xano MCP later.
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.

Runs the discovery and 401 checks, then reads the wrangler tail output for you.

Open in Cursor
What it does (optional, but five minutes well spent): curls the three discovery endpoints to confirm the Worker is spec-compliant, then tails the Worker logs while you connect with the MCP Inspector (npx @modelcontextprotocol/inspector — you run this part) and tells you the first line that deviates from a healthy run. Skipping it just means a later failure is harder to attribute: this is what separates “the Worker is broken” from “the client is misconfigured.” Every check is written out command by command in Step 4 — Test with the MCP Inspector, if you’d rather run them yourself.

Connect a client

Add a custom connector pointing at your Worker:
No token, no query string. The client runs the registration → login → PKCE → token handshake itself, then lists and calls your tools. How you know it worked: a tool call comes back with real rows. That’s the only pass condition that means anything — initialize succeeding proves nothing, because Xano’s authentication toggle gates tool calls only and an unauthenticated initialize still returns 200. If it doesn’t: connect with the MCP Inspector before you start changing Worker code. It runs the same handshake outside your client, so it tells you which of the two is actually at fault — about five minutes, and optional. Step 4 — Test with the MCP Inspector has the commands and the healthy log sequence to compare against.

Troubleshooting

Takes your failing symptom and works the table against your live Worker.

Open in Cursor
What it does: gathers evidence first — the Worker logs, which secrets are set, the two curl checks — then matches your symptom against the nine known failure modes and says what rules the others out. The same causes are written out as a scannable table in Manual setup if you’d rather search for your error text yourself.

Stop the daily re-login (optional)

Kills the 24-hour re-login: adds a Xano refresh endpoint and wires it into tokenExchangeCallback.

Open in Cursor
What it does: the Xano user JWT expires after 24 hours while the OAuth grant lasts longer, so users get sent back to the login screen once a day. This is the one prompt that changes both sides — it adds a POST /auth/refresh endpoint to your Xano auth group and wires the Worker’s tokenExchangeCallback to call it. Worth running once you’re past testing. As built, the Worker treats a successful login as consent — you sign in and the grant is issued. That’s fine while you’re the only user. Once anyone else can reach the Worker, they should see what they’re approving and be able to say no.

Inserts an explicit approve/deny step between login and grant issuance, with CSRF protection, and brands the pages.

Open in Cursor
What it does: splits /authorize into login → consent → grant. Deny becomes a real outcome — the client gets an access_denied redirect rather than a grant it never asked the user about — and the approve path gains CSRF protection, so a third-party page can’t forge an approval on a signed-in user’s behalf. It also brands both pages with your display name and icon, which is what people actually see during the handshake. Skip it and the Worker still works exactly as before; you just have no consent record and no deny path, which is only safe while you’re the only user.
  • 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.
  • Connector icons are resolved from the HTML your Worker serves at /, and are cached per domain. See Icons and display name.

Next steps

Manual setup

Every step by hand, the four Worker files in full, and the troubleshooting table.

Connecting Clients

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

MCP Servers

Building servers, connection URL anatomy, and URL parameters.