Skip to content
Merged
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
24 changes: 23 additions & 1 deletion extensions/cli/src/services/MCPService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -503,11 +503,33 @@
} catch (error: unknown) {
// If token refresh didn't work and it's a 401, fall back to mcp-remote
if (isAuthError(error) && !this.isHeadless) {
// Build mcp-remote args with Supabase-specific OAuth scopes if needed
const mcpRemoteArgs = ["-y", "mcp-remote", serverConfig.url];

// Detect Supabase MCP and add custom OAuth scopes
if (serverConfig.url.includes("mcp.supabase.com")) {

Check failure

Code scanning / CodeQL

Incomplete URL substring sanitization High

'
mcp.supabase.com
' can be anywhere in the URL, and arbitrary hosts may come before or after it.

Copilot Autofix

AI 23 days ago

To robustly determine whether serverConfig.url points to a valid Supabase MCP host, we should parse the URL and examine its hostname component, ensuring that it is either exactly mcp.supabase.com or perhaps (if required) a known set of subdomains. This avoids false positives from substring matching on path, query, or other unrelated parts of the URL.

The best fix is to replace serverConfig.url.includes("mcp.supabase.com") with a check like new URL(serverConfig.url).hostname === "mcp.supabase.com". This change should be made at line 510. Since we're writing TypeScript/Node, the global URL class can be safely used. If for any reason we suspect serverConfig.url might not be a valid URL, a try/catch could be added for resilience, but assuming well-formed input for now is reasonable.

No new imports are needed because URL is available in modern Node environments.


Suggested changeset 1
extensions/cli/src/services/MCPService.ts

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/extensions/cli/src/services/MCPService.ts b/extensions/cli/src/services/MCPService.ts
--- a/extensions/cli/src/services/MCPService.ts
+++ b/extensions/cli/src/services/MCPService.ts
@@ -507,8 +507,9 @@
           const mcpRemoteArgs = ["-y", "mcp-remote", serverConfig.url];
 
           // Detect Supabase MCP and add custom OAuth scopes
-          if (serverConfig.url.includes("mcp.supabase.com")) {
-            const supabaseScopes = [
+          try {
+            if (new URL(serverConfig.url).hostname === "mcp.supabase.com") {
+              const supabaseScopes = [
               "organizations:read",
               "projects:read",
               "database:read",
@@ -519,10 +520,13 @@
               "storage:read",
             ].join(" ");
 
-            mcpRemoteArgs.push(
-              "--static-oauth-client-metadata",
-              JSON.stringify({ scope: supabaseScopes }),
-            );
+              mcpRemoteArgs.push(
+                "--static-oauth-client-metadata",
+                JSON.stringify({ scope: supabaseScopes }),
+              );
+            }
+          } catch (e) {
+            logger.warn(`[MCPService] Failed to parse URL '${serverConfig.url}': ${e}`);
           }
 
           const transport = this.constructStdioTransport(
EOF
@@ -507,8 +507,9 @@
const mcpRemoteArgs = ["-y", "mcp-remote", serverConfig.url];

// Detect Supabase MCP and add custom OAuth scopes
if (serverConfig.url.includes("mcp.supabase.com")) {
const supabaseScopes = [
try {
if (new URL(serverConfig.url).hostname === "mcp.supabase.com") {
const supabaseScopes = [
"organizations:read",
"projects:read",
"database:read",
@@ -519,10 +520,13 @@
"storage:read",
].join(" ");

mcpRemoteArgs.push(
"--static-oauth-client-metadata",
JSON.stringify({ scope: supabaseScopes }),
);
mcpRemoteArgs.push(
"--static-oauth-client-metadata",
JSON.stringify({ scope: supabaseScopes }),
);
}
} catch (e) {
logger.warn(`[MCPService] Failed to parse URL '${serverConfig.url}': ${e}`);
}

const transport = this.constructStdioTransport(
Copilot is powered by AI and may make mistakes. Always verify output.
const supabaseScopes = [
"organizations:read",
"projects:read",
"database:read",
"analytics:read",
"secrets:read",
"edge_functions:read",
"environment:read",
"storage:read",
].join(" ");

mcpRemoteArgs.push(
"--static-oauth-client-metadata",
JSON.stringify({ scope: supabaseScopes }),
);
}

const transport = this.constructStdioTransport(
{
name: serverConfig.name,
command: "npx",
args: ["-y", "mcp-remote", serverConfig.url],
args: mcpRemoteArgs,
},
connection,
);
Expand Down
Loading