branch:
README.md
2323 bytesRaw
# Authenticated MCP Server
An MCP server protected by OAuth 2.1, using `@cloudflare/workers-oauth-provider`. Clients must complete the OAuth flow before calling tools — the auth context is then available inside tool handlers.
## What it demonstrates
- **OAuth 2.1 with MCP** — dynamic client registration, authorization code flow, and token exchange
- **`OAuthProvider`** — wrapping `createMcpHandler` with `@cloudflare/workers-oauth-provider`
- **`getMcpAuthContext()`** — accessing the authenticated user's identity inside tool handlers
- **Custom authorization UI** — a Hono-based approval page for the OAuth flow
## Running
First, create a KV namespace for OAuth state:
```sh
npx wrangler kv namespace create OAUTH_KV
```
Update the `kv_namespaces` binding in `wrangler.jsonc` with the returned ID, then:
```sh
npm install
npm run dev
```
Open the browser to see the server info page. To test the tools, use the [MCP Inspector](https://github.com/modelcontextprotocol/inspector) — it will handle the OAuth flow automatically.
## How it works
The `OAuthProvider` wraps the entire Worker. It intercepts OAuth endpoints (`/authorize`, `/oauth/token`, `/oauth/register`) and validates Bearer tokens on the API route (`/mcp`).
```typescript
import { OAuthProvider } from "@cloudflare/workers-oauth-provider";
import { createMcpHandler, getMcpAuthContext } from "agents/mcp";
const apiHandler = {
async fetch(request, env, ctx) {
const server = createServer();
return createMcpHandler(server)(request, env, ctx);
}
};
export default new OAuthProvider({
authorizeEndpoint: "/authorize",
tokenEndpoint: "/oauth/token",
clientRegistrationEndpoint: "/oauth/register",
apiRoute: "/mcp",
apiHandler,
defaultHandler: { fetch: (req, env, ctx) => AuthHandler.fetch(req, env, ctx) }
});
```
Inside tool handlers, access the authenticated user:
```typescript
server.registerTool("whoami", { description: "Who am I?" }, async () => {
const auth = getMcpAuthContext();
return {
content: [{ type: "text", text: JSON.stringify(auth?.props) }]
};
});
```
## Related examples
- [`mcp-worker`](../mcp-worker/) — same stateless pattern without authentication
- [`mcp-client`](../mcp-client/) — connecting to authenticated MCP servers as a client (handles OAuth automatically)