MCP (Model Context Protocol) Zero-Config Authorization Implemented with RFC 9728: How Clients Automatically Discovery of Server Authorization Settings
The era has arrived where AI agents communicate simultaneously with dozens of external services. GitHub, Jira, Notion, Slack—each service has a different authorization method, and until now, developers have manually hardcoded this authorization server information into the code. As the number of services increased, configuration files became bloated, and whenever an authorization server URL changed, the entire codebase had to be searched through.
MCP (Model Context Protocol) is a standard protocol for AI hosts, such as Claude and GPT, to communicate with external tools and data sources. By connecting individual services through standardized interfaces, it enables AI agents to handle tasks such as querying code on GitHub or creating issues in Jira in a consistent manner. However, as the number of MCP servers increases, the problem of managing individual authorization settings grows alongside it.
RFC 9728 (OAuth 2.0 Protected Resource Metadata), officially published by the IETF in April 2025, resolves this issue as a standard. When a resource server exposes a JSON document containing its authorization requirements to the /.well-known/oauth-protected-resource endpoint, clients look it up at runtime to automatically determine "where to obtain the token." The MCP specification goes a step further by making the implementation of RFC 9728 MUST mandatory for MCP servers.
After reading this article, you will be able to implement Zero-Config authorization on MCP servers and enable AI agents to automatically complete the authorization flow on any server without prior configuration.
Key Concepts
Authentication and Authorization: What Is the Difference?
Before reading the main text, it is helpful to distinguish one concept. Authentication is the process of verifying "who you are," while Authorization is the process of determining "what you can do." As the name suggests, OAuth (Open Authorization) is an authorization protocol. Authorization is also the core focus of RFC 9728 and the MCP specification, and the term "authorization" will be used throughout this article.
Problems Solved by RFC 9728
In the existing OAuth 2.0 environment, clients had to know the authorization server's URL in advance to access a resource server. This leads to two problems.
- Authorization server information is hardcoded into the client code or configuration file.
- Developers must manually change settings whenever a new resource server is added.
RFC 9728 reverses this dependency by having the resource server directly expose its authorization requirements.
What is RFC 9728?
This is an IETF standard where an OAuth 2.0 protected resource (Resource Server) publishes a JSON metadata document to the /.well-known/oauth-protected-resource path. Clients read this document to automatically determine at runtime "which authorization server to receive the token from." It was published as an official standard in April 2025 after a draft period of approximately 8.5 years.
Differences between OAuth 2.0 and OAuth 2.1
MCP is based on OAuth 2.1. The key differences from OAuth 2.0 are the following two:
| Changes | OAuth 2.0 | OAuth 2.1 |
|---|---|---|
| PKCE | Optional | Mandatory for all clients |
| Implicit Flow | Available | Completely Removed |
PKCE (Proof Key for Code Exchange, RFC 7636) is a security extension that prevents code theft attacks in the OAuth 2.0 authorization code flow. It allows clients to generate a random code validator and include its hash in authorization requests, preventing tokens from being issued with stolen code. As instances of code theft attacks accumulated in mobile app and SPA environments, the use of PKCE became mandatory in OAuth 2.1.
Zero-Config Authorization Search Flow
The overall flow of RFC 9728-based authorization is as follows.
1. MCP 클라이언트 → 인가 토큰 없이 MCP 서버에 첫 요청
2. MCP 서버 → 401 Unauthorized 응답
WWW-Authenticate: Bearer
resource_metadata="https://api.example.com/.well-known/oauth-protected-resource"
3. 클라이언트 → /.well-known/oauth-protected-resource 메타데이터 GET
4. 메타데이터에서 authorization_servers 필드로 인가 서버 URL 획득
5. 인가 서버 → OAuth 2.1 + PKCE 플로우로 액세스 토큰 발급
6. 클라이언트 → Bearer 토큰 포함하여 MCP 서버 재요청 → 성공If the client developer knows just the MCP server URL, everything else is handled automatically.
The November 2025 MCP specification (2025-11-25) also added a convention-based navigation method. This method allows the client to construct the /.well-known/oauth-protected-resource path directly from the server URL without the WWW-Authenticate header, and is compatible with servers that do not return headers.
Key Fields of Metadata Documents
The main fields of the JSON document returned by the /.well-known/oauth-protected-resource endpoint are as follows.
| Field | Description |
|---|---|
resource |
URL of the protected resource identifier |
authorization_servers |
List of trusted authorization server URLs |
scopes_supported |
List of supported OAuth scopes |
bearer_methods_supported |
Supported Bearer token delivery methods (header, body, etc.) |
jwks_uri |
Public Key Lookup URI (for Token Signature Verification) |
{
"resource": "https://api.myservice.com/mcp",
"authorization_servers": ["https://auth.myservice.com"],
"scopes_supported": ["mcp:tools:read", "mcp:tools:write"],
"bearer_methods_supported": ["header"],
"jwks_uri": "https://auth.myservice.com/.well-known/jwks.json"
}Relationship between MCP Specification and RFC 9728
The MCP specification runs on top of OAuth 2.1 and mandates RFC 9728 as follows.
| Role | Response in MCP | RFC 9728 Level of Obligation |
|---|---|---|
| OAuth Resource Server | MCP Server | Implementation MUST |
| OAuth Client | MCP Client | MUST use when discovering authorization servers |
RFC 9728 became mandatory starting with the June 2025 specification (MCP 2025-06-18), and RFC 8707 Resource Indicators became mandatory in March 2026 to prevent token misuse attacks.
Related RFC Stack: RFC 9728 alone is not complete. It is combined with RFC 8414 (Exploring Authorization Server Metadata), RFC 7591 (Dynamic Client Registration), RFC 7636 (PKCE), and RFC 8707 (Resource Indicators) to complete the complete Zero-Config authorization stack.
Tradeoffs Good to Know Before Introduction
It is a good idea to identify the key trade-offs before implementation.
Eligible Cases: AI agents dynamically connecting multiple MCP servers, enterprise gateways seeking to minimize client setup, and organizations already running standards-based IdPs (Auth0, Keycloak, Entra ID, etc.).
Caution Needed: Small teams that must implement the entire OAuth stack themselves (using libraries is recommended), local development environments (HTTPS configuration required), and the complexity of managing scopes in multi-hop agent chains.
Practical Application
Example 1: TypeScript MCP Server — Using the mcp-auth library
The fastest way to implement RFC 9728 in a TypeScript environment is to utilize the mcp-auth library. The following is an example of adding a metadata endpoint to an Express-based MCP server and validating a Bearer token.
import { MCPAuth } from 'mcp-auth';
import express from 'express';
const app = express();
// RFC 9728 메타데이터 설정
const mcpAuth = new MCPAuth({
mode: 'resource-server',
protectedResources: [{
resource: 'https://api.myservice.com/mcp',
authorizationServers: ['https://auth.myservice.com'],
scopesSupported: ['mcp:tools:read', 'mcp:tools:write'],
bearerMethodsSupported: ['header'],
jwksUri: 'https://auth.myservice.com/.well-known/jwks.json',
}]
});
// /.well-known/oauth-protected-resource 자동 마운트
app.use(mcpAuth.router());
// MCP 툴 엔드포인트 — 토큰 검증 미들웨어 적용
app.use('/mcp', mcpAuth.bearerAuth({
requiredScopes: ['mcp:tools:read']
}), async (req, res) => {
try {
// MCP 툴 목록 응답 (MCP 프로토콜 스키마 형식)
// { tools: [{ name: string, description: string, inputSchema: object }] }
res.json({ tools: [] });
} catch (err) {
res.status(500).json({ error: 'Internal server error' });
}
});
app.listen(3000);| Code Section | Role |
|---|---|
MCPAuth({ mode: 'resource-server' }) |
RFC 9728 Enable Resource Server Mode |
mcpAuth.router() |
/.well-known/oauth-protected-resource Endpoint Auto-registration |
mcpAuth.bearerAuth({ requiredScopes }) |
JWT Validation + Scope Check Middleware |
On the client side, it operates with the following conceptual flow. For actual implementation, it is recommended to refer to the README and OAuth examples in the Official TypeScript SDK.
// 개념적 흐름 — 실제 SDK API는 공식 README를 참고하세요
//
// 내부적으로 일어나는 일:
// 1. 401 응답 수신
// 2. WWW-Authenticate 헤더(또는 컨벤션 기반)로 메타데이터 URL 탐색
// 3. /.well-known/oauth-protected-resource GET → authorization_servers 획득
// 4. OAuth 2.1 + PKCE 플로우 → 액세스 토큰 발급 및 캐싱
// 5. Bearer 토큰 포함하여 원래 요청 재시도
//
// @modelcontextprotocol/sdk 실제 연결 예시:
// import { Client } from "@modelcontextprotocol/sdk/client/index.js";
// const client = new Client({ name: "my-client", version: "1.0.0" });
// await client.connect(transport); // transport에 OAuth 핸들러를 포함합니다Example 2: Python FastMCP Server Implementation
The following is an example of automatically providing RFC 9728 metadata endpoints using FastMCP in a Python environment. Since the actual API of OAuth21ResourceServer may vary depending on the FastMCP version, it is recommended to check the latest API in the FastMCP official repository before implementation.
from fastmcp import FastMCP
from fastmcp.server.auth import OAuth21ResourceServer
mcp = FastMCP(
name="my-mcp-server",
auth=OAuth21ResourceServer(
resource="https://api.myservice.com/mcp",
authorization_servers=["https://auth.myservice.com"],
jwks_uri="https://auth.myservice.com/.well-known/jwks.json",
required_scopes=["mcp:tools"]
)
)
@mcp.tool()
async def get_data(query: str) -> dict:
"""데이터 조회 툴 — 자동으로 인가 보호됨"""
return {"result": query}
# /.well-known/oauth-protected-resource 자동 생성 및 서빙
if __name__ == "__main__":
mcp.run()| Parameters | Description |
|---|---|
resource |
URL of this MCP server's unique identifier |
authorization_servers |
List of Trusted Authorization Servers |
jwks_uri |
Public key endpoint to use for JWT signature verification |
required_scopes |
Scope commonly required by all tools |
Example 3: Enterprise MCP Gateway Pattern (Keycloak Integration)
In large-scale enterprise environments, the central gateway pattern is more suitable than individual MCP servers handling authorization. In this pattern, a single gateway publishes RFC 9728 metadata and interacts with Keycloak, while the underlying internal API is not exposed to clients.
사용자 → AI 호스트(Claude/GPT)
↓
MCP 클라이언트
↓ (1. 첫 요청 → 401)
MCP 게이트웨이 ← /.well-known/oauth-protected-resource 게시
↓ (2. 메타데이터 탐색 → Keycloak URL 획득)
Keycloak (인가 서버)
↓ (3. OAuth 2.1 + PKCE → 토큰 발급)
MCP 게이트웨이 ← (4. Bearer 토큰으로 재요청)
↓ (토큰 검증 후 라우팅)
┌─────────┼─────────┐
GitHub API Jira API Notion APIExample of RFC 9728 metadata for a gateway:
{
"resource": "https://gateway.corp.com/mcp",
"authorization_servers": ["https://keycloak.corp.com/realms/ai-agents"],
"scopes_supported": [
"mcp:github:read",
"mcp:jira:write",
"mcp:notion:read"
],
"bearer_methods_supported": ["header"],
"jwks_uri": "https://keycloak.corp.com/realms/ai-agents/protocol/openid-connect/certs"
}In this pattern, the client only needs to know the gateway URL. There is no need to modify client settings even if internal APIs are added or changed.
Example 4: Azure AD (Entra ID) + MCP Server Integration
Finally, let's look at the reference architecture released by Microsoft. It is a pattern that connects an Entra ID to an authorization server on an Azure Container Apps-based MCP server. In the code below, replace {tenant-id} with the Tenant ID value found on the Azure Portal → App registrations screen.
// Azure Container Apps에서 실행되는 MCP 서버
const mcpAuth = new MCPAuth({
mode: 'resource-server',
protectedResources: [{
resource: 'https://my-mcp-app.azurecontainerapps.io/mcp',
// {tenant-id}: Azure Portal > App registrations에서 확인
authorizationServers: [
'https://login.microsoftonline.com/{tenant-id}/v2.0'
],
scopesSupported: ['api://my-mcp-app/mcp.tools'],
jwksUri: 'https://login.microsoftonline.com/{tenant-id}/discovery/v2.0/keys',
}]
});Resource Indicators (RFC 8707): This feature became mandatory in the MCP specification starting March 2026. If you specify the server to use the token via the resource parameter during an authorization request, the issued token is restricted to that specific server. This prevents "mis-redemption attacks," where tokens are stolen and reused on other servers. Detailed implementation methods will be covered in the next article.
Pros and Cons Analysis
Advantages
| Item | Content |
|---|---|
| True Plug and Play | Clients automatically discover all remaining authorization settings knowing only the server URL. Even when connecting dozens of MCP servers, there is no need to hardcode the authorization server for each server in your code. |
| Standard-Based Interoperability | Interoperability with all standards-compliant IdPs, such as Auth0, Okta, Cognito, Keycloak, and Entra ID, through the combination of RFC 9728 + RFC 8414 + OAuth 2.1. No vendor lock-in. |
| Fully automated when combined with Dynamic Client Registration (DCR) | When used with RFC 7591, clients can automatically acquire a Client ID without prior registration with an authorization server, eliminating onboarding friction. |
| Enhanced Security | Token signature verification is standardized by including JWKS URIs in metadata, and when combined with RFC 8707 Resource Indicators, token misuse attacks can be prevented. |
| AI Agent Multi-Server Connection Optimization | Agent code is simplified as the agent automatically determines each server's authorization requirements at runtime when dynamically connecting to GitHub, Jira, and Notion. |
Disadvantages and Precautions
| Item | Content | Response Plan |
|---|---|---|
| Implementation Complexity | Correctly implementing OAuth 2.1 + PKCE + RFC 9728 + RFC 8414 all together presents a high barrier to entry. | It is recommended to use proven libraries such as mcp-auth and FastMCP. |
| Discovery Poisoning Risk | A bug has been reported in the actual client (Claude Code) where all subsequent connection attempts are blocked if a metadata document is incorrectly cached. | It is recommended to set the cache TTL conservatively and add logic to invalidate the cache upon connection failure. |
| Lack of Configuration Portability | If you replace the MCP client, you must reconfigure the authorization settings from scratch. | It is helpful to manage authorization settings by separating them into an external configuration file. |
| HTTPS Required | Since metadata endpoints must be served over HTTPS, configuring the local development environment is cumbersome. | You can consider issuing a local HTTPS certificate using mkcert or utilizing ngrok tunnels. |
| Token Validity Scope Management | Maintaining consistency in the scope and authorization context of each segment within a multi-hop agent chain is complex. | It is recommended to explicitly restrict the usage scope of each token by applying RFC 8707 Resource Indicators. |
| Actual Implementation Gap | There are reports that a significant number of MCP servers on the public internet are operating without authorization. 1 | It is recommended to first verify whether authorization is implemented when integrating with third-party MCP servers. |
The Most Common Mistakes in Practice
- Looking up
/.well-known/oauth-protected-resourceon every request without metadata caching — Metadata documents do not change frequently, so they must be cached with an appropriate TTL. Otherwise, unnecessary latency and authorization server load will occur. - Requesting a token without the
resourceparameter — Starting March 2026, RFC 8707 Resource Indicators have become mandatory in the MCP specification. Failure to include theresourceparameter in both authorization and token requests results in a non-compliant status. - Setting scopes too broadly — Defining granular scopes like
mcp:tools:readandmcp:resources:writeinstead of wildcard scopes likemcp:*allows you to adhere to the principle of least privilege and facilitates audit trails.
In Conclusion
RFC 9728 reverses the dependency direction of client-server authorization configuration. Previously, clients had to "know" the server's authorization server in advance; now, the server exposes its authorization requirements, and the client discovers them at runtime. This paradigm shift is the core principle that eliminates hardcoding of authorization configurations, even when connecting dozens of MCP servers.
3 Steps to Start Right Now:
- Server Preparation: After installing
pnpm add mcp-auth(TypeScript) orpip install fastmcp(Python), you can add the/.well-known/oauth-protected-resourceendpoint to the server by referring to the example code above. If you use Keycloak or the Auth0 free tier as the authorization server, you can get started without a separate server. - Verify Navigation Flow: After verifying that the metadata document is correctly returned to
curl https://your-mcp-server/.well-known/oauth-protected-resource, you can attempt an actual Zero-Config connection with the MCP client of@modelcontextprotocol/sdk. - RFC 8707 Application: By adding the
resourceparameter to authorization requests to enable Resource Indicators, a production-grade implementation is completed that includes protection against token misuse attacks. For example, includingresource=https://api.myservice.com/mcpin the authorization request restricts issued tokens to that specific server only. Detailed implementation methods will be covered in the next article.
Next Post: How to Defend Against Token Abuse Attacks on Multi-Hop AI Agent Chains by Combining RFC 8707 Resource Indicators and OAuth 2.1 PKCE
Reference Materials
- RFC 9728 - OAuth 2.0 Protected Resource Metadata | IETF Datatracker
- Authorization - Model Context Protocol Official Specification (2025-06-18)
- Authorization - Model Context Protocol Draft
- What's New In The 2025-11-25 MCP Authorization Spec · Den Delimarsky
- The New MCP Authorization Specification (2026-04, Resource Indicators)
- Introducing RFC 9728: Say hello to standardized OAuth 2.0 resource metadata | WorkOS
- What Is Protected Resource Metadata (PRM) and How It Works | Descope
- Diving Into the MCP Authorization Specification | Descope
- Technical Deconstruction of MCP Authorization: OAuth 2.1 and IETF RFC Deep Dive
- Let's fix OAuth in MCP · Aaron Parecki
- How MCP Leverages OAuth 2.1 and RFC 9728 for Authorization | Gentoro
- Part Two: MCP Authorization The Hard Way | Solo.io
- Open Protocols for Agent Interoperability Part 2: Authentication on MCP | AWS
- Building a Secure MCP Server with OAuth 2.1 and Azure AD | Microsoft ISE Blog
- MCP Auth — Plug-and-play auth for MCP servers
- OAuth for MCP - Emerging Enterprise Patterns | GitGuardian
- MCP's 2026 roadmap makes enterprise readiness a top priority | WorkOS
Footnotes
-
This content is based on the GitGuardian OAuth for MCP report. It is recommended to check the report directly for specific figures and source data. ↩