MCP OAuth Test

MCP OAuth Test

Multi-tenant MCP server with OAuth 2.1 authorization, enabling tenant-scoped tool access and audit logging.

Category
Visit Server

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:

  1. hit /mcp, get 401 + WWW-Authenticate pointing at the resource metadata;
  2. discover the authorization server and dynamically register itself (POST /register);
  3. 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:

  1. Audit log is the throughput ceiling — every tools/call writes one append-only row synchronously before responding. SQLite has a single writer, so concurrent calls serialize on the write lock.
  2. 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.
  3. Authorization-code consume race — codes must be single-use; atomic consume adds another write-serialization point.
  4. Multi-tenant noisy-neighbor — all tenants share one process, CPU, and audit-write lock; A tenant hammering tools degrades everyone.
  5. 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.
  6. 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: /authorize persists whatever scope the 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_id check 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

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.

Official
Featured
TypeScript
Magic Component Platform (MCP)

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.

Official
Featured
Local
TypeScript
Audiense Insights MCP Server

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.

Official
Featured
Local
TypeScript
VeyraX MCP

VeyraX MCP

Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.

Official
Featured
Local
graphlit-mcp-server

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.

Official
Featured
TypeScript
Kagi MCP Server

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.

Official
Featured
Python
E2B

E2B

Using MCP to run code via e2b.

Official
Featured
Neon Database

Neon Database

MCP server for interacting with Neon Management API and databases

Official
Featured
Exa Search

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.

Official
Featured
Qdrant Server

Qdrant Server

This repository is an example of how to create a MCP server for Qdrant, a vector search engine.

Official
Featured