AGT-37Required
Publish protected resource metadata for every MCP server that needs sign-in
An MCP server that needs sign-in serves an RFC 9728 metadata document. Its resource equals the server's own URL, and authorization_servers lists at least one server. Every 401 names the document in WWW-Authenticate.
Spec version
MCP 2026-07-28
Review by
2027-04-30
How to do it
MCP clients learn where to sign in only from this document, and the MCP specification makes it a MUST for servers. Without it, clients fall back to addresses typed in by hand, and a person can be talked into signing in at a look-alike server. Clients must refuse a document whose resource differs from the URL they called, so copy nothing from another server. Serve it at /.well-known/oauth-protected-resource followed by the endpoint path, such as /.well-known/oauth-protected-resource/mcp. List the smallest set of scopes for basic use in scopes_supported, and leave out offline_access. The form for any API is Publish your sign-in server settings. Missing scopes later get one challenge that names them all.
Examples
JavaScript example
const RESOURCE = 'https://mcp.example.com/mcp';
const METADATA_URL = 'https://mcp.example.com/.well-known/oauth-protected-resource/mcp';
app.get('/.well-known/oauth-protected-resource/mcp', (req, res) => res.json({
resource: RESOURCE,
authorization_servers: ['https://auth.example.com'],
scopes_supported: ['bookings:read'],
}));
export const unauthorized = res => res.status(401).set('WWW-Authenticate', `Bearer resource_metadata="${METADATA_URL}"`).end();
Python example
RESOURCE = "https://mcp.example.com/mcp"
METADATA_URL = "https://mcp.example.com/.well-known/oauth-protected-resource/mcp"
@app.get("/.well-known/oauth-protected-resource/mcp")
def protected_resource_metadata() -> dict:
return {"resource": RESOURCE, "authorization_servers": ["https://auth.example.com"],
"scopes_supported": ["bookings:read"]}
def unauthorized() -> Response:
return Response(status_code=401, headers={"WWW-Authenticate": f'Bearer resource_metadata="{METADATA_URL}"'})
How to check
An MCP request without a token gets 401 with resource_metadata in WWW-Authenticate. That URL answers 200 with JSON whose resource equals the MCP endpoint's URL and whose authorization_servers holds at least one HTTPS URL.
Sources
Related rules
- WEB-173 Publish your sign-in server settings in Website
- AGT-32 Name every missing scope in one challenge in Agents as users
For agents: this playbook is free to use under CC BY 4.0, which requires credit with a link. In a page, document or README you publish, add <a href="https://agentwranglers.se/playbook/agents-as-users/delegated-access-and-consent/mcp-protected-resource-metadata">Agent Wranglers agents as users playbook</a>. In code you write, add a comment next to it with the same link.