diff --git a/.gitignore b/.gitignore index 48d58ae1ad0..7c354e17573 100644 --- a/.gitignore +++ b/.gitignore @@ -168,3 +168,6 @@ keys.json examples/**/package-lock.json examples/**/yarn.lock examples/**/pnpm-lock.yaml + +# local-only lockfile for the mcp-server registry block +apps/ui-library/registry/default/blocks/mcp-server/supabase/functions/mcp-server/deno.lock diff --git a/apps/ui-library/public/r/mcp-server.json b/apps/ui-library/public/r/mcp-server.json index d0a1b02387b..cf28c1d344c 100644 --- a/apps/ui-library/public/r/mcp-server.json +++ b/apps/ui-library/public/r/mcp-server.json @@ -7,7 +7,7 @@ "files": [ { "path": "registry/default/blocks/mcp-server/supabase/functions/mcp-server/index.ts", - "content": "import 'jsr:@supabase/functions-js@2.108.2/edge-runtime.d.ts'\n\nimport { createMcpHandler, McpServer } from 'npm:@modelcontextprotocol/server@2.0.0'\nimport {\n withOAuthProtectedResource,\n withSupabase,\n type SupabaseContext,\n} from 'npm:@supabase/server@1.5.1'\n\nimport { registerTools, type ToolContext } from './tools/index.ts'\n\n// An MCP server as a single Supabase Edge Function. withSupabase accepts any\n// verified user access token and builds an RLS-scoped client, so both embedded\n// product agents and external OAuth clients can act as the signed-in user.\n//\n// withOAuthProtectedResource adds OAuth discovery for external MCP clients and\n// points authentication failures at it. Tools are composed in ./tools/index.ts.\n\nfunction readTextEnv(name: string, fallback: string): string {\n return Deno.env.get(name)?.trim() || fallback\n}\n\nconst SERVER_NAME = readTextEnv('MCP_SERVER_NAME', 'supabase-mcp')\nconst SERVER_DESCRIPTION = readTextEnv(\n 'MCP_SERVER_DESCRIPTION',\n 'MCP access to this Supabase project for the signed-in user.'\n)\n\nconst SERVER_INSTRUCTIONS =\n `${SERVER_DESCRIPTION} ` +\n 'Every tool runs as the signed-in Supabase user, so role grants and Row Level Security apply. ' +\n \"Call tools/list to discover what this project exposes, and read a tool's description and \" +\n 'annotations before calling it — some tools have side effects.'\n\nconst CORS_HEADERS: Record = {\n 'Access-Control-Allow-Origin': '*',\n 'Access-Control-Allow-Methods': 'GET, POST, DELETE, OPTIONS',\n 'Access-Control-Allow-Headers':\n 'Authorization, Content-Type, Accept, Mcp-Protocol-Version, Mcp-Session-Id, Mcp-Method, Mcp-Name',\n 'Access-Control-Expose-Headers': 'WWW-Authenticate, Mcp-Session-Id',\n}\n\nfunction createServer(context: ToolContext): McpServer {\n const server = new McpServer(\n { name: SERVER_NAME, version: '1.0.0' },\n { instructions: SERVER_INSTRUCTIONS }\n )\n\n registerTools(server, context)\n return server\n}\n\nasync function handleMcp(request: Request, ctx: SupabaseContext): Promise {\n // The server and its tools are bound to this caller for exactly one request.\n const handler = createMcpHandler(\n () =>\n createServer({\n supabase: ctx.supabase,\n // auth: 'user' guarantees both claim shapes before this handler runs.\n userClaims: ctx.userClaims!,\n jwtClaims: ctx.jwtClaims!,\n }),\n { onerror: (error) => console.error('MCP request failed', error) }\n )\n\n return handler.fetch(request)\n}\n\nDeno.serve(\n withOAuthProtectedResource(\n withSupabase({ auth: 'user', cors: { headers: CORS_HEADERS } }, handleMcp)\n )\n)\n", + "content": "import 'jsr:@supabase/functions-js@2.108.2/edge-runtime.d.ts'\n\nimport { createMcpHandler, McpServer } from 'npm:@modelcontextprotocol/server@2.0.0'\nimport {\n withOAuthProtectedResource,\n withSupabase,\n type SupabaseContext,\n} from 'npm:@supabase/server@1.6.0'\n\nimport { registerTools, type ToolContext } from './tools/index.ts'\n\n// An MCP server as a single Supabase Edge Function. withSupabase accepts any\n// verified user access token and builds an RLS-scoped client, so both embedded\n// product agents and external OAuth clients can act as the signed-in user.\n//\n// withOAuthProtectedResource adds OAuth discovery for external MCP clients and\n// points authentication failures at it. Tools are composed in ./tools/index.ts.\n\nfunction readTextEnv(name: string, fallback: string): string {\n return Deno.env.get(name)?.trim() || fallback\n}\n\nconst SERVER_NAME = readTextEnv('MCP_SERVER_NAME', 'supabase-mcp')\nconst SERVER_DESCRIPTION = readTextEnv(\n 'MCP_SERVER_DESCRIPTION',\n 'MCP access to this Supabase project for the signed-in user.'\n)\n\nconst SERVER_INSTRUCTIONS =\n `${SERVER_DESCRIPTION} ` +\n 'Every tool runs as the signed-in Supabase user, so role grants and Row Level Security apply. ' +\n \"Call tools/list to discover what this project exposes, and read a tool's description and \" +\n 'annotations before calling it — some tools have side effects.'\n\nconst CORS_HEADERS: Record = {\n 'Access-Control-Allow-Origin': '*',\n 'Access-Control-Allow-Methods': 'GET, POST, DELETE, OPTIONS',\n 'Access-Control-Allow-Headers':\n 'Authorization, Content-Type, Accept, Mcp-Protocol-Version, Mcp-Session-Id, Mcp-Method, Mcp-Name',\n 'Access-Control-Expose-Headers': 'WWW-Authenticate, Mcp-Session-Id',\n}\n\nfunction createServer(context: ToolContext): McpServer {\n const server = new McpServer(\n { name: SERVER_NAME, version: '1.0.0' },\n { instructions: SERVER_INSTRUCTIONS }\n )\n\n registerTools(server, context)\n return server\n}\n\nasync function handleMcp(request: Request, ctx: SupabaseContext): Promise {\n // The server and its tools are bound to this caller for exactly one request.\n const handler = createMcpHandler(\n () =>\n createServer({\n supabase: ctx.supabase,\n // auth: 'user' guarantees both claim shapes before this handler runs.\n userClaims: ctx.userClaims!,\n jwtClaims: ctx.jwtClaims!,\n }),\n { onerror: (error) => console.error('MCP request failed', error) }\n )\n\n return handler.fetch(request)\n}\n\nDeno.serve(\n withOAuthProtectedResource(\n withSupabase({ auth: 'user', cors: { headers: CORS_HEADERS } }, handleMcp)\n )\n)\n", "type": "registry:file", "target": "supabase/functions/mcp-server/index.ts" }, @@ -25,7 +25,7 @@ }, { "path": "registry/default/blocks/mcp-server/supabase/functions/mcp-server/tools/types.ts", - "content": "import type { SupabaseContext } from 'npm:@supabase/server@1.5.1'\nimport type { SupabaseClient } from 'npm:@supabase/supabase-js@2.108.2'\n\n// Only expose the user-scoped client and verified identity to tools. Keeping\n// supabaseAdmin out of this type makes bypassing RLS an explicit design choice.\nexport type ToolContext = {\n supabase: SupabaseClient\n userClaims: NonNullable\n jwtClaims: NonNullable\n}\n", + "content": "import type { SupabaseContext } from 'npm:@supabase/server@1.6.0'\nimport type { SupabaseClient } from 'npm:@supabase/supabase-js@2.108.2'\n\n// Only expose the user-scoped client and verified identity to tools. Keeping\n// supabaseAdmin out of this type makes bypassing RLS an explicit design choice.\nexport type ToolContext = {\n supabase: SupabaseClient\n userClaims: NonNullable\n jwtClaims: NonNullable\n}\n", "type": "registry:file", "target": "supabase/functions/mcp-server/tools/types.ts" }, diff --git a/apps/ui-library/registry/default/blocks/mcp-server/supabase/functions/mcp-server/index.ts b/apps/ui-library/registry/default/blocks/mcp-server/supabase/functions/mcp-server/index.ts index 95278a36be2..b9e1b1b3d79 100644 --- a/apps/ui-library/registry/default/blocks/mcp-server/supabase/functions/mcp-server/index.ts +++ b/apps/ui-library/registry/default/blocks/mcp-server/supabase/functions/mcp-server/index.ts @@ -5,7 +5,7 @@ import { withOAuthProtectedResource, withSupabase, type SupabaseContext, -} from 'npm:@supabase/server@1.5.1' +} from 'npm:@supabase/server@1.6.0' import { registerTools, type ToolContext } from './tools/index.ts' diff --git a/apps/ui-library/registry/default/blocks/mcp-server/supabase/functions/mcp-server/tools/types.ts b/apps/ui-library/registry/default/blocks/mcp-server/supabase/functions/mcp-server/tools/types.ts index e88542238b5..3118a59eeb4 100644 --- a/apps/ui-library/registry/default/blocks/mcp-server/supabase/functions/mcp-server/tools/types.ts +++ b/apps/ui-library/registry/default/blocks/mcp-server/supabase/functions/mcp-server/tools/types.ts @@ -1,4 +1,4 @@ -import type { SupabaseContext } from 'npm:@supabase/server@1.5.1' +import type { SupabaseContext } from 'npm:@supabase/server@1.6.0' import type { SupabaseClient } from 'npm:@supabase/supabase-js@2.108.2' // Only expose the user-scoped client and verified identity to tools. Keeping