MCP OAuth Test
Multi-tenant MCP server with OAuth 2.1 authorization, enabling tenant-scoped tool access and audit logging.
README
MCP + OAuth 2.1 (PKCE) multi-tenant mockup
A self-contained research mockup: one Node process is BOTH an OAuth 2.1 Authorization Server (PKCE/S256) AND an MCP Resource Server with per-tenant tool filtering and an append-only audit log.
Run
npm install
npm run dev # server on http://localhost:3000
Drive it (CLI harness)
npm run harness -- --tenant tenant-a --tool echo --args '{"message":"hi"}'
npm run harness -- --tenant tenant-b --tool export_report --args '{"reportId":"r1"}'
npm run harness -- --tenant tenant-a --tool export_report --args '{"reportId":"r1"}' # denied (cross-tenant)
npm run harness -- --tenant tenant-a --tool admin_purge --args '{"confirm":true}' --scope "tools:call admin"
Use with Claude Code
The server speaks the OAuth flow Claude Code's remote-MCP client expects (Streamable HTTP, RFC 9728/8414 discovery, PKCE S256, Dynamic Client Registration).
npm run dev # http://localhost:3000
claude mcp add --transport http mockup http://localhost:3000/mcp
Then trigger the connection (e.g. list tools). Claude Code will:
- hit
/mcp, get401+WWW-Authenticatepointing at the resource metadata; - discover the authorization server and dynamically register itself (
POST /register); - open a browser to the login/consent page at
/authorize.
Sign in with a demo user (password demo):
| user | tenant | can call |
|---|---|---|
| alice | tenant-a | echo, search_documents, admin_purge (has admin) |
| bob | tenant-a | echo, search_documents (admin_purge denied — no admin) |
| carol | tenant-b | echo, search_documents, export_report |
After authorizing, Claude Code exchanges the code for a token and calls tools scoped to that user's tenant. The login is the authority that grants scope — there is no self-service admin.
Mock fidelity gaps (deliberate)
Plaintext passwords, no CSRF tokens, no sessions/cookies, open client registration, no refresh-token rotation, and a programmatic GET /authorize?tenant_id=…&sub=… shortcut used by the CLI harness/tests. These are research-mockup simplifications, not production patterns. (See spec §7 / §12.)
Test
npm test # unit + e2e
npx tsx tests/benchmark.ts 16 500 # audit-throughput benchmark (server must be running)
Flow
discovery → /authorize (PKCE challenge, mock tenant login) → redirect with code
→ /token (PKCE verify, JWT minted with tenant_id) → /mcp initialize + tools/list (filtered per tenant)
→ tools/call (re-checked against tenant policy, audited before responding).
Note: every denied tool call (cross-tenant or scope-gated) is recorded in the audit log as tool_denied; tools/list remains filtered per tenant.
Bottlenecks & tradeoffs
See docs/superpowers/specs/2026-06-29-mcp-oauth-multitenant-design.md §11 for the
full analysis. Headline findings:
- Audit log is the throughput ceiling — every
tools/callwrites one append-only row synchronously before responding. SQLite has a single writer, so concurrent calls serialize on the write lock. - Stateless JWT vs revocation lag — local verification means no per-request DB hit, but tokens stay valid until expiry; you cannot have stateless, revocable, and cheap all at once.
- Authorization-code consume race — codes must be single-use; atomic consume adds another write-serialization point.
- Multi-tenant noisy-neighbor — all tenants share one process, CPU, and audit-write lock; A tenant hammering tools degrades everyone.
- Self-contained fidelity gap — because the RS verifies tokens it minted itself, no real network/trust boundary; JWKS rotation, clock skew, discovery-cache staleness, or AS-downtime behavior are not observable.
- Streamable HTTP session state — stateless mode scales horizontally but loses server→client push; sessionful mode enables push but grows memory and requires durable binding.
Measured throughput (audit-write ceiling)
concurrency 1: 584 calls/s
concurrency 16: 1360 calls/s
Interpretation: only ~2.3x throughput at 16x parallelism — sub-linear scaling.
The synchronous, single-writer SQLite audit append serializes tool calls;
that append (written before each tool result returns) is the throughput ceiling.
Detailed analysis, including secondary tradeoffs (#7–10) and out-of-scope items, in §11–12 of the spec.
Mock fidelity gaps (cross-ref spec §12)
These are deliberate simplifications — the enforcement paths are real, the authority backing them is not:
- Scopes are self-service:
/authorizepersists whateverscopethe client requests (mock login, no consent authority), so the scope×tenant gating demonstrates the enforcement path, not authoritative scope granting. - Refresh-token grant is not client-bound: no
client_idcheck on refresh, and the refresh flow is not integration-tested. - Localhost HTTP only: no TLS; token confidentiality relies on loopback isolation alone.
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.