The Remote MCP Endpoint
The MCP server is a developer tool: it runs on your machine and holds a service
key or an API key. A deployed backend can also serve MCP itself, at /mcp, for
the people who use your application. An assistant one of them connects reads and
writes the project as that person, and every call runs under their own
row-level security.
It is off unless you turn it on, and both variables are required:
REBASE_MCP_ENABLED=trueREBASE_PUBLIC_URL=https://app.example.com # this deployment's real originWithout REBASE_PUBLIC_URL, a JWT secret, or a data driver that can scope a query
to one user, the endpoint declines to mount and says why in the boot log. No
REBASE_ROLE turns it on.
- OAuth, with a consent screen. A client finds the authorization server
through
/.well-known/oauth-protected-resource, registers itself (dynamic registration is on by default;REBASE_MCP_OPEN_REGISTRATION=falselimits it to clients you register), and sends the person to a consent screen that signs them in through your existing/auth/login. An account with a second factor is then asked for its authenticator code or a recovery code, through the existing/auth/mfa/challengeroutes. The screen signs in with a password only: someone who has only ever used Google, GitHub or an email link sets one first with/auth/forgot-password(your app’s “Forgot password”), and the screen tells them so. It also names the host the authorization code is sent to, and says that host is not verified: anyone may register a client under any name, so the host is the part a person can check. - Eight tools, three scopes. The same scopes
every credential uses.
data:readofferslist_collections,describe_collection,query_collection,count_documentsandget_document;data:writeaddscreate_documentandupdate_document;data:deleteaddsdelete_document. A client that asks for nothing getsdata:read. Each one narrows to a collection:data:read:postslists, describes and readspostsand nothing else. A scope decides which tools are offered and which collections they reach, not which rows: an empty list can be RLS working, anddata:writestill cannot write a row the person could not. - Grants made before 0.24 keep their reach.
mcp:readis read asdata:read, andmcp:writeasdata:write data:delete, on stored grants and on tokens already issued. - An API key works too.
/mcpalso acceptsAuthorization: Bearer rk_…, for a client configured with a header rather than an OAuth flow. The key reaches the tools itsdata:*scopes cover, as whoever it acts as: a personal key as its owner, a service key asapi-key:<id>. - The SDK’s vocabulary, REST’s answers. The tools take what the SDK takes —
where({"status": ["==", "paid"]}),orderBy(["created_at", "desc"]or"created_at:desc"),limit,offset,searchString, anddatafor a write — and read throughGET /api/data/<collection>’s path, so a row comes back as REST serves it (ISO dates, abelongsToas its foreign key, e.g.authorId) and can be sent back in an update unchanged.query_collectionanswers{ data, meta }withmeta.totalandmeta.hasMore, andcount_documents{ count }. As on REST, alimitabove 1000, an undeclared argument and an edit or delete of a trashed row (404) are refused; setting the soft-delete field tonullrestores it.deleted: "only"(or"include") onquery_collectionandcount_documentsreads the trash, as REST’s?deleted=does, so a rowdelete_documenttrashed can be found again to restore. Its description tells the model the delete is permanent only where the collection has no soft-delete field. - The listing names the collections;
describe_collectiongives one’s schema.list_collectionsanswers each collection’sname,titleanddescription, anddescribe_collection { collection }that collection’s OpenAPIrowandcreateschemas, plussoftDeleteFieldwhere rows go to a trash. The tool descriptions tell the model to describe a collection before writing to it. A 200-collection project’s listing is about 5k tokens, and each description under 1k; with every schema in the listing it was about 150k. - A token for this endpoint only. An MCP access token is refused by
/api/data,/api/adminand the WebSocket, so connecting an assistant does not hand it a session.
Every request to /mcp re-reads the person’s account. A deleted or disabled
account, or a “sign out everywhere” or password change after the token was
issued, stops a connected client at once with a 401. A demotion applies to its
next tool call. Every refresh makes the same checks and refuses such a grant
for good. A guest session cannot consent at all.
One limit. Disconnecting a client (DELETE /api/oauth/grants/:clientId, with the
person’s own session) revokes its refresh tokens at once, but an access token
already issued keeps working until it expires, within the hour.
The routes are in Endpoints and the variables in Configuration.