From 0f618d8efbd64063cce4fc99df2c97ab32a38ec7 Mon Sep 17 00:00:00 2001 From: Alex Gercog Date: Wed, 14 Oct 2026 19:19:04 +0700 Subject: [PATCH] fix(mcp): use native HTTP for Devin MCP connections (#51646) ## Problem The Devin Desktop preset wraps Supabase MCP URLs in `npx -y mcp-remote`, although Devin Local and Devin CLI support Streamable HTTP natively. Connecting therefore adds a Node/npm bridge that the client does not need. The preset also lacks Devin-specific setup and authentication instructions. ## Solution Use the existing native `url` configuration for Devin: ```json { "mcpServers": { "supabase": { "url": "https://mcp.supabase.com/mcp" } } } ``` The generated URL retains the selected project, read-only mode, and features. The internal `windsurf` key is preserved. Add shared setup instructions for the configuration panel and generated Markdown: user-scope installation, the Windows config file location next to the shared macOS/Linux one, a re-authentication command for hosted connections, and loading tools in a new Devin Local or CLI session. Local connections omit the re-authentication step. Include Devin in the shared client URL round-trip test. The Devin-only test files from the first revision were removed in review so that tests stay shared across clients. Native configuration follows the official [Devin MCP documentation](https://docs.devin.ai/cli/extensibility/mcp/configuration) and [Devin Local integration](https://docs.devin.ai/desktop/devin-local). ## Validation - **273 tests passed** across 28 `ui-patterns` test files on the current revision; 34 of them in the MCP section. - Package typechecking, Prettier on the four changed files, and `git diff --check` passed. - **Devin CLI 3000.11.3:** native HTTP initialization and tool discovery; synthetic OAuth with S256 PKCE and authenticated tool discovery using a saved token. - **Devin Desktop 3.10.48 / bundled Devin Local 3000.10.48:** the server card showed `Connected` and the fixture tool. Its `tools/list` request came from the bundled Devin Local process. OAuth validation used controlled local fixtures; live Supabase Hosted authorization was not exercised. The full monorepo application build was not run. ## Review instructions 1. Run `pnpm --filter ui-patterns exec vitest run src/McpUrlBuilder` and `pnpm --filter ui-patterns typecheck`. 2. Select **Devin Desktop** in the MCP configuration panel. Confirm that the JSON uses `url` and preserves the selected project, read-only mode, and features. 3. Switch to the local connection. Confirm that Hosted login instructions disappear. Check that generated Markdown explicitly limits that login step to Hosted connections. ## Checklist - [x] I have read [CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md) - [ ] If I wrote a new docs topic or edited an existing topic, I used the `/write-the-docs` or `/edit-the-docs` skill, which applies the docs [style guide](https://github.com/supabase/supabase/tree/master/apps/docs/style-guide). N/A: no docs topic edited; the change is in the shared MCP configuration component and its generated instructions. --- .../src/McpUrlBuilder/clients.data.ts | 17 +++------- .../McpUrlBuilder/clients.instructions.md.tsx | 33 +++++++++++++++++++ .../src/McpUrlBuilder/types.test.ts | 24 +++++--------- .../ui-patterns/src/McpUrlBuilder/types.ts | 10 ------ 4 files changed, 46 insertions(+), 38 deletions(-) diff --git a/packages/ui-patterns/src/McpUrlBuilder/clients.data.ts b/packages/ui-patterns/src/McpUrlBuilder/clients.data.ts index c27fb187395..2c6e6c20969 100644 --- a/packages/ui-patterns/src/McpUrlBuilder/clients.data.ts +++ b/packages/ui-patterns/src/McpUrlBuilder/clients.data.ts @@ -16,7 +16,6 @@ import type { OmpMcpConfig, OpenCodeMcpConfig, VSCodeMcpConfig, - WindsurfMcpConfig, } from './types' import { getMcpUrl } from './types' @@ -248,17 +247,7 @@ export const MCP_CLIENT_DATA: McpClientData[] = [ icon: 'devin', hasDistinctDarkIcon: true, configFile: '~/.config/devin/mcp_config.json', - externalDocsUrl: '', - transformConfig: (config): WindsurfMcpConfig => { - return { - mcpServers: { - supabase: { - command: 'npx', - args: ['-y', 'mcp-remote', config.mcpServers.supabase.url], - }, - }, - } - }, + externalDocsUrl: 'https://docs.devin.ai/cli/extensibility/mcp/configuration', }, { key: 'warp', @@ -441,6 +430,10 @@ export const MCP_CLI_COMMANDS: Record = { install: (url) => `copilot mcp add --transport http supabase "${url}"`, authenticate: 'copilot -i /mcp', }, + windsurf: { + install: (url) => `devin mcp add -s user supabase "${url}"`, + authenticate: 'devin mcp login supabase', + }, goose: { install: (url) => `goose session --with-streamable-http-extension "${url}"`, }, diff --git a/packages/ui-patterns/src/McpUrlBuilder/clients.instructions.md.tsx b/packages/ui-patterns/src/McpUrlBuilder/clients.instructions.md.tsx index e59a51c558c..babf6a1e36c 100644 --- a/packages/ui-patterns/src/McpUrlBuilder/clients.instructions.md.tsx +++ b/packages/ui-patterns/src/McpUrlBuilder/clients.instructions.md.tsx @@ -210,6 +210,39 @@ export const MCP_CLIENT_INSTRUCTIONS: Record = { ), }, + windsurf: { + primary: ({ url }) => ( + <> + + These instructions use the Devin Local agent in Devin Desktop or Devin CLI. Add the + Supabase MCP server to your user configuration: + + + + ), + alternate: ({ isPlatform }) => ( + <> + + On Windows, the configuration file is{' '} + instead. + + {isPlatform && ( + <> + + If you skipped the browser sign-in or need to re-authenticate, run: + + + Complete the authorization flow in your browser. + + )} + Check the server configuration: + + + Start a new Devin Local or Devin CLI session to load the server's tools. + + + ), + }, goose: { primary: ({ url }) => ( <> diff --git a/packages/ui-patterns/src/McpUrlBuilder/types.test.ts b/packages/ui-patterns/src/McpUrlBuilder/types.test.ts index e7e8183b555..5e4a8cbf75e 100644 --- a/packages/ui-patterns/src/McpUrlBuilder/types.test.ts +++ b/packages/ui-patterns/src/McpUrlBuilder/types.test.ts @@ -5,22 +5,14 @@ import { getMcpUrl, type McpClientBaseConfig } from './types' const SERVER_URL = 'https://mcp.supabase.com/mcp?project_ref=abc123&read_only=true' -/** - * `windsurf` configures a stdio `mcp-remote` command that carries the URL in `args`, so its - * config has no URL field to read back. It renders no instructions and no deep link, so it - * never reaches `getMcpUrl`. - */ -const CLIENTS_WITHOUT_URL_IN_CONFIG = new Set(['windsurf']) - describe('getMcpUrl', () => { - it.each( - MCP_CLIENT_DATA.filter((client) => !CLIENTS_WITHOUT_URL_IN_CONFIG.has(client.key)).map( - (client) => [client.key, client] as const - ) - )('reads the server URL back out of the %s config', (_key, client) => { - const base: McpClientBaseConfig = { mcpServers: { supabase: { url: SERVER_URL } } } - const config = client.transformConfig ? client.transformConfig(base) : base + it.each(MCP_CLIENT_DATA.map((client) => [client.key, client] as const))( + 'reads the server URL back out of the %s config', + (_key, client) => { + const base: McpClientBaseConfig = { mcpServers: { supabase: { url: SERVER_URL } } } + const config = client.transformConfig ? client.transformConfig(base) : base - expect(getMcpUrl(config)).toBe(SERVER_URL) - }) + expect(getMcpUrl(config)).toBe(SERVER_URL) + } + ) }) diff --git a/packages/ui-patterns/src/McpUrlBuilder/types.ts b/packages/ui-patterns/src/McpUrlBuilder/types.ts index 89daf506c3d..e80c3b6e641 100644 --- a/packages/ui-patterns/src/McpUrlBuilder/types.ts +++ b/packages/ui-patterns/src/McpUrlBuilder/types.ts @@ -64,15 +64,6 @@ export interface VSCodeMcpConfig { } } -export interface WindsurfMcpConfig { - mcpServers: { - supabase: { - command: 'npx' - args: ['-y', 'mcp-remote', string] - } - } -} - export interface ClaudeCodeMcpConfig extends McpClientBaseConfig { mcpServers: { supabase: { @@ -247,7 +238,6 @@ export type McpClientConfig = | OpenCodeMcpConfig | OtherMcpConfig | VSCodeMcpConfig - | WindsurfMcpConfig // Type guards export function isVSCodeMcpConfig(config: McpClientConfig): config is VSCodeMcpConfig {