MCP connectors
Authorize a user with an MCP server through OAuth with dynamic client registration in Vault, connect with the stored session and give the model the server's tools.
better-supabase/ai-sdk/mcp connects the connectors
block to MCP servers through @ai-sdk/mcp. It runs the OAuth flow for a
user, keeps the tokens in Vault, reuses the MCP session of a chat and only
returns tools from a tool list an admin approved.
pnpm add ai @ai-sdk/mcpAuthorize a user
import { authorizeConnector } from "better-supabase/ai-sdk/mcp";
const result = await authorizeConnector({
connectors,
vault,
server,
userId,
redirectUrl: `${origin}/connectors/callback`,
}).orThrow();
if (result.url) return Response.redirect(result.url);import { completeConnector } from "better-supabase/ai-sdk/mcp";
await completeConnector({
connectors,
vault,
server,
userId,
redirectUrl: `${origin}/connectors/callback`,
callback: request.url,
}).orThrow();authorizeConnector registers the app with the server's authorization
server when it has no client yet (dynamic client registration) and returns
the URL to send the user to, or no URL when the stored tokens still work.
completeConnector checks the state, exchanges the code, then records the
grant. vaultOAuthProvider is the OAuthClientProvider
behind both: the client information goes in an app secret
mcp-client:<serverId> and the user's tokens and PKCE verifier in a user
secret under mcpOAuthRef(serverId).
Connect and get tools
import { connectAll } from "better-supabase/ai-sdk/mcp";
const servers = await connectors.servers.list(organizationId).orThrow();
const { tools, skipped, close } = await connectAll(servers, {
connectors,
userId,
vault,
credentials,
chatKey: chatId,
});
try {
return streamText({ model, messages, tools });
} finally {
await close();
}connectTools connects to one server and connectAll to many, naming each
tool after its server (github_create_issue). A server's auth type sets
the credential:
| Auth | Sends |
|---|---|
none | Nothing |
header | The headers of the server's credential_ref, resolved for the app |
oauth | The user's Vault tokens, or their grant through another provider |
With chatKey, the MCP session id and initialize result are stored per
chat and reused on the next request. A server that is disabled, has no
grant for the user or can't be reached fails with the hint
CONNECTOR_DISABLED, CONNECTOR_NOT_AUTHORIZED or CONNECTOR_UNREACHABLE;
connectAll lists those in skipped and keeps the rest. A tool list that
changed returns CONNECTOR_TOOLS_CHANGED until an admin approves it.
Pass apps: true to split out MCP Apps tools into appTools, and elicit
to answer a server's elicitation requests; without it they are declined.
Supabase's MCP server
Supabase's MCP server
gives an agent project tools: list tables, run SQL, read the logs and search
the Supabase docs. supabaseMcp returns the URL to register as a connector
server and the tool schemas from @supabase/mcp-server-supabase, so
connectTools types each tool's input and output:
pnpm add @supabase/mcp-server-supabaseimport { connectTools, supabaseMcp } from "better-supabase/ai-sdk/mcp";
const supabase = await supabaseMcp({
projectRef: "abcdefghijklmnopqrst",
features: ["database", "docs"],
});
// supabase.url is
// https://mcp.supabase.com/mcp?project_ref=abcdefghijklmnopqrst&read_only=true&features=database%2Cdocs
const { tools, close } = await connectTools({
connectors,
server, // a connector server registered with supabase.url
userId,
vault,
schemas: supabase.schemas,
}).orThrow();supabaseMcp is read-only unless you pass readOnly: false: the URL sets
read_only=true, so SQL runs read-only, and the schemas leave out the tools
that write, such as apply_migration.
connectTools returns only the tools the schemas name, and the fingerprint
an admin approves still covers every tool the server lists. Pass
url: "http://localhost:54321/mcp" for the server of the local Supabase
stack.
The hosted server signs the user in with their Supabase account through
OAuth, so register it with the oauth auth type and send the user through
authorizeConnector first. To serve it from your own app with a Management
API token you hold, see
Supabase's MCP server on the MCP
page.
Supabase's server and better-supabase's MCP tools answer different needs.
Supabase's tools administer a project (SQL, migrations, logs, branches) for
the people who run it. createMcp tools are typed,
RLS-scoped tools over your tables for your app's own users.
Last updated on
Agents
Build a ToolLoopAgent from a stored agent with its tools, approvals and knowledge search, and check input and output with a moderation middleware.
Tenant keys and sandboxes
Send each tenant's own provider keys to the AI Gateway as BYOK, and keep the sandbox registry current while a sandbox runs.