mirror of
https://github.com/anthropics/claude-plugins-official.git
synced 2026-03-19 11:13:08 +00:00
Three skills guiding developers through MCP server design: - build-mcp-server: entry-point decision guide (remote HTTP vs MCPB vs local) - build-mcp-app: interactive UI widgets rendered in chat - build-mcpb: bundled local servers with runtime Includes reference files for scaffolds, tool design, auth (DCR/CIMD), widget templates, manifest schema, and local security hardening.
74 lines
3.7 KiB
Markdown
74 lines
3.7 KiB
Markdown
# Auth for MCP Servers
|
|
|
|
Auth is the reason most people end up needing a **remote** server even when a local one would be simpler. OAuth redirects, token storage, and refresh all work cleanly when there's a real hosted endpoint to redirect back to.
|
|
|
|
---
|
|
|
|
## The three tiers
|
|
|
|
### Tier 1: No auth / static API key
|
|
|
|
Server reads a key from env. User provides it once at setup. Done.
|
|
|
|
```typescript
|
|
const apiKey = process.env.UPSTREAM_API_KEY;
|
|
if (!apiKey) throw new Error("UPSTREAM_API_KEY not set");
|
|
```
|
|
|
|
Works for local stdio, MCPB, and remote servers alike. If this is all you need, stop here.
|
|
|
|
### Tier 2: OAuth 2.0 via Dynamic Client Registration (DCR)
|
|
|
|
The MCP host (Claude desktop, Claude Code, etc.) discovers your server's OAuth metadata, **registers itself as a client dynamically**, runs the auth-code flow, and stores the token. Your server never sees credentials — it just receives bearer tokens on each request.
|
|
|
|
This is the **recommended path** for any remote server wrapping an OAuth-protected API.
|
|
|
|
**Server responsibilities:**
|
|
|
|
1. Serve OAuth Authorization Server Metadata (RFC 8414) at `/.well-known/oauth-authorization-server`
|
|
2. Serve an MCP-protected-resource metadata document pointing at (1)
|
|
3. Implement (or proxy to) a DCR endpoint that hands out client IDs
|
|
4. Validate bearer tokens on incoming `/mcp` requests
|
|
|
|
Most of this is boilerplate — the SDK has helpers. The real decision is whether you **proxy** to the upstream's OAuth (if they support DCR) or run your own **shim** authorization server that exchanges your tokens for upstream tokens.
|
|
|
|
```
|
|
┌─────────┐ DCR + auth code ┌──────────────┐ upstream OAuth ┌──────────┐
|
|
│ MCP host│ ──────────────────> │ Your MCP srv │ ─────────────────> │ Upstream │
|
|
└─────────┘ <── bearer token ── └──────────────┘ <── access token ──└──────────┘
|
|
```
|
|
|
|
### Tier 3: CIMD (Client ID Metadata Document)
|
|
|
|
An alternative to DCR for ecosystems that don't want dynamic registration. The host publishes its client metadata at a well-known URL; your server fetches it, validates it, and issues a client credential. Lower friction than DCR for the host, slightly more work for you.
|
|
|
|
Use CIMD when targeting hosts that advertise CIMD support in their client metadata. Otherwise default to DCR — it's more broadly implemented.
|
|
|
|
---
|
|
|
|
## Hosting providers with built-in DCR/CIMD support
|
|
|
|
Several MCP-focused hosting providers handle the OAuth plumbing for you — you implement tool logic, they run the authorization server. Check their docs for current capabilities. If the user doesn't have strong hosting preferences, this is usually the fastest path to a working OAuth-protected server.
|
|
|
|
---
|
|
|
|
## Local servers and OAuth
|
|
|
|
Local stdio servers **can** do OAuth (open a browser, catch the redirect on a localhost port, stash the token in the OS keychain). It's fragile:
|
|
|
|
- Breaks in headless/remote environments
|
|
- Every user re-does the dance
|
|
- No central token refresh or revocation
|
|
|
|
If OAuth is required, lean hard toward remote HTTP. If you *must* ship local + OAuth, the `@modelcontextprotocol/sdk` includes a localhost-redirect helper, and MCPB is the right packaging so at least the runtime is predictable.
|
|
|
|
---
|
|
|
|
## Token storage
|
|
|
|
| Deployment | Store tokens in |
|
|
|---|---|
|
|
| Remote, stateless | Nowhere — host sends bearer each request |
|
|
| Remote, stateful | Session store keyed by MCP session ID (Redis, etc.) |
|
|
| MCPB / local | OS keychain (`keytar` on Node, `keyring` on Python). **Never plaintext on disk.** |
|