Dynamic Client Registration and OAuth in MCP
Implement RFC 7591 Dynamic Client Registration and OAuth 2.0 token exchange for remote MCP servers. Secure AI agent credentials with zero-trust policies.
Generate & Validate Multi-Client MCP Config
One-click export with environment variables & path locators for Claude Desktop, Cursor, Windsurf, and OpenAI Codex CLI.
Dynamic Client Registration and OAuth in MCP
As Model Context Protocol (MCP) servers transition from local workstation processes toward remote cloud environments accessible via Streamable HTTP and Server-Sent Events (SSE), relying on static API keys introduces severe enterprise security liabilities. Autonomous AI agents, ephemeral developer containers, and multi-tenant agent frameworks cannot securely hardcode static credentials without risking credential sprawl, permission over-provisioning, and non-compliance with SOC 2, HIPAA, and ISO 27001 regulatory frameworks.
Securing remote MCP infrastructure at enterprise scale requires standardized Dynamic Client Registration (DCR, RFC 7591) paired with OAuth 2.0 Token Exchange (RFC 8693). This architecture enables ephemeral AI clients to register cryptographically verifiable credentials on the fly, negotiate granular tool execution scopes, and automatically rotate access tokens without human administrative intervention.
1. Problem Statement and Architecture
In a distributed cloud environment where dozens of autonomous developer agents operate concurrently, conventional authentication models suffer from several structural vulnerabilities:
- ▸Static Credential Sprawl: Hardcoding long-lived bearer tokens inside
.cursor/mcp.jsonor local developer dotfiles ensures that lost workstations or compromised container images leak full administrative tool privileges. - ▸Coarse-Grained Tool Privileges: Traditional API tokens grant uniform access across entire server endpoints. An orchestrator agent that only needs to read cluster telemetry often inherits access to sensitive mutating tools like database drop commands or Kubernetes deployment deleters.
- ▸Agent Delegation and Privilege Escalation: When an autonomous orchestrator spawns subagents to handle specialized tasks, passing the orchestrator's broad identity violates least privilege. Downstream agents must receive cryptographically downscoped tokens restricted exclusively to their assigned subtasks.
+-----------------------------------------------------------------------------------+
| Zero-Trust Auth Flow |
| |
| +--------------------+ 1. RFC 7591 POST /register +-------------+ |
| | AI Host Client | -------------------------------------> | | |
| | (Cursor / Claude) | <------------------------------------- | Enterprise | |
| +---------+----------+ 2. Ephemeral client_id / secret | OAuth 2.0 | |
| | | IdP / DCR | |
| | 3. POST /token (Exchange) | (Keycloak / | |
| +-------------------------------------------------> | Okta) | |
| | <------------------------------------------------ | | |
| | 4. Scoped JWT (mcp:db:read) +-------------+ |
| | |
| | 5. HTTP GET /sse (Authorization: Bearer <JWT>) |
| v |
| +--------------------+ 6. POST /messages (Scope Guard) |
| | Remote MCP Server | <---------------------------------------------------------+
| +--------------------+
+-----------------------------------------------------------------------------------+In an enterprise DCR architecture, the AI host first contacts the enterprise Identity Provider (IdP). It registers its ephemeral instance, acquires short-lived credentials, exchanges an employee or workload identity token for an MCP-scoped JSON Web Token (JWT), and establishes a secured SSE connection to the remote server.
2. Dynamic Client Registration (RFC 7591) Wire Flow
When an ephemeral developer container or CI/CD runner initializes, the client programmatically registers itself using standard RFC 7591 endpoints.
Registration Request (POST /oauth/register)
POST /oauth/register HTTP/1.1
Host: auth.enterprise.internal
Content-Type: application/json
Authorization: Bearer <INITIAL_REGISTRATION_TOKEN>
{
"client_name": "Cursor-DevInstance-user-8921",
"grant_types": ["client_credentials", "urn:ietf:params:oauth:grant-type:token-exchange"],
"response_types": ["token"],
"scope": "mcp:tools:read mcp:tools:call:db_query mcp:tools:call:k8s_read",
"token_endpoint_auth_method": "private_key_jwt",
"software_id": "4c9d8a-cursor-agent",
"software_version": "2026.3.1"
}Authorization Server Registration Response
The identity provider validates registration policies, bounds maximum permissions according to organizational role-based access control (RBAC), and issues short-lived client credentials:
HTTP/1.1 201 Created
Content-Type: application/json
Cache-Control: no-store
{
"client_id": "mcp-client-881b29a-4c22",
"client_secret": "sec_77f81a0e8d91c2b3e4f5a6b7c8d9e0f1",
"client_id_issued_at": 1773446400,
"client_secret_expires_at": 1773532800,
"registration_client_uri": "https://auth.enterprise.internal/oauth/register/mcp-client-881b29a-4c22",
"scope": "mcp:tools:read mcp:tools:call:db_query"
}Ephemeral agent workers are assigned a maximum Time-To-Live (TTL) of 24 hours. Once the agent workflow terminates, the credentials automatically expire within the authorization registry.
3. Scoped Token Minting and JSON-RPC Access Control
Once registered, the AI host exchanges its ephemeral credentials for a scoped JWT access token:
Token Request (POST /oauth/token)
POST /oauth/token HTTP/1.1
Host: auth.enterprise.internal
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials
&client_id=mcp-client-881b29a-4c22
&client_secret=sec_77f81a0e8d91c2b3e4f5a6b7c8d9e0f1
&scope=mcp:tools:call:db_queryDecoded JWT Claims
The authorization server signs a cryptographically verifiable token containing precise tool execution scopes:
{
"iss": "https://auth.enterprise.internal",
"sub": "mcp-client-881b29a-4c22",
"aud": "https://mcp-server.enterprise.internal",
"exp": 1773450000,
"nbf": 1773446400,
"scope": "mcp:tools:read mcp:tools:call:db_query",
"enterprise": {
"org_id": "engineering_core",
"user_email": "jane.dev@enterprise.internal",
"clearance_level": "l4"
}
}4. MCP Server Authorization Middleware Implementation
The remote MCP server verifies the JWT token using an asynchronous JSON Web Key Set (JWKS) validation provider. It enforces granular scopes on each tool call dispatched across the transport.
import Fastify, { FastifyRequest, FastifyReply } from "fastify";
import fastifyJwt from "@fastify/jwt";
import jwksRsa from "jwks-rsa";
const app = Fastify({ logger: true });
// Configure JWKS validation against enterprise identity provider
const jwksClient = jwksRsa({
jwksUri: "https://auth.enterprise.internal/.well-known/jwks.json",
cache: true,
rateLimit: true,
jwksRequestsPerMinute: 10
});
const getPublicKey = async (req: FastifyRequest, token: any) => {
const decodedToken = token as { header: { kid: string } };
const key = await jwksClient.getSigningKey(decodedToken.header.kid);
return key.getPublicKey();
};
app.register(fastifyJwt, {
secret: getPublicKey,
algorithms: ["RS256"]
});
function enforceToolScope(requiredScope: string) {
return async (request: FastifyRequest, reply: FastifyReply) => {
try {
await request.jwtVerify();
const user = request.user as { scope?: string };
const scopes = (user.scope || "").split(" ");
if (!scopes.includes(requiredScope) && !scopes.includes("mcp:admin")) {
reply.status(403).send({
jsonrpc: "2.0",
id: (request.body as any)?.id || null,
error: {
code: -32003,
message: `Forbidden: Missing required OAuth 2.0 scope '${requiredScope}'`,
data: { requiredScope, currentScopes: scopes }
}
});
}
} catch {
reply.status(401).send({
jsonrpc: "2.0",
id: (request.body as any)?.id || null,
error: {
code: -32002,
message: "Unauthorized: Invalid or expired OAuth 2.0 Bearer token"
}
});
}
};
}
// Authenticated SSE Route
app.get("/sse", async (request, reply) => {
try {
await request.jwtVerify();
reply.raw.setHeader("Content-Type", "text/event-stream");
reply.raw.setHeader("Cache-Control", "no-cache");
reply.raw.setHeader("Connection", "keep-alive");
reply.raw.flushHeaders();
reply.raw.write("event: endpoint\ndata: /messages?sessionId=sess_842\n\n");
} catch {
reply.status(401).send({ error: "Invalid token" });
}
});
// Authenticated Tool Dispatch Route
app.post("/messages", async (request: FastifyRequest, reply: FastifyReply) => {
const body = request.body as any;
if (body?.method === "tools/call") {
const toolName = body.params?.name;
const requiredScope = `mcp:tools:call:${toolName}`;
await enforceToolScope(requiredScope)(request, reply);
if (reply.sent) return;
return reply.send({
jsonrpc: "2.0",
id: body.id,
result: { content: [{ type: "text", text: "Protected enterprise payload" }] }
});
}
return reply.send({ jsonrpc: "2.0", id: body.id, result: { status: "acknowledged" } });
});
app.listen({ port: 8080, host: "0.0.0.0" });5. Token Exchange (RFC 8693) for Multi-Agent Workflows
In hierarchical agent topologies where an orchestrator delegates subtasks to specialized worker agents, passing the orchestrator's broad token violates security boundaries. Instead, the orchestrator invokes RFC 8693 token exchange to mint downscoped credentials for subordinate workers:
POST /oauth/token HTTP/1.1
Host: auth.enterprise.internal
Content-Type: application/x-www-form-urlencoded
grant_type=urn:ietf:params:oauth:grant-type:token-exchange
&subject_token=eyJhbGciOiJSUzI1Ni...
&subject_token_type=urn:ietf:params:oauth:token-type:access_token
&audience=https://mcp-analytics.internal
&scope=mcp:tools:call:aggregate_metricsThe resulting token allows the subagent to execute aggregate_metrics but strictly forbids invoking broader capabilities such as database deletions or secret extractions.
6. Multi-Host Configuration Snippets
Developers configure their clients to supply dynamic OAuth tokens via environment variables.
Claude Desktop
In claude_desktop_config.json:
{
"mcpServers": {
"enterprise-oauth-mcp": {
"endpoint": "https://mcp.ai.example.com/sse",
"headers": {
"Authorization": "Bearer ${ENTERPRISE_OAUTH_TOKEN}"
}
}
}
}Cursor IDE
In .cursor/mcp.json:
{
"mcpServers": {
"enterprise-oauth-mcp": {
"endpoint": "https://mcp.ai.example.com/sse",
"headers": {
"Authorization": "Bearer ${ENTERPRISE_OAUTH_TOKEN}"
}
}
}
}OpenAI Codex CLI
In ~/.codex/config.toml:
[mcp_servers.enterprise_oauth_mcp]
url = "https://mcp.ai.example.com/sse"
headers = { Authorization = "Bearer ${ENTERPRISE_OAUTH_TOKEN}" }7. Common Errors and Production Troubleshooting
1. JSON-RPC Error -32003: Forbidden Missing Scope
- ▸Symptom: Tool calls fail with
-32003error code despite successful SSE connection. - ▸Root Cause: The client successfully authenticated to the SSE stream using a token with
mcp:tools:readscope, but lacked the specificmcp:tools:call:<tool_name>claim required by the invoked tool. - ▸Solution: Update the client's token request scope parameter to explicitly include target tool scopes or configure role-based wildcards (
mcp:tools:call:*) in the authorization server.
2. JWKS Cache Stale Key Failures (kid not found)
- ▸Symptom: All agent requests fail with 401 errors following identity provider key rotation.
- ▸Root Cause: The MCP server cached old RSA public keys in memory and rejected incoming JWTs signed with the newly active key.
- ▸Solution: Configure
jwks-rsawithcache: trueand a reasonable cache TTL (e.g., 10 minutes) combined with on-demand key refresh when an unknownkidis encountered.
3. Connection Drops on Ephemeral Client Expiration
- ▸Symptom: Long-running agent task chains disconnect after 60 minutes with connection reset errors.
- ▸Root Cause: The OAuth access token expired without a client-side background refresh cycle.
- ▸Solution: Deploy an OS-level token daemon or background refresh loop that fetches a new token 5 minutes prior to token expiration and updates the active environment variable.
8. External Citations and Security Guardrails
Securing remote Model Context Protocol infrastructure requires adherence to formal internet security standards:
- ▸Short-Lived Ephemeral Credentials: Limit DCR client credentials to 24 hours and access tokens to 60 minutes to minimize exposure windows.
- ▸Mutual TLS (mTLS): Enforce mTLS between the MCP server and enterprise identity providers to safeguard token verification traffic.
- ▸Audit Traces: Log subject claims (
sub) and client identifiers (client_id) on all tool calls for centralized SOC 2 SIEM audit ingestion.
MCP Developer Newsletter (In Planning)
We are preparing an occasional technical dispatch covering new servers, benchmarks, and protocol updates. Sign up early to receive issues when we launch.
Zero marketing spam. 1-click unsubscribe anytime.
Build your full agent toolstack in the Visual Generator
Combine verified MCP servers with databases, search APIs, and memory graphs in a single configuration file.
Did this setup guide work with your AI host?
Help test this configuration across Claude, Cursor, and Codex CLI. Be the first to report:
Written by Rad Tome
Lead AI Systems Architect & Maintainer, MCP Codex
Specializing in Model Context Protocol (MCP) integrations, autonomous AI agent orchestration, and distributed developer toolchains. Researches and benchmarks production MCP client-server architectures across OpenAI Codex, Claude, and Cursor.
Related Guides
The MCP Security Checklist: 50 Vulnerabilities to Audit Before Shipping
Comprehensive security audit checklist for MCP servers. 50 specific vulnerabilities across injection, authentication, authorization, transport, supply chain, and operational security. Includes exploitation examples, detection methods, and remediation code.
EnterpriseBenchmarking MCP: Latency, Transport Overheads & Cost Model
Empirical latency baselines comparing MCP stdio vs SSE transports, cold start overheads, memory footprints, and AWS cost modeling with runnable test scripts.
EnterpriseMCP Server Monetization: Production Models
Architect paid MCP servers using Stripe Billing, token metering, and HTTP 402 machine payments. Covers real auth flows, mppx code, and unit economics.