Deploy it and connect Claude
Claude's remote connectors run from Anthropic's cloud, so they cannot reach localhost. This is the public deployment they need and the checks that prove it works before you add the connector.
The editor worked because it runs on the same machine as the dev server. A
remote connector does not, so http://localhost:3000/api/mcp is unreachable to
it. The desktop app is no exception. Everything below is the same app, on a real
domain.
Set the deployed origin
APP_URL=https://cms.example.com
BETTER_AUTH_SECRET=<a-strong-production-secret>
DATABASE_URL=<production-postgres-url>APP_URL has to match the public origin exactly. Access tokens carry
<APP_URL>/api/mcp as their audience, and verification rejects a token whose
audience does not match. BETTER_AUTH_SECRET has a default in the starter's env
schema. That default is for your laptop, not for a server.
Ship the schema as migrations
Fix the starter's migration path first. Codegen only discovers migrations in
src/questpie/server/migrations, and questpie migrate runs only what codegen
found. The starter's cli.migrations.directory sends new files to
src/migrations instead, where nothing reads them. Delete that line from
src/questpie/server/questpie.config.ts.
Then write the migration in development, read it, and commit it:
bun run migrate:createApply only committed files at deploy time:
bun run migrate`migrate`, never `push`
questpie push writes the schema straight to whatever database it is pointed
at. Keep it out of container commands, init containers, CI deploy steps and
runbooks. --force does not make it safer.
Prove the endpoint before you connect
Discovery sits under the handler's base path, which is /api in the starters:
curl https://cms.example.com/api/.well-known/oauth-protected-resource
curl https://cms.example.com/api/.well-known/oauth-authorization-serverBoth return JSON. Then check the endpoint itself:
curl -i -X POST https://cms.example.com/api/mcpIt must answer 401 with a WWW-Authenticate: Bearer resource_metadata="..."
header. That header is what starts the OAuth flow in a compliant client. Use
POST. A GET on /api/mcp returns 405 and tells you nothing.
A `200` there is a hole
POST /api/mcp with no session and no token must never succeed. If it does,
the endpoint is answering unauthenticated callers and every tool you exposed
is public.
Also confirm that /api/auth/oauth2/register, /admin/login and
/admin/oauth/consent all resolve on the same deployment. A client walks
through all three during its first connection.
Add the connector
Claude's remote connectors speak Streamable HTTP, run OAuth, and register
themselves. So the endpoint URL is the whole configuration. Add
https://cms.example.com/api/mcp as a custom connector and leave the advanced
client ID and secret fields empty. Anthropic documents the individual and
organization flows in
Get started with custom connectors using remote MCP.
Then connect it. You sign in with a real account from this app and approve the scopes on your own consent screen. Nothing about that step is Anthropic's.
Do not put this server in claude_desktop_config.json. That file is for local
stdio servers. This one is remote.
What the client can ask for
Of your resource scopes, the authorization server metadata lists only the coarse
umbrellas, such as collections:read and collections:write. The granular
per-resource scopes stay grantable but unlisted. Discovery does not enumerate
your data model.
Consent can only narrow. The signed-in user's .access() rules run unchanged
underneath, so the effective permission is the intersection of the two.
Next
Back to Connect an AI agent for the config and the custom tool. MCP over OAuth 2.1 covers registration, consent and token verification in full.