Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Fix MCP local deployment detection for self-hosted projects (#78) #92

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
JustYannicc wants to merge 4 commits into get-convex:main
base: main
Choose a base branch
Loading
from JustYannicc:main
Open
Show file tree
Hide file tree
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
22 changes: 9 additions & 13 deletions src/cli/lib/api.ts
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -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> {
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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;
}
62 changes: 39 additions & 23 deletions src/cli/lib/localDeployment/run.ts
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -143,34 +143,50 @@ export async function assertLocalBackendRunning(
deploymentName: string;
},
): Promise<void> {
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. */
Expand Down
19 changes: 11 additions & 8 deletions src/cli/mcp.ts
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -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({
Expand Down

AltStyle によって変換されたページ (->オリジナル) /