From a392085d7e628d763f588a572679c60eca198dd3 Mon Sep 17 00:00:00 2001 From: JustYannicc <52761674+JustYannicc@users.noreply.github.com> Date: Thu, 11 Sep 2025 16:08:18 +0200 Subject: [PATCH 1/2] Allow local MCP without login --- src/cli/mcp.ts | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/cli/mcp.ts b/src/cli/mcp.ts index 97d14541..f247c312 100644 --- a/src/cli/mcp.ts +++ b/src/cli/mcp.ts @@ -110,14 +110,17 @@ function makeServer(options: McpOptions) { const ctx = new RequestContext(options); await initializeBigBrainAuth(ctx, options); try { - const authorized = await checkAuthorization(ctx, false); - if (!authorized) { - await ctx.crash({ - exitCode: 1, - errorType: "fatal", - printedMessage: - "Not Authorized: Run `npx convex dev` to login to your Convex project.", - }); + const auth = ctx.bigBrainAuth(); + if (auth !== null) { + const authorized = await checkAuthorization(ctx, false); + if (!authorized) { + await ctx.crash({ + exitCode: 1, + errorType: "fatal", + printedMessage: + "Not Authorized: Run `npx convex dev` to login to your Convex project.", + }); + } } if (!request.params.arguments) { await ctx.crash({ From 136561ebf4f27b85a7891b6325794dcb4dec7a72 Mon Sep 17 00:00:00 2001 From: JustYannicc <52761674+JustYannicc@users.noreply.github.com> Date: Tue, 30 Sep 2025 15:22:51 +0200 Subject: [PATCH 2/2] Fix MCP local deployment selection --- src/cli/lib/api.ts | 22 +++++------ src/cli/lib/localDeployment/run.ts | 62 +++++++++++++++++++----------- 2 files changed, 48 insertions(+), 36 deletions(-) diff --git a/src/cli/lib/api.ts b/src/cli/lib/api.ts index 2167eb2e..17c3472c 100644 --- a/src/cli/lib/api.ts +++ b/src/cli/lib/api.ts @@ -249,7 +249,7 @@ export async function checkAccessToSelectedProject( } } -export async function getTeamAndProjectSlugForDeployment( +async function getTeamAndProjectSlugForDeployment( ctx: Context, selector: { deploymentName: string }, ): Promise<{ teamSlug: string; projectSlug: string } | null> { @@ -600,7 +600,14 @@ async function _loadExistingDeploymentCredentialsForProject( teamSlug: string | null; } | null; }> { - const accessResult = await checkAccessToSelectedProject(ctx, targetProject); + // Avoid BigBrain access checks for explicitly local deployments. + // These are self-contained and shouldn't require cloud auth. + const skipAccessCheck = + targetProject.kind === "deploymentName" && + targetProject.deploymentType === "local"; + const accessResult = skipAccessCheck + ? ({ kind: "unknown" } as const) + : await checkAccessToSelectedProject(ctx, targetProject); if (accessResult.kind === "noAccess") { return await ctx.crash({ exitCode: 1, @@ -810,14 +817,3 @@ export async function fetchTeamAndProjectForKey( return data; } - -export async function getTeamsForUser(ctx: Context) { - const teams = await bigBrainAPI<{ id: number; name: string; slug: string }[]>( - { - ctx, - method: "GET", - url: "teams", - }, - ); - return teams; -} diff --git a/src/cli/lib/localDeployment/run.ts b/src/cli/lib/localDeployment/run.ts index 8a0e164c..89a13d8b 100644 --- a/src/cli/lib/localDeployment/run.ts +++ b/src/cli/lib/localDeployment/run.ts @@ -143,34 +143,50 @@ export async function assertLocalBackendRunning( deploymentName: string; }, ): Promise { - logVerbose(`Checking local backend at ${args.url} is running`); + const candidates: string[] = []; + const add = (u: string | null | undefined) => { + if (!u) return; + if (!candidates.includes(u)) candidates.push(u); + }; + add(args.url); + // If CONVEX_URL is set in the environment, try it as well. + add(process.env.CONVEX_URL); + // Try swapping localhost and 127.0.0.1 for the primary URL. try { - const resp = await fetch(`${args.url}/instance_name`); - if (resp.status === 200) { - const text = await resp.text(); - if (text !== args.deploymentName) { - return await ctx.crash({ - exitCode: 1, - errorType: "fatal", - printedMessage: `A different local backend ${text} is running at ${args.url}`, - }); - } else { + const u = new URL(args.url); + const swappedHost = u.hostname === "127.0.0.1" ? "localhost" : u.hostname === "localhost" ? "127.0.0.1" : null; + if (swappedHost) { + u.hostname = swappedHost; + add(u.toString()); + } + } catch { } + + for (const base of candidates) { + logVerbose(`Checking local backend at ${base} is running`); + try { + const resp = await fetch(`${base.replace(/\/$/, "")}/instance_name`); + if (resp.status === 200) { + const text = await resp.text(); + if (text !== args.deploymentName) { + return await ctx.crash({ + exitCode: 1, + errorType: "fatal", + printedMessage: `A different local backend ${text} is running at ${base}`, + }); + } + // Found the correct backend return; } - } else { - return await ctx.crash({ - exitCode: 1, - errorType: "fatal", - printedMessage: `Error response code received from local backend ${resp.status} ${resp.statusText}`, - }); + } catch { + // Try next candidate } - } catch { - return await ctx.crash({ - exitCode: 1, - errorType: "fatal", - printedMessage: `Local backend isn't running. (it's not listening at ${args.url})\nRun \`npx convex dev\` in another terminal first.`, - }); } + const tried = candidates.join(", "); + return await ctx.crash({ + exitCode: 1, + errorType: "fatal", + printedMessage: `Local backend isn't running. Tried: ${tried}\nRun \`npx convex dev\` in another terminal first.`, + }); } /** Wait for up to maxTimeSecs for the correct local backend to be running on the expected port. */