Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -496,7 +496,7 @@ export const gettingstarted: NavMenuConstant = {
},
{
name: 'Deploy MCP servers',
url: '/guides/getting-started/byom' as `/${string}`,
url: '/guides/getting-started/byo-mcp' as `/${string}`,
},
],
},
Expand Down
44 changes: 44 additions & 0 deletions apps/docs/content/_partials/universal_links_apple.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
### Universal links

For a better user experience, you can use **Universal Links** instead of custom URL schemes. Universal Links allow your app to open directly from web links without showing a browser redirect prompt.

To enable Universal Links, you need to:

1. **Configure Associated Domains** in your Xcode project:

- Add your domain to the Associated Domains capability
- Format: `applinks:yourdomain.com`

2. **Host the Apple App Site Association (AASA) file** on your own infrastructure:
- The file must be accessible at `https://yourdomain.com/.well-known/apple-app-site-association` or `https://yourdomain.com/apple-app-site-association`
- The file must be served with `Content-Type: application/json` (or `text/json`)
- The file must be accessible over HTTPS without redirects
- The file should not have a file extension

<Admonition type="caution">

Supabase does not currently support hosting the AASA file. You must host this file on your own
infrastructure following [Apple's best
practices](https://developer.apple.com/documentation/xcode/supporting-associated-domains).

</Admonition>

The AASA file format should look like this:

```json
{
"applinks": {
"apps": [],
"details": [
{
"appID": "TEAM_ID.BUNDLE_ID",
"paths": ["*"]
}
]
}
}
```

Replace `TEAM_ID` with your Apple Developer Team ID and `BUNDLE_ID` with your app's bundle identifier.

For detailed setup instructions, see [Apple's documentation on supporting associated domains](https://developer.apple.com/documentation/xcode/supporting-associated-domains).
4 changes: 4 additions & 0 deletions apps/docs/content/guides/auth/native-mobile-deep-linking.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,8 @@ With Deep Linking, you can configure this redirect to open a specific page. This

For more info: https://developer.apple.com/documentation/xcode/defining-a-custom-url-scheme-for-your-app

<$Partial path="universal_links_apple.mdx" />

</TabPanel>
<TabPanel id="windows" label="Windows">

Expand Down Expand Up @@ -343,6 +345,8 @@ With Deep Linking, you can configure this redirect to open a specific page. This
</plist>
```

<$Partial path="universal_links_apple.mdx" />

</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -540,7 +540,7 @@ Response:

<Admonition type="note">

For complete API documentation, see the [OAuth Admin API reference](/todo).
For complete API documentation, see the [OAuth Admin API reference](/docs/reference/javascript/auth-admin-oauth-admin).

</Admonition>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ When building your own MCP server, integrate with Supabase Auth to authenticate

**Looking for an easier way to build MCP servers?**

[FastMCP](https://gofastmcp.com) provides a streamlined way to build MCP servers with built-in Supabase Auth integration. FastMCP handles OAuth configuration, token management, and authentication flows automatically, letting you focus on building your AI agent's functionality. Check out their [Supabase integration guide](https://gofastmcp.com/todo) to get started quickly.
[FastMCP](https://gofastmcp.com) provides a streamlined way to build MCP servers with built-in Supabase Auth integration. FastMCP handles OAuth configuration, token management, and authentication flows automatically, letting you focus on building your AI agent's functionality. Check out their [Supabase integration guide](https://gofastmcp.com/integrations/supabase) to get started quickly.

</Admonition>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
---
id: 'ai-tools-byom'
id: 'ai-tools-byo-mcp'
title: 'Deploy MCP servers'
description: 'Build and deploy remote MCP servers on Supabase Edge Functions'
subtitle: 'Deploy custom MCP servers on Supabase Edge Functions'
---

Deploy your [Model Context Protocol](https://modelcontextprotocol.io/specification/2025-11-25) (MCP) servers on Supabase take advantage of features like [Edge Functions](/docs/guides/functions), [OAuth](/docs/guides/auth/oauth-server), and scaling for AI applications.
Build and deploy [Model Context Protocol](https://modelcontextprotocol.io/specification/2025-11-25) (MCP) servers on Supabase using [Edge Functions](/docs/guides/functions).

- Get started with [deploying](#deploy-your-mcp-server) MCP servers on Supabase
<Admonition type="note">

This guide covers MCP servers that do not require authentication. Auth support for MCP on Edge Functions is coming soon.

</Admonition>

## Deploy your MCP server

Expand All @@ -34,17 +37,16 @@ supabase init
Create a new Edge Function for your MCP server:

```bash
supabase functions new simple-mcp-server
supabase functions new mcp
```

Create a `deno.json` file in `supabase/functions/simple-mcp-server/` with the required dependencies:
Create a `deno.json` file in `supabase/functions/mcp/` with the required dependencies:

```json
{
"imports": {
"@hono/mcp": "npm:@hono/mcp@^0.1.1",
"@modelcontextprotocol/sdk": "npm:@modelcontextprotocol/sdk@^1.24.3",
"@modelcontextprotocol/sdk/": "npm:/@modelcontextprotocol/sdk@^1.24.3/",
"hono": "npm:hono@^4.9.2",
"zod": "npm:zod@^4.1.13"
}
Expand All @@ -57,7 +59,7 @@ This tutorial uses the [official MCP TypeScript SDK](https://github.com/modelcon

</Admonition>

Replace the contents of `supabase/functions/simple-mcp-server/index.ts` with:
Replace the contents of `supabase/functions/mcp/index.ts` with:

```ts
// Setup type definitions for built-in Supabase Runtime APIs
Expand All @@ -68,14 +70,13 @@ import { StreamableHTTPTransport } from '@hono/mcp'
import { Hono } from 'hono'
import { z } from 'zod'

// Change this to your function name
const functionName = 'simple-mcp-server'
const app = new Hono().basePath(`/${functionName}`)
// Create Hono app
const app = new Hono()

// Create your MCP server
const server = new McpServer({
name: 'simple-mcp-server',
version: '1.0.0',
name: 'mcp',
version: '0.1.0',
})

// Register a simple addition tool
Expand All @@ -91,8 +92,8 @@ server.registerTool(
})
)

// Handle MCP requests
app.all('/mcp', async (c) => {
// Handle MCP requests at the root path
app.all('/', async (c) => {
const transport = new StreamableHTTPTransport()
await server.connect(transport)
return transport.handleRequest(c)
Expand All @@ -101,52 +102,6 @@ app.all('/mcp', async (c) => {
Deno.serve(app.fetch)
```

### Understanding the code

The MCP server implementation uses several key components:

**Hono routing**: Supabase Edge Functions route all requests to `/<function-name>/*`. The Hono app uses `basePath` to handle this:

```ts
const functionName = 'simple-mcp-server'
const app = new Hono().basePath(`/${functionName}`)
```

**MCP server setup**: The `McpServer` class from the official SDK handles the MCP protocol:

```ts
const server = new McpServer({
name: 'simple-mcp-server',
version: '1.0.0',
})
```

**Tool registration**: Tools are registered with a name, metadata, input schema (using Zod), and a handler function:

```ts
server.registerTool(
'add',
{
title: 'Addition Tool',
description: 'Add two numbers together',
inputSchema: { a: z.number(), b: z.number() },
},
({ a, b }) => ({
content: [{ type: 'text', text: String(a + b) }],
})
)
```

**HTTP transport**: The `StreamableHTTPTransport` from `@hono/mcp` connects your MCP server to HTTP requests:

```ts
app.all('/mcp', async (c) => {
const transport = new StreamableHTTPTransport()
await server.connect(transport)
return transport.handleRequest(c)
})
```

### Local development

Start the Supabase local development stack:
Expand All @@ -158,18 +113,18 @@ supabase start
In a separate terminal, serve your function:

```bash
supabase functions serve --no-verify-jwt simple-mcp-server
supabase functions serve --no-verify-jwt mcp
```

Your MCP server is now running at:

```
http://localhost:54321/functions/v1/simple-mcp-server/mcp
http://localhost:54321/functions/v1/mcp
```

<Admonition type="note">

The `--no-verify-jwt` flag disables JWT verification at the Edge Function layer. This is required because MCP authentication is handled by the MCP server itself, not by Supabase's standard JWT validation.
The `--no-verify-jwt` flag disables JWT verification at the Edge Function layer so your MCP server can accept unauthenticated requests. Authenticated MCP support is coming soon.

</Admonition>

Expand All @@ -181,21 +136,21 @@ Test your server with the official [MCP Inspector](https://github.com/modelconte
npx -y @modelcontextprotocol/inspector
```

Enter your MCP endpoint URL in the inspector UI to explore available tools and test them interactively.
Use the local endpoint `http://localhost:54321/functions/v1/mcp` in the inspector UI to explore available tools and test them interactively.

### Deploy to production

When you're ready to deploy, link your project and deploy the function:

```bash
supabase link --project-ref <your-project-ref>
supabase functions deploy --no-verify-jwt simple-mcp-server
supabase functions deploy --no-verify-jwt mcp
```

Your MCP server will be available at:

```
https://<your-project-ref>.supabase.co/functions/v1/simple-mcp-server/mcp
https://<your-project-ref>.supabase.co/functions/v1/mcp
```

Update your MCP client configuration to use the production URL.
Expand Down Expand Up @@ -240,14 +195,6 @@ server.registerTool(
)
```

## Add authentication

<Admonition type="caution">

MCP authentication is not yet supported on Edge Functions. For now, MCP servers deployed on Supabase Edge Functions are publicly accessible.

</Admonition>

## Examples

You can find ready-to-use MCP server implementations here:
Expand Down
13 changes: 13 additions & 0 deletions apps/docs/content/guides/local-development.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,19 @@ As a prerequisite, you must install a container runtime compatible with Docker A

4. View your local Supabase instance at [http://localhost:54323](http://localhost:54323).

<Admonition type="caution">

If your local development machine is connected to an untrusted public network, you should create a separate docker network and bind to 127.0.0.1 before starting the local development stack. This restricts network access to only your localhost machine.

```sh
docker network create -o 'com.docker.network.bridge.host_binding_ipv4=127.0.0.1' local-network
npx supabase start --network-id local-network
```

You should never expose your local development stack publicly.

</Admonition>

## Local development

Local development with Supabase allows you to work on your projects in a self-contained environment on your local machine. Working locally has several advantages:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
{
"imports": {
"@hono/mcp": "npm:@hono/mcp@^0.1.1",
"@modelcontextprotocol/sdk": "npm:/@modelcontextprotocol/sdk@^1.17.3",
"@modelcontextprotocol/sdk/": "npm:/@modelcontextprotocol/sdk@^1.17.3/",
"@modelcontextprotocol/sdk": "npm:/@modelcontextprotocol/sdk@^1.24.3",
"hono": "npm:hono@^4.9.2",
"zod": "npm:zod@^3.25.76"
"zod": "npm:zod@^4.1.13"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,13 @@ import { StreamableHTTPTransport } from "@hono/mcp";
import { Hono } from "hono";
import { z } from "zod";

// Change this to your function name
const functionName = "simple-mcp-server";
const app = new Hono().basePath(`/${functionName}`);
// Create Hono app
const app = new Hono();

// Create your MCP server
const server = new McpServer({
name: "simple-mcp-server",
version: "1.0.0",
name: "mcp",
version: "0.1.0",
});

// Register a simple addition tool
Expand All @@ -25,8 +24,8 @@ server.registerTool("add", {
content: [{ type: "text", text: String(a + b) }],
}));

// Handle MCP requests
app.all("/mcp", async (c) => {
// Handle MCP requests at the root path
app.all("/", async (c) => {
const transport = new StreamableHTTPTransport();
await server.connect(transport);
return transport.handleRequest(c);
Expand Down
Loading