Skip to content

bug: HTTP MCP invalid bearer token returns 500 instead of 401/403 #616

@ArshyaAI

Description

@ArshyaAI

Summary

gbrain serve --http currently returns HTTP 500 for an invalid bearer token on /mcp. The request is fail-closed, but remote MCP/OAuth deployments should return a clean auth failure (401 or 403) so canaries, clients, and security monitors can distinguish bad credentials from server faults.

Repro

Against gbrain 0.26.6 / upstream 9e2093fc9bb6cb46520e58b0c95b807e788d9606:

curl -i "$GBRAIN_PUBLIC_URL/mcp" \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -H 'Authorization: Bearer gbrain_bad_token_for_canary' \
  --data '{"jsonrpc":"2.0","method":"tools/list","params":{},"id":"bad_token"}'

Observed:

HTTP 500

Expected:

HTTP 401 Unauthorized

or 403 Forbidden where appropriate. The response body should avoid echoing token material.

Why this matters

For remote MCP/OAuth readiness, negative auth canaries need to prove:

  • missing token is rejected cleanly
  • bad token is rejected cleanly
  • expired/revoked credentials fail as auth failures, not server errors
  • logs do not contain bearer material

A 500 is fail-closed, but it makes auth posture look like application instability and blocks strict readiness gates.

Likely source

src/commands/serve-http.ts mounts:

app.post('/mcp', requireBearerAuth({ verifier: oauthProvider }), async (...)

An invalid token thrown/rejected by the MCP SDK bearer middleware appears to fall through Express default error handling as a 500. A narrow /mcp error middleware that maps auth-related errors to 401/403 should be enough.

Downstream workaround

In astack, the Railway wrapper is adding a temporary /mcp auth error handler that redacts the response and maps auth failures to 401/403. That should not remain permanently astack-specific if upstream can own the semantics.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions