Nextbase Docs
Nextbase Docs
HomeBlogWelcome to Nextbase v5!Choose your starterGetting startedLocal Supabase per agent
TanStack + ConvexInstallationEnvironment variablesAuthenticationAgent connectionsProject structureDeployment
AuthenticationWorkspaces and the admin area
Building with agentsEmails with Resend
TroubleshootingNextbase v5
The 8 starter kitsTanStack + Convex

Agent connections

User MCP and Admin MCP in the TanStack + Convex starter: endpoints, tools, consent and how to extend them.

The kit exposes two MCP servers from the Convex backend. Both use the existing Convex Auth login and delegated OAuth tokens. Agents never receive the user's password, a Convex JWT or an API key. Read the shared User and admin MCPs page for the model, and connect an agent for the client-side steps.

The MCP code ships in apps/database/convex/mcp/, and the repository's docs/mcp-connections.md describes it in detail. This page follows that document.

Where users manage connections

ConnectionSettings pageLive demo server
UserWeb app, /user/settings/connections (sidebar: Agent connections)https://ceaseless-lark-846.convex.site/mcp/user
AdminAdmin app, /app-admin/connections (admin menu: Admin agent connections), on the admin origin https://tanstack-convex-admin.usenextbase.com in the demohttps://ceaseless-lark-846.convex.site/mcp/admin

Each settings page shows the server URL with a Copy URL button, the list of connections with their scopes and last use, a revoke action, and recent activity. The admin page requires a current platform administrator and lives in the separate admin app (apps/admin, port 3002 locally).

Your own deployment has its own addresses. The MCP endpoints live on the backend's CONVEX_SITE_URL, not on either frontend origin: http://127.0.0.1:3211/mcp/user locally, https://<name>.convex.site/mcp/user in production. Copy the URL from the settings page rather than typing it.

Endpoints

All of these are mounted on the Convex site URL by mountMcp in apps/database/convex/mcp/http.ts:

EndpointPurpose
/mcp/userUser server: account_context, projects_list, projects_create
/mcp/adminAdmin server: admin_users_list, admin_workspaces_list
/.well-known/oauth-protected-resource/mcp/userUser resource discovery
/.well-known/oauth-protected-resource/mcp/adminAdmin resource discovery
/.well-known/oauth-authorization-server/oauthOAuth issuer discovery (issuer is <CONVEX_SITE_URL>/oauth)
/oauth/register, /oauth/authorize, /oauth/token, /oauth/revokeOAuth lifecycle

The consent page is /mcp/authorize?request_id=... in both frontends (apps/web/src/routes/mcp.authorize.tsx and apps/admin/src/routes/mcp.authorize.tsx). For user connections the backend redirects to MCP_APP_URL, falling back to APP_URL and then SITE_URL. For admin connections it redirects to ADMIN_SITE_URL first, then the same fallbacks. If an admin request lands on the web app anyway, the web consent page shows an Open admin app link built from VITE_ADMIN_APP_URL.

Tools and permissions

ServerToolScopeAccessWhat it does
Useraccount_contextuser:readReadSigned-in account plus the one authorized workspace and granted scopes
Userprojects_listuser:readReadProjects in the authorized workspace, newest first, with continueCursor; limit 1 to 50, default 20
Userprojects_createuser:writeWriteCreates a project through createProjectForActor, the same operation the website uses
Adminadmin_users_listadmin:readReadProfiles (id, email, name, platform role); no credentials or sessions
Adminadmin_workspaces_listadmin:readReadWorkspaces (id, name, slug)

The user server offers user:read and user:write; the admin server offers only admin:read. A token for one resource is rejected by the other, even for a platform administrator.

Every tool call runs verifiedCaller in apps/database/convex/mcp/connections.ts. It checks that the connection exists, is not revoked or expired, includes the scope, that the approving Convex Auth session is still valid, that the account is not being deleted, and then re-runs the real permission check: platform admin role for admin tools, workspace membership for user tools, and a non-readonly membership for projects_create. The gateway's caller argument is hidden from tool schemas; clients cannot supply it.

Consent flow in this kit

  1. The agent registers as a public client (/oauth/register), then opens /oauth/authorize with PKCE S256 and the exact resource URL.
  2. The backend stores a pending request (10 minutes) and redirects to /mcp/authorize on the web app (user server) or the admin app (admin server). If you are not signed in on that origin, the page links to /login?returnTo=... and brings you back.
  3. The consent card shows the client name (marked as supplied by the client), the exact callback URL and the requested permissions. For the user server you choose one workspace; the write permission (create projects) is off by default and resets when you change workspace. For the admin server there is no workspace, and only a platform administrator can approve.
  4. Approving creates an mcpConnections row tied to your current auth session and returns a one-time code (5 minutes). The agent exchanges it for a 15 minute access token and a refresh token.
  5. Connections and refresh tokens last 30 days, or until you revoke them, sign out of the approving session, lose the workspace membership, or lose the admin role. Refresh tokens rotate once; reusing one revokes the connection. Each account can hold 20 active connections.

Browser clients are allowed from the app origin (MCP_APP_URL, falling back to APP_URL then SITE_URL), https://claude.ai and https://chatgpt.com. Desktop and server clients without an Origin header can connect. Confidential clients and client ID metadata documents are not supported.

An hourly cron (apps/database/convex/crons.ts) prunes expired clients, requests, codes and tokens, keeping used refresh tokens seven days past expiry for replay detection, and removes activity older than 90 days.

Where the code lives

convex.config.ts
crons.ts
http.ts
mcp.test.ts
actor.ts
cleanup.ts
connections.ts
http.ts
oauth.ts
protocol.ts
schema.ts
tools.ts
components/mcp-connections.tsx
components/mcp-consent.tsx
routes/mcp.authorize.tsx
routes/_authenticated.user.settings.connections.tsx
components/mcp-connections.tsx
components/mcp-consent.tsx
routes/mcp.authorize.tsx
routes/_authenticated.app-admin.connections.tsx

convex.config.ts installs the pinned convex-mcp-gateway@2.1.1 component twice, as mcpUser and mcpAdmin. Keep them separate; do not share a registry between the two servers. The MCP tables (mcpClients, mcpRequests, mcpConnections, mcpCodes, mcpTokens, mcpActivity) are defined in mcp/schema.ts and spread into the main schema.

Adding a tool safely

  1. Write an internalQuery or internalMutation in mcp/tools.ts whose first argument is caller: mcpCallerValidator. Start the handler with await verifiedCaller(ctx, caller, "user" | "admin", "<scope>", writable).
  2. Call an existing application function or shared helper with the verified grant.userId and grant.workspaceId. Do not trust a userId or workspaceId passed by the client.
  3. Register it in userTools or adminTools with defineMcpQuery or defineMcpMutation, identityArg: "caller" and metadata: { scope }. The gateway's authorize callback only allows tools whose scope the connection granted.
  4. For writes, call record(ctx, grant, "<tool_name>") so the activity appears in settings, and keep paging bounded with bounded(limit).
  5. Add cases to apps/database/convex/mcp.test.ts, then test the real HTTP flow against a local Convex backend. The in-memory tests do not prove that bearer tokens reach HTTP actions.

Never publish local fixture functions or synthetic identity helpers to production. The repository also ships an mcp-tool skill in .agents/skills/ that walks AI coding tools through these steps.

Authentication

How Convex Auth works in the TanStack + Convex starter, including verification emails, social login, sessions, the separate admin app, the admin claim flow and impersonation.

Project structure

The TanStack + Convex monorepo layout and where to make changes to routes, data, auth, the admin app, emails, jobs, MCP and tests.

On this page

Where users manage connectionsEndpointsTools and permissionsConsent flow in this kitWhere the code livesAdding a tool safely