Skip to content

Commit a1f73e5

Browse files
Rodriguespngithub-actions[bot]ChrisChinchilla
authored
docs: add MCP-lite Edge Functions tutorial (supabase#40004)
* Add Pedro Rodrigues to humans.txt * docs: add MCP-lite Edge Functions tutorial - Add comprehensive tutorial on building MCP servers with mcp-lite on Supabase Edge Functions - Add navigation entries in Examples and Third-Party Tools sections - Based on Fiberplane blog post about mcp-lite and Supabase integration * docs: remove redundant 'supabase init' step from MCP-lite tutorial The template from 'npm create mcp-lite@latest' already initializes Supabase, so this step is not needed. * docs: clarify local development steps for MCP-lite tutorial - Separate 'supabase start' and 'supabase functions serve' into distinct steps - Clarify that npm run dev only serves the function, not starts Supabase - Make it clear these should be run in separate terminals * style: format MCP-lite tutorial with prettier * Update apps/docs/content/guides/functions/examples/mcp-server-mcp-lite.mdx Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Fix rules --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Chris Chinchilla <[email protected]>
1 parent 6d91761 commit a1f73e5

File tree

4 files changed

+311
-0
lines changed

4 files changed

+311
-0
lines changed

apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1639,6 +1639,10 @@ export const functions: NavMenuConstant = {
16391639
name: 'Auth Send Email Hook',
16401640
url: '/guides/functions/examples/auth-send-email-hook-react-email-resend' as `/${string}`,
16411641
},
1642+
{
1643+
name: 'Building an MCP Server with mcp-lite',
1644+
url: '/guides/functions/examples/mcp-server-mcp-lite' as `/${string}`,
1645+
},
16421646
{
16431647
name: 'CORS support for invoking from the browser',
16441648
url: '/guides/functions/cors' as `/${string}`,
@@ -1702,6 +1706,10 @@ export const functions: NavMenuConstant = {
17021706
url: undefined,
17031707
items: [
17041708
{ name: 'Dart Edge on Supabase', url: '/guides/functions/dart-edge' },
1709+
{
1710+
name: 'mcp-lite (Model Context Protocol)',
1711+
url: '/guides/functions/examples/mcp-server-mcp-lite' as `/${string}`,
1712+
},
17051713
{
17061714
name: 'Browserless.io',
17071715
url: '/guides/functions/examples/screenshots' as `/${string}`,
Lines changed: 300 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,300 @@
1+
---
2+
id: 'examples-mcp-server-mcp-lite'
3+
title: 'Building an MCP Server with mcp-lite'
4+
description: 'Build and deploy a Model Context Protocol (MCP) server on Supabase Edge Functions using mcp-lite.'
5+
---
6+
7+
The [Model Context Protocol](https://modelcontextprotocol.io/introduction) (MCP) enables Large Language Models (LLMs) to interact with external tools and data sources. With `mcp-lite`, you can build lightweight MCP servers that run on Supabase Edge Functions, giving your AI assistants the ability to execute custom tools at the edge.
8+
9+
This guide shows you how to scaffold, develop, and deploy an MCP server using mcp-lite on Supabase Edge Functions.
10+
11+
## What is mcp-lite?
12+
13+
[mcp-lite](https://github.com/fiberplane/mcp-lite) is a lightweight, zero-dependency TypeScript framework for building MCP servers. It works everywhere the Fetch API is available, including Node, Bun, Cloudflare Workers, Deno, and Supabase Edge Functions.
14+
15+
## Why Supabase Edge Functions + mcp-lite?
16+
17+
This combination offers several advantages:
18+
19+
- **Zero cold starts**: Edge Functions stay warm for fast responses
20+
- **Global distribution**: Deploy once and run everywhere
21+
- **Direct database access**: Connect directly to your Supabase Postgres
22+
- **Minimal footprint**: mcp-lite has zero runtime dependencies
23+
- **Full type safety**: TypeScript support in Deno
24+
- **Simple deployment**: One command to production
25+
26+
## Prerequisites
27+
28+
You need:
29+
30+
- [Docker](https://docs.docker.com/get-docker/) (to run Supabase locally)
31+
- [Deno](https://deno.land/) (Supabase Edge Functions runtime)
32+
- [Supabase CLI](/docs/guides/cli/getting-started)
33+
34+
## Create a new MCP server
35+
36+
Starting with `[email protected]`, you can scaffold a complete MCP server that runs on Supabase Edge Functions:
37+
38+
```bash
39+
npm create mcp-lite@latest
40+
```
41+
42+
When prompted, select **Supabase Edge Functions (MCP server)** from the template options.
43+
44+
The template creates a focused structure for Edge Functions development:
45+
46+
```
47+
my-mcp-server/
48+
├── supabase/
49+
│ ├── config.toml # Minimal Supabase config (Edge Functions only)
50+
│ └── functions/
51+
│ └── mcp-server/
52+
│ ├── index.ts # MCP server implementation
53+
│ └── deno.json # Deno imports and configuration
54+
├── package.json
55+
└── tsconfig.json
56+
```
57+
58+
## Understanding the project structure
59+
60+
### Minimal config.toml
61+
62+
The template includes a minimal `config.toml` that runs only Edge Functions - no database, storage, or Studio UI. This keeps your local setup lightweight:
63+
64+
```toml
65+
# Minimal config for running only Edge Functions (no DB, storage, or studio)
66+
project_id = "starter-mcp-supabase"
67+
68+
[api]
69+
enabled = true
70+
port = 54321
71+
72+
[edge_runtime]
73+
enabled = true
74+
policy = "per_worker"
75+
deno_version = 2
76+
```
77+
78+
You can always add more services as needed.
79+
80+
### Two Hono apps pattern
81+
82+
The template uses a specific pattern required by Supabase Edge Functions:
83+
84+
```ts
85+
// Root handler - matches the function name
86+
const app = new Hono()
87+
88+
// MCP protocol handler
89+
const mcpApp = new Hono()
90+
91+
mcpApp.get('/', (c) => {
92+
return c.json({
93+
message: 'MCP Server on Supabase Edge Functions',
94+
endpoints: {
95+
mcp: '/mcp',
96+
health: '/health',
97+
},
98+
})
99+
})
100+
101+
mcpApp.all('/mcp', async (c) => {
102+
const response = await httpHandler(c.req.raw)
103+
return response
104+
})
105+
106+
// Mount at /mcp-server (the function name)
107+
app.route('/mcp-server', mcpApp)
108+
```
109+
110+
This is required because Supabase routes all requests to `/<function-name>/*`. The outer `app` handles the function-level routing, while `mcpApp` handles your actual MCP endpoints.
111+
112+
### Deno import maps
113+
114+
The template uses Deno's import maps in `deno.json` to manage dependencies:
115+
116+
```json
117+
{
118+
"compilerOptions": {
119+
"lib": ["deno.window", "deno.ns"],
120+
"strict": true
121+
},
122+
"imports": {
123+
"hono": "npm:hono@^4.6.14",
124+
"mcp-lite": "npm:[email protected]",
125+
"zod": "npm:zod@^4.1.12"
126+
}
127+
}
128+
```
129+
130+
This gives you npm package access while staying in the Deno ecosystem.
131+
132+
## Local development
133+
134+
### Start Supabase
135+
136+
Navigate to your project directory and start Supabase services:
137+
138+
```bash
139+
supabase start
140+
```
141+
142+
### Serve your function
143+
144+
In a separate terminal, serve your MCP function locally:
145+
146+
```bash
147+
supabase functions serve --no-verify-jwt mcp-server
148+
```
149+
150+
Or use the npm script (which runs the same command):
151+
152+
```bash
153+
npm run dev
154+
```
155+
156+
Your MCP server is available at:
157+
158+
```
159+
http://localhost:54321/functions/v1/mcp-server/mcp
160+
```
161+
162+
### Testing your server
163+
164+
Test the MCP server by adding it to your Claude Code, Claude Desktop, Cursor, or your preferred MCP client.
165+
166+
Using Claude Code:
167+
168+
```bash
169+
claude mcp add my-mcp-server -t http http://localhost:54321/functions/v1/mcp-server/mcp
170+
```
171+
172+
You can also test it using the MCP inspector:
173+
174+
```bash
175+
npx @modelcontextprotocol/inspector
176+
```
177+
178+
Then add the MCP endpoint URL in the inspector UI.
179+
180+
## How it works
181+
182+
The MCP server setup is straightforward:
183+
184+
```ts
185+
import { McpServer, StreamableHttpTransport } from 'mcp-lite'
186+
import { z } from 'zod'
187+
188+
// Create MCP server instance
189+
const mcp = new McpServer({
190+
name: 'starter-mcp-supabase-server',
191+
version: '1.0.0',
192+
schemaAdapter: (schema) => z.toJSONSchema(schema as z.ZodType),
193+
})
194+
195+
// Define a tool
196+
mcp.tool('sum', {
197+
description: 'Adds two numbers together',
198+
inputSchema: z.object({
199+
a: z.number(),
200+
b: z.number(),
201+
}),
202+
handler: (args: { a: number; b: number }) => ({
203+
content: [{ type: 'text', text: String(args.a + args.b) }],
204+
}),
205+
})
206+
207+
// Bind to HTTP transport
208+
const transport = new StreamableHttpTransport()
209+
const httpHandler = transport.bind(mcp)
210+
```
211+
212+
## Adding more tools
213+
214+
Extend your MCP server by adding tools directly to the `mcp` instance. Here's an example of adding a database search tool:
215+
216+
```ts
217+
mcp.tool('searchDatabase', {
218+
description: 'Search your Supabase database',
219+
inputSchema: z.object({
220+
table: z.string(),
221+
query: z.string(),
222+
}),
223+
handler: async (args) => {
224+
// Access Supabase client here
225+
// const { data } = await supabase.from(args.table).select('*')
226+
return {
227+
content: [{ type: 'text', text: `Searching ${args.table}...` }],
228+
}
229+
},
230+
})
231+
```
232+
233+
You can add tools that:
234+
235+
- Query your Supabase database
236+
- Access Supabase Storage for file operations
237+
- Call external APIs
238+
- Process data with custom logic
239+
- Integrate with other Supabase features
240+
241+
## Deploy to production
242+
243+
When ready, deploy to Supabase's global edge network:
244+
245+
```bash
246+
supabase functions deploy --no-verify-jwt mcp-server
247+
```
248+
249+
Or use the npm script:
250+
251+
```bash
252+
npm run deploy
253+
```
254+
255+
Your MCP server will be live at:
256+
257+
```
258+
https://your-project-ref.supabase.co/functions/v1/mcp-server/mcp
259+
```
260+
261+
## Authentication considerations
262+
263+
<Admonition type="caution">
264+
265+
The template uses `--no-verify-jwt` for quick development. This means authentication is not enforced by Supabase's JWT layer.
266+
267+
For production, you should implement authentication at the MCP server level following the [MCP Authorization specification](https://modelcontextprotocol.io/specification/draft/basic/authorization). This gives you control over who can access your MCP tools.
268+
269+
</Admonition>
270+
271+
### Security best practices
272+
273+
When deploying MCP servers:
274+
275+
- **Don't expose sensitive data**: Use the server in development environments with non-production data
276+
- **Implement authentication**: Add proper authentication for production deployments
277+
- **Validate inputs**: Always validate and sanitize tool inputs
278+
- **Limit tool scope**: Only expose tools that are necessary for your use case
279+
- **Monitor usage**: Track tool calls and monitor for unusual activity
280+
281+
For more security guidance, see the [MCP security guide](/guides/getting-started/mcp#security-risks).
282+
283+
## What's next
284+
285+
With your MCP server running on Supabase Edge Functions, you can:
286+
287+
- Connect it to your Supabase database for data-driven tools
288+
- Use Supabase Auth to secure your endpoints
289+
- Access Supabase Storage for file operations
290+
- Deploy to multiple regions automatically
291+
- Scale to handle production traffic
292+
- Integrate with AI assistants like Claude, Cursor, or custom MCP clients
293+
294+
## Resources
295+
296+
- [mcp-lite on GitHub](https://github.com/fiberplane/mcp-lite)
297+
- [Model Context Protocol Spec](https://modelcontextprotocol.io/)
298+
- [Supabase Edge Functions Docs](/guides/functions)
299+
- [Deno Runtime Documentation](https://deno.land/)
300+
- [Fiberplane tutorial](https://blog.fiberplane.com/blog/mcp-lite-supabase-edge-functions/)

supa-mdx-lint/Rule001HeadingCase.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ may_uppercase = [
9292
"GraphQL",
9393
"Heroku",
9494
"Homebrew",
95+
"Hono",
9596
"Hooks?",
9697
"Hours",
9798
"Hugging Face",

supa-mdx-lint/Rule003Spelling.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ allow_list = [
7676
"[Ll]iveness",
7777
"LogEvent",
7878
"[Mm]atryoshka",
79+
"[Mm][Cc][Pp]",
7980
"[Mm]essageBird",
8081
"MetaMask",
8182
"[Mm]icroservices?",
@@ -177,6 +178,7 @@ allow_list = [
177178
"Erlang",
178179
"ESZip",
179180
"Ethereum",
181+
"Fiberplane",
180182
"Figma",
181183
"Firestore",
182184
"Fivetran",

0 commit comments

Comments
 (0)