MCP: CONVEX_DEPLOY_KEY makes every tool call "Not Authorized" — the documented way to scope the server to one deployment does not work
Summary
The MCP docs recommend a deploy key to restrict the server to one deployment:
To restrict access to a single deployment, generate a deploy key and set the
CONVEX_DEPLOY_KEYenvironment variable.
With CONVEX_DEPLOY_KEY set to a valid, correctly scoped deployment key, every MCP tool call — including status — returns:
{"error":"Not Authorized: Run `npx convex dev` to login to your Convex project."}The server starts, accepts the connection, and then fails every request.
Reproduction
npx convex deployment token create my-token --deployment <deployment-name>
CONVEX_DEPLOY_KEY="<the key>" npx convex mcp start --project-dir /path/to/projectCall any tool. Every one returns the Not Authorized error above. Unsetting CONVEX_DEPLOY_KEY makes the same server work immediately.
Reproduced on convex 1.43.0 and 1.45.0 with a freshly minted key, on a deployment the key was scoped to.
Cause
cli/mcp.js runs checkAuthorization(ctx, false) on every CallToolRequest:
const authorized = await checkAuthorization(ctx, false);
if (!authorized) {
await ctx.crash({ … printedMessage: "Not Authorized: Run `npx convex dev` to login to your Convex project." });
}checkAuthorization (cli/lib/login.js) sends HEAD ${provisionHost}/api/authorize with ctx.bigBrainAuth()?.header. With a deployment key, getBigBrainAuth returns {kind: "deploymentKey", header: "Bearer <key>"}, and that endpoint does not accept a deployment key — the response is not 200, so checkAuthorization returns false and every call is refused.
Note the precedence in getBigBrainAuth: a project key is returned ahead of the global config, but a deployment key is too, so having a valid ~/.convex/config.json does not rescue it.
Impact
This is the documented mitigation for scoping an MCP server to one deployment, and it does not work — which matters more given the selector-resolution issue filed separately, where the server otherwise resolves to a deployment the caller did not name.
Suggested fix
Either accept a deployment key for the MCP authorization check (or skip checkAuthorization when the auth kind is deploymentKey, since the key itself is the authorization and each tool call authorizes against the deployment anyway), or correct the documentation to say CONVEX_DEPLOY_KEY is not supported for mcp start and name what is.
Docs: https://docs.convex.dev/ai/convex-mcp-server
Versions: convex 1.43.0 and 1.45.0, macOS, cloud deployments.
Source: get-convex/convex-backend