Skip to content

MCP server returns HTTP 500 on Cloudflare Workers when mcp: true is set (EmDash 0.1.0) #449

@peterhadorn

Description

@peterhadorn

Description

After enabling mcp: true in the EmDash config, the MCP endpoint at /_emdash/api/mcp returns HTTP 500 with an empty response body on Cloudflare Workers. The route is registered (no longer 404), but every request crashes silently.

This also affects the REST API when using Bearer token authentication. All /_emdash/api/content/* requests with a valid ec_pat_ token return 500, while unauthenticated requests correctly return 401. The admin UI (session-based auth) works fine.

Steps to reproduce

  1. Deploy EmDash to Cloudflare Workers with mcp: true in astro.config.mjs:
emdash({
    database: d1({ binding: "DB", session: "auto" }),
    storage: r2({ binding: "MEDIA" }),
    mcp: true,
})
  1. Generate a valid ec_pat_ token and insert it into the _emdash_api_tokens table (via wrangler d1 execute)

  2. Send a request to the MCP endpoint:

curl -X POST https://your-site.workers.dev/_emdash/api/mcp \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -H "Authorization: Bearer ec_pat_..." \
  -d '{"jsonrpc":"2.0","method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}},"id":1}'
  1. Response: HTTP 500, empty body

Also confirmed: the REST API at /_emdash/api/content/posts returns 500 with the same Bearer token, while returning 401 without auth. So the issue is in the auth middleware's token resolution path on Workers, not specific to MCP.

What I verified

  • Token hash is correct (SHA-256 via @oslojs/crypto/sha2, base64url-encoded, matches DB value)
  • User exists in the users table with admin role (50)
  • Token row exists in _emdash_api_tokens with correct token_hash, prefix, and user_id
  • The hashPrefixedToken function from @emdash-cms/auth produces the same hash locally
  • Admin UI works (session auth path is fine)
  • nodejs_compat flag is set in wrangler.jsonc

Likely cause

The auth middleware at dist/astro/middleware/auth.mjs imports hashPrefixedToken from @emdash-cms/auth, which uses @oslojs/crypto/sha2 (synchronous SHA-256). This may behave differently in the Cloudflare Workers runtime vs Node.js, or the Kysely query on D1 may throw an unhandled error. The catch block in the MCP route returns a JSON error, but the 500 has an empty body, suggesting the crash happens before the MCP handler (i.e., in the auth middleware).

Environment

  • EmDash: 0.1.0 (npm emdash@0.0.3)
  • Cloudflare Workers with D1 + R2
  • compatibility_date: 2026-02-24
  • compatibility_flags: ["nodejs_compat"]
  • Node.js 24.11.1 (local)

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions