---
title: Give your Supabase app its own MCP server
description: >-
  Every tool call runs as the signed-in user, so the RLS you already wrote
  decides what each agent reaches.
author: 'raul_barroso,gregnr,saxon_fletcher'
date: '2026-10-22'
tags:
  - ai
  - mcp
  - auth
  - edge-functions
categories:
  - product
---
At Supabase Select, we announced a way to give your Supabase app its own MCP server. Your customers can use your app from ChatGPT, Claude, or another MCP client. They sign in with the account they already have. Every tool call runs as that user, so your RLS policies decide what each agent can reach.You expose your app’s actions as tools through the Model Context Protocol (MCP).The [MCP Server block](https://supabase.com/library/docs/headless/mcp) adds the server code to your project. Supabase Auth handles the OAuth flow. Helpers from `@supabase/server` give each tool a Supabase client for the signed-in user. Each tool can be a plain query, with no service role key. You write the tools that fit your app.See it in action in [Greg Richardson’s Select talk](https://www.youtube.com/watch?v=H6R8JT5U5rU). For the broader announcements, read [Build anything: Supabase from code, and an MCP server for your app](https://supabase.com/blog/select-2026-build-anything) and our [Supabase Select 2026 recap](https://supabase.com/blog/supabase-select-2026-recap).## Your app, in your customer’s workflowSay your app turns product photos into video ads. A customer is planning a campaign in Claude. They need their products and the ad tools in your app. Through MCP, their agent can find a product, request an ad, and use the result in the same conversation, alongside their other tools.That’s the flow we showed with Sizzle, a demo app, at Supabase Select. The app uses Supabase Auth, Database, and Storage. Its MCP tools let the customer list their products and generate video ads through an external service. The customer can use those actions from ChatGPT or Claude. [Watch the full demo](https://www.youtube.com/watch?v=H6R8JT5U5rU).## Start with code you ownInstall the MCP Server block from the Supabase Library:```bash
npx shadcn@latest add https://supabase.com/library/r/mcp.json
```The command copies an Edge Function into `supabase/functions/mcp`. It includes the MCP handler, authentication middleware, and a `whoami` tool for checking the caller’s identity. Each tool has its own file, and `tools/index.ts` registers them.You own that code. Add tools for the operations your product supports, change their inputs, and decide what information they return. The block's Library page has a Copy agent prompt button that points your coding agent at the block's docs.The block uses the official MCP TypeScript SDK for the protocol and tool registration. The Supabase helpers handle the connection to Supabase Auth and the user’s client.The Supabase helpers also work in other backends that use standard Web `Request` and `Response` handlers, including Cloudflare Workers, and with other MCP libraries. To reuse logic that runs elsewhere, add the MCP endpoint there and set its public URL and your Supabase Auth URL so clients can find the right Auth server.## Carry the user’s identity into every callThe customer’s agent (the MCP client) starts with your server’s URL. The authentication middleware tells it where to find your project’s OAuth server. The user signs in through your app and approves the client on your consent page. Supabase Auth then issues an access token for that user.Later tool calls carry that token.In the generated function, `handleMcp` is the MCP request handler. The authentication helpers run before it:```ts
import { pipeline } from 'npm:@supabase/middleware@1'
import {
  withOAuthProtectedResource,
  withSupabase,
} from 'npm:@supabase/server@1'

Deno.serve(
  pipeline(
    [
      withOAuthProtectedResource(),
      withSupabase({ auth: 'user' }),
    ],
    handleMcp,
  ),
)
````withOAuthProtectedResource()` tells a client where to sign in. It answers discovery requests and sends an OAuth challenge when a request has no token.`withSupabase({ auth: 'user' })` verifies the token and supplies the handler with the user’s Supabase client. Queries through that client run with the user’s identity, so Postgres applies the table’s RLS policies.The [MCP server guide](https://github.com/supabase/server/blob/main/docs/mcp.md) explains the middleware and request handling in detail.## Write tools around your app’s actionsEach tool module gets the MCP server as `server` and the caller’s Supabase client as `supabase`. `z` is Zod’s schema builder. A tool for an existing RLS-protected `todos` table could list unfinished tasks:```ts
server.registerTool(
  'list_open_tasks',
  {
    description: 'Find up to 20 unfinished tasks for the signed-in user.',
    inputSchema: z.object({}),
    annotations: { readOnlyHint: true },
  },
  async () => {
    const result = await supabase
      .from('todos')
      .select('id, title')
      .eq('done', false)
      .limit(20)

    if (result.error) throw new Error(result.error.message)

    return {
      content: [
        { type: 'text', text: JSON.stringify(result.data) },
      ],
    }
  },
)
```The tool filters by task status. Your [RLS policies](https://supabase.com/docs/guides/database/postgres/row-level-security) decide which rows that user can reach.![A migration that creates an RLS-protected todos table with a policy on auth.uid(), next to the MCP Edge Function whose list_todos tool queries todos as the signed-in user](/images/blog/give-your-supabase-app-its-own-mcp-server/code.png)A tool can also call a database function, invoke an Edge Function, or use an existing application API.Keep business rules in the code the tool calls. For example, an expense might need an approval check. The MCP tool should call the same function your app uses for that check.## Add an interface inside the agentYour MCP tools can show part of your app's UI right in the chat. This uses MCP Apps, an extension to MCP. ChatGPT and other clients that support it display the UI inside the conversation.In the Sizzle demo, a customer asks ChatGPT for one of their products. ChatGPT shows Sizzle's product card with the description and a video player. When the customer asks for a new ad, they watch it render in the same chat.The UI reuses the React components from Sizzle's web app. A separate build bundles them into one HTML file. The Edge Function sends that file with the tool result.If people mainly use your app through an agent, the [Headless App block](https://supabase.com/library/docs/tanstack/headless-app) provides another starting point. It includes a browser flow for sign-in and consent, example task tools, and an RLS-protected database. Users approve access in the browser, then work through their agent.## Get startedTo connect external agents, configure your Supabase project with asymmetric signing keys and turn on the OAuth 2.1 server. Turn on dynamic client registration so compatible clients can register themselves.Add the [OAuth Consent block](https://supabase.com/library/docs/nextjs/oauth-consent) to your frontend so users can approve access. Set your Auth Site URL to the site that hosts the consent page.![An OAuth consent page asking the signed-in user to authorize Claude, showing the client name, redirect URL, and signed-in account, with Deny and Allow access buttons](/images/blog/give-your-supabase-app-its-own-mcp-server/consent.png)The Edge Function verifies tokens in its middleware. Turn off the built-in JWT check so discovery requests without a token can reach it:```toml
[functions.mcp]
verify_jwt = false
```Users connect their agent to the deployed server URL.Follow the [Deploy MCP servers guide](https://supabase.com/docs/guides/ai-tools/byo-mcp#add-authentication) for the full setup, local testing, and deployment steps.
