bee-ai-auth-mcp

For developers

One Worker, two legs of trust.

bee-ai-auth-mcp is a single Cloudflare Worker that borrows its protocol, transport, and OAuth plumbing and builds only the Bee-specific glue. Here's the whole shape, including the parts that don't work yet.

The stack

Nothing in the auth or transport layer is hand-rolled. The Worker composes three proven pieces and adds a thin Bee client:

workers-oauth-provider
The OAuth 2.1 surface for MCP clients — dynamic client registration, PKCE, and encrypted grant storage in KV.
@modelcontextprotocol/sdk
MCP protocol framing, capability negotiation, and tool transport.
agents
Cloudflare's runtime for a Workers-hosted remote MCP endpoint.
src/bee.ts
The only bespoke part: a read-only client for Bee's /v1/* API.

The provider wraps the whole Worker. Requests to /mcp go to the MCP API handler; everything else (identity, health) goes to the default handler. The OAuth endpoints — /authorize, /token, /register, and /.well-known/oauth-authorization-server — are served by the provider itself.

Leg one — you ↔ the relay live

This leg proves you're allowed to use the instance. It's a standard OAuth web flow with GitHub as the upstream identity provider:

  1. Your MCP client registers itself (dynamic client registration) and opens /authorize.
  2. The relay 302-redirects to GitHub's /login/oauth/authorize with the instance's GITHUB_CLIENT_ID and a callback of https://<your-worker>/callback.
  3. You approve on GitHub. GitHub returns to /callback with a code.
  4. The relay exchanges the code for a short-lived GitHub token, reads only your login from /user, then discards the token.
  5. Your login is checked against ALLOWED_GITHUB_LOGIN. Pass, and the provider issues the relay's own OAuth token to your client. Fail, and you get a plain "not authorized" page.

GitHub here is identity only — no repository scope, no data access. The relay never stores your GitHub token; it reads a username and lets it go.

Why an OAuth App, not a GitHub App

The sibling git-repo-auth uses a GitHub App because it mints repository tokens. bee only needs to read a login, so a plain GitHub OAuth App is the right, smaller primitive. Its client_id and client_secret are the two secrets this leg needs.

Leg two — the relay ↔ Bee live

This leg carries your Bee credential to Bee. The token is captured at a consent step when you connect and held only in your own encrypted grant props — there is no BEE_API_TOKEN Worker secret, and nothing is custodied for anyone else. The relay reaches Bee's read surface: GET /v1/me behind whoami, plus the Phase-2 bee_read passthrough (GET any /v1/*, POST only to /v1/search/*) and the bee_docs reference tool.

The private-CA bridge

A Cloudflare Worker's fetch trusts only publicly-trusted certificates, and Bee's direct API uses a private CA. So the relay reaches Bee through a Cloudflare Container bound to the Worker (BEE_BRIDGE) running caddy, which trusts bee-ca.pem and re-originates TLS to Bee. The Worker->container hop is internal (no public hostname or cert); only the container->Bee hop is TLS. Requires the Workers Paid plan.

What's stored

The only persistent state is the OAuth provider's grants in the OAUTH_KV namespace. Grant props are encrypted per-grant with key material derived from the token itself — token-derived, not KMS-backed. A storage-only leak therefore reveals metadata, not usable credentials. The Bee bearer never appears in logs, URLs, errors, or tool output; errors return a status and a generic message, never the request or the token.

The MCP surface

Tools are added deliberately, against confirmed endpoints only:

Tool / endpointStatusNotes
whoami → /v1/meliveReturns your Bee identity through the bridge — validated end-to-end.
bee_read → /v1/* (GET) + /v1/search/* (POST)merged — validatingRead-only retrieval passthrough; /v1/stream + mutations refused, size-capped. Phase 2, merged to main.
bee_docsmerged — validatingServes the Bee-API-usage reference so the client knows what paths exist.
/v1/search/conversationsunconfirmedNot in Bee's public docs — confirm-or-drop against the live API first.
/v1/changesunconfirmedSame — frozen out of the tool surface until verified.

Tiers

Tier 1 (Model A, self-host) is what ships: one deployment, one operator, zero third-party custody. Tier 2 (hosted, multi-tenant) is deferred — without an upstream minting primitive it would mean storing many users' long-lived Bee tokens, the exact honeypot self-host avoids. The roadmap covers why, and the security model covers the custody trade in full.

Read the source on GitHub →