Agent Wranglers

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

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.