MCP: CONVEX_DEPLOY_KEY makes every tool call "Not Authorized" — the documented way to scope the server to one deployment does not work

Author: ssahil97Created Sep 2, 2026Updated Sep 5, 2026

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_KEY environment variable.

With CONVEX_DEPLOY_KEY set to a valid, correctly scoped deployment key, every MCP tool call — including status — returns:

json
{"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

bash
npx convex deployment token create my-token --deployment <deployment-name>
CONVEX_DEPLOY_KEY="<the key>" npx convex mcp start --project-dir /path/to/project

Call 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:

javascript
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