You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This SEP adds a delegated authorization primitive to the Model Context Protocol that enables servers to request OAuth authorization from clients using an auth/request API. This provides a standardized way for servers to request OAuth authorization from clients in order to access upstream resources. This enables servers to obtain necessary access tokens for upstream APIs through the user's MCP client.
The delegated authorization primitive allows MCP servers to:
Request OAuth authorization for upstream resources
Receive authorization codes through the client's UI (e.g. user log-in, and other OAuth flows)
Motivation
MCP servers that need to access authenticated upstream resources have no standard way to request user authorization through the MCP protocol. The current MCP specification defines authorization for client-to-server access but lacks a mechanism for server-initiated authorization requests. This gap prevents important use cases:
Real-World Use Cases
Agents as MCP servers: Servers which are agents may act as clients to upstream servers which need authorization.
Workflow Automation: Servers with tools that orchestrate actions across authenticated platforms
API Aggregators: Servers that combine data from multiple authenticated APIs (GitHub, Slack, Jira)
Example Scenario
Consider an MCP server that provides unified access to a user's code repositories:
User → Claude Desktop → Repository MCP Server → GitHub API
→ GitLab API
→ Bitbucket API
The Repository MCP Server needs to obtain authorization for each upstream API on behalf of the user, but has no standard way to request this authorization through the MCP protocol.
Specification
1. Client Capability
Clients supporting delegated authorization requests declare the capability during initialization:
exportinterfaceClientCapabilities{// ... existing fields .../** * Present if the client supports delegated authorization requests from servers. */delegated_authorization?: object;}
2. Authorization Request
The server initiates authorization with a blocking request:
/** * Request OAuth authorization from the client for accessing upstream resources. * * @category auth/request */exportinterfaceDelegatedAuthorizationRequestextendsRequest{method: "auth/request";params: {/** * The complete OAuth authorization URL to open. * This URL contains all necessary OAuth parameters including * client_id, redirect_uri, scope, state, code_challenge, etc. */url: string;/** * Human-readable message explaining why authorization is needed. */message: string;/** * Optional: Alternative redirect URI templates the server supports. * Clients SHOULD select the first option they can handle. * Templates may include placeholders like {port} or {session}. * * Examples: * - "http://127.0.0.1:{port}/callback" (desktop clients) * - "https://callback.example.com/{session}" (web clients) * - "com.example.app://oauth/callback" (mobile clients) */redirect_uri_options?: string[];};}
3. Authorization Result
The client returns the OAuth callback URL:
/** * Result of a delegated authorization request. * * @category auth/request */exportinterfaceDelegatedAuthorizationResultextendsResult{/** * The complete callback URL from the OAuth provider. * Only present if the user completed authorization. * Contains the authorization code and state parameters. */url?: string;}
4. Protocol Flow
sequenceDiagram
participant User
participant Client as MCP Client
participant Server as MCP Server
participant OAuth as OAuth Provider
Server->>Client: auth/request<br/>{url: "oauth_url", message: "authorize upstream resource"}
Client->>User: Show authorization prompt
User->>Client: Approves
Client->>User: Open OAuth URL
User->>OAuth: Complete OAuth flow
OAuth->>User: Redirect with code
User->>Client: Callback URL
Client-->>Server: {url: "callback_url"}
Note over Server: Exchange code for token
Loading
Rationale
Design Principles
Minimal Addition: Only two new types, following existing patterns
OAuth Native: Works directly with standard OAuth 2.1 flows
Security First: No token handling in the protocol layer
Clear Semantics: Missing URL means user declined
Alternatives Considered
Notification-based approach: Would require complex callback correlation
Extending elicitation: Authorization has distinct security requirements
Full OAuth proxy: Would violate protocol layering principles
Related Work
Elicitation Pattern: This proposal follows the same blocking request pattern
OAuth 2.1: Aligns with industry-standard authorization flows
Backward Compatibility
This proposal is fully backward compatible:
Optional Capability: Only used when both client and server support it
Additive Change: No modifications to existing protocol elements
Graceful Degradation: Servers can detect lack of client support
Servers MUST check for client capability before sending delegated authorization requests:
if(clientCapabilities.delegated_authorization){// Can use auth/request}else{// Fall back to alternative method}
Reference Implementation
Server Implementation
asyncfunctionauthorizeWithUpstream(client: MCPClient,provider: string){// Build OAuth URL with PKCEconststate=generateSecureRandom();constcodeVerifier=generateCodeVerifier();constcodeChallenge=generateCodeChallenge(codeVerifier);constauthUrl=newURL('https://github.com/login/oauth/authorize');authUrl.searchParams.set('client_id',CLIENT_ID);authUrl.searchParams.set('redirect_uri',REDIRECT_URI);authUrl.searchParams.set('scope','repo read:user');authUrl.searchParams.set('state',state);authUrl.searchParams.set('code_challenge',codeChallenge);authUrl.searchParams.set('code_challenge_method','S256');// Request authorizationconstresult=awaitclient.request('auth/request',{url: authUrl.toString(),message: `GitHub authorization required to access private repositories`});if(!result.url){thrownewError('Authorization declined by user');}// Parse callbackconstcallback=newURL(result.url);constcode=callback.searchParams.get('code');constreturnedState=callback.searchParams.get('state');// Validate stateif(returnedState!==state){thrownewError('State mismatch - possible CSRF');}// Exchange code for tokenconsttoken=awaitexchangeCodeForToken(code,codeVerifier);returntoken;}// Multi-platform support exampleasyncfunctionauthorizeWithRedirectOptions(client: MCPClient){constauthUrl=newURL('https://github.com/login/oauth/authorize');authUrl.searchParams.set('client_id',CLIENT_ID);authUrl.searchParams.set('redirect_uri','http://localhost:8080/callback');// ... other OAuth parametersconstresult=awaitclient.request('auth/request',{url: authUrl.toString(),message: 'GitHub authorization required',redirect_uri_options: ['http://127.0.0.1:{port}/callback',// Desktop clients'https://auth.myserver.com/{session}',// Web clients 'com.mycompany.mcp://oauth/callback'// Mobile clients]});}
Client Implementation
asyncfunctionhandleDelegatedAuthorizationRequest(params: DelegatedAuthorizationRequestParams){// Show UI to userconstuserChoice=awaitshowAuthorizationDialog({message: params.message,domain: newURL(params.url).hostname});if(!userChoice.approved){return{};// User declined}// Open OAuth URLawaitopenBrowser(params.url);// Capture callback (automatic or manual)constcallbackUrl=awaitcaptureOAuthCallback();return{url: callbackUrl};}
OAuth Callback Capture
The captureOAuthCallback() implementation should follow RFC 8252: OAuth 2.0 for Native Apps, which defines standard approaches for native applications:
Loopback Interface Redirect (Recommended):
Start a temporary HTTP server on 127.0.0.1 with an ephemeral port
Configure OAuth provider with http://127.0.0.1:{port}/callback as redirect URI
Automatically capture the callback when the browser redirects
Delegated authorization allows server-initiated authorization flows that is compliant with existing MCP patterns as well as OAuth2.1 standards. It enables MCP servers to grow more sophisticated while still maintaining security primitives.
SEP: Delegated Authorization
SEP Number: TBD (to be assigned by sponsor)
Title: Delegated Authorization
Author: Sarmad Qadri [email protected]
Status: Proposal
Type: Standards Track
Created: 2025-07-20
Tags: proposal, sep
Abstract
This SEP adds a delegated authorization primitive to the Model Context Protocol that enables servers to request OAuth authorization from clients using an
auth/requestAPI. This provides a standardized way for servers to request OAuth authorization from clients in order to access upstream resources. This enables servers to obtain necessary access tokens for upstream APIs through the user's MCP client.The delegated authorization primitive allows MCP servers to:
Motivation
MCP servers that need to access authenticated upstream resources have no standard way to request user authorization through the MCP protocol. The current MCP specification defines authorization for client-to-server access but lacks a mechanism for server-initiated authorization requests. This gap prevents important use cases:
Real-World Use Cases
Example Scenario
Consider an MCP server that provides unified access to a user's code repositories:
The Repository MCP Server needs to obtain authorization for each upstream API on behalf of the user, but has no standard way to request this authorization through the MCP protocol.
Specification
1. Client Capability
Clients supporting delegated authorization requests declare the capability during initialization:
2. Authorization Request
The server initiates authorization with a blocking request:
3. Authorization Result
The client returns the OAuth callback URL:
4. Protocol Flow
sequenceDiagram participant User participant Client as MCP Client participant Server as MCP Server participant OAuth as OAuth Provider Server->>Client: auth/request<br/>{url: "oauth_url", message: "authorize upstream resource"} Client->>User: Show authorization prompt User->>Client: Approves Client->>User: Open OAuth URL User->>OAuth: Complete OAuth flow OAuth->>User: Redirect with code User->>Client: Callback URL Client-->>Server: {url: "callback_url"} Note over Server: Exchange code for tokenRationale
Design Principles
Alternatives Considered
Related Work
Backward Compatibility
This proposal is fully backward compatible:
Servers MUST check for client capability before sending delegated authorization requests:
Reference Implementation
Server Implementation
Client Implementation
OAuth Callback Capture
The
captureOAuthCallback()implementation should follow RFC 8252: OAuth 2.0 for Native Apps, which defines standard approaches for native applications:Loopback Interface Redirect (Recommended):
127.0.0.1with an ephemeral porthttp://127.0.0.1:{port}/callbackas redirect URIManual Entry (Fallback):
This approach is used by standard tools like GitHub CLI, Google Cloud SDK, and AWS CLI.
Security Implications
OAuth Security Requirements
Servers implementing delegated authorization MUST follow OAuth 2.1 security best practices:
Client Security Requirements
Preventing Common Attacks
Following RFC 6819: OAuth 2.0 Threat Model:
stateparameterRedirect URI Selection
When using
redirect_uri_options:Implementation Guidance
For Clients
For Servers
Error Handling
OAuth errors are indicated by the
errorparameter in the callback URL:Standard OAuth error codes include:
access_denied: User denied authorizationinvalid_scope: Requested scope is invalidserver_error: Authorization server errorConclusion
Delegated authorization allows server-initiated authorization flows that is compliant with existing MCP patterns as well as OAuth2.1 standards. It enables MCP servers to grow more sophisticated while still maintaining security primitives.