diff --git a/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts b/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts index ae10e996a5301..05951f0b0cabd 100644 --- a/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts +++ b/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts @@ -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}`, }, ], }, diff --git a/apps/docs/content/_partials/universal_links_apple.mdx b/apps/docs/content/_partials/universal_links_apple.mdx new file mode 100644 index 0000000000000..ef9ada6753b17 --- /dev/null +++ b/apps/docs/content/_partials/universal_links_apple.mdx @@ -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 + + + +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). + + + +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). diff --git a/apps/docs/content/guides/auth/native-mobile-deep-linking.mdx b/apps/docs/content/guides/auth/native-mobile-deep-linking.mdx index 6d2155e9e64b3..797a8094bc417 100644 --- a/apps/docs/content/guides/auth/native-mobile-deep-linking.mdx +++ b/apps/docs/content/guides/auth/native-mobile-deep-linking.mdx @@ -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" /> + @@ -343,6 +345,8 @@ With Deep Linking, you can configure this redirect to open a specific page. This ``` + <$Partial path="universal_links_apple.mdx" /> + <$Show if="sdk:kotlin"> diff --git a/apps/docs/content/guides/auth/oauth-server/getting-started.mdx b/apps/docs/content/guides/auth/oauth-server/getting-started.mdx index fbcdbcd1694e9..e9033142c1fd3 100644 --- a/apps/docs/content/guides/auth/oauth-server/getting-started.mdx +++ b/apps/docs/content/guides/auth/oauth-server/getting-started.mdx @@ -540,7 +540,7 @@ Response: -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). diff --git a/apps/docs/content/guides/auth/oauth-server/mcp-authentication.mdx b/apps/docs/content/guides/auth/oauth-server/mcp-authentication.mdx index 4e5406357f750..592d9eff3e4fe 100644 --- a/apps/docs/content/guides/auth/oauth-server/mcp-authentication.mdx +++ b/apps/docs/content/guides/auth/oauth-server/mcp-authentication.mdx @@ -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. diff --git a/apps/docs/content/guides/getting-started/byom.mdx b/apps/docs/content/guides/getting-started/byo-mcp.mdx similarity index 62% rename from apps/docs/content/guides/getting-started/byom.mdx rename to apps/docs/content/guides/getting-started/byo-mcp.mdx index 69e6de4d4c24e..60251952cc0f0 100644 --- a/apps/docs/content/guides/getting-started/byom.mdx +++ b/apps/docs/content/guides/getting-started/byo-mcp.mdx @@ -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 + + +This guide covers MCP servers that do not require authentication. Auth support for MCP on Edge Functions is coming soon. + + ## Deploy your MCP server @@ -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" } @@ -57,7 +59,7 @@ This tutorial uses the [official MCP TypeScript SDK](https://github.com/modelcon -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 @@ -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 @@ -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) @@ -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 `//*`. 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: @@ -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 ``` -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. @@ -181,7 +136,7 @@ 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 @@ -189,13 +144,13 @@ When you're ready to deploy, link your project and deploy the function: ```bash supabase link --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://.supabase.co/functions/v1/simple-mcp-server/mcp +https://.supabase.co/functions/v1/mcp ``` Update your MCP client configuration to use the production URL. @@ -240,14 +195,6 @@ server.registerTool( ) ``` -## Add authentication - - - -MCP authentication is not yet supported on Edge Functions. For now, MCP servers deployed on Supabase Edge Functions are publicly accessible. - - - ## Examples You can find ready-to-use MCP server implementations here: diff --git a/apps/docs/content/guides/local-development.mdx b/apps/docs/content/guides/local-development.mdx index 8545ceb17685a..872f486567e2e 100644 --- a/apps/docs/content/guides/local-development.mdx +++ b/apps/docs/content/guides/local-development.mdx @@ -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). + + +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. + + + ## 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: diff --git a/examples/edge-functions/supabase/functions/mcp/simple-mcp-server/deno.json b/examples/edge-functions/supabase/functions/mcp/simple-mcp-server/deno.json index 7233c5f1d1a70..a56b7f4e018dc 100644 --- a/examples/edge-functions/supabase/functions/mcp/simple-mcp-server/deno.json +++ b/examples/edge-functions/supabase/functions/mcp/simple-mcp-server/deno.json @@ -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" } } diff --git a/examples/edge-functions/supabase/functions/mcp/simple-mcp-server/index.ts b/examples/edge-functions/supabase/functions/mcp/simple-mcp-server/index.ts index 7676f61ad25f0..e5cc7c7e178ea 100644 --- a/examples/edge-functions/supabase/functions/mcp/simple-mcp-server/index.ts +++ b/examples/edge-functions/supabase/functions/mcp/simple-mcp-server/index.ts @@ -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 @@ -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);