Protect an HTTP MCP endpoint in one plug.
The MCP authorization spec treats a protected HTTP MCP server as an OAuth
resource server (RFC 9728). Guarding such an endpoint correctly takes two
ordered steps: authenticate the access token (and any DPoP/mTLS sender
constraint), then enforce the scopes the route requires. ProtectResource
composes AttestoMCP.Plug.Authenticate followed by
AttestoMCP.Plug.RequireScopes into a single, correctly ordered,
halt-respecting pipeline so the host does not hand-wire and re-order the two
plugs (and the WWW-Authenticate resource_metadata challenge) on every
route.
plug AttestoMCP.Plug.ProtectResource,
config: &MyApp.Attesto.config/0,
replay_check: &MyApp.DPoPReplay.check_and_record/2,
resource: "/mcp",
scopes: [AttestoMCP.Scopes.tools_call()]This is exactly equivalent to:
plug AttestoMCP.Plug.Authenticate,
config: &MyApp.Attesto.config/0,
replay_check: &MyApp.DPoPReplay.check_and_record/2,
resource_path: "/mcp"
plug AttestoMCP.Plug.RequireScopes,
scopes: [AttestoMCP.Scopes.tools_call()]Options
:scopes(or:scope) - the scope(s) the route requires, forwarded toAttestoMCP.Plug.RequireScopes. At least one scope is required.:resource(or:resource_path) - the MCP endpoint path, for example"/mcp"or"/mcp/brokers". It drives the RFC 9728resource_metadataauth-param appended toWWW-Authenticatechallenges, derived from the live request origin viaAttestoMCP.Metadata.protected_resource_url/2. Both names mean the same thing;:resourcereads naturally here while:resource_pathmatchesAttestoMCP.Plug.Authenticate.
Every other option is passed through to AttestoMCP.Plug.Authenticate:
:config, :replay_check, :nonce_check, :nonce_issue, :cert_der,
:htu, :credential_from_conn, :send_error, :www_authenticate,
:no_store, :principal, :principal_key, :claims_key, :scopes_key,
:sender_key, and :resource_metadata_url. The transport hooks
(:send_error, :www_authenticate) and the assign keys (:claims_key,
:scopes_key) are also shared with AttestoMCP.Plug.RequireScopes so a
scope rejection renders through the same host-controlled error envelope.