MCP 401 challenge: the WWW-Authenticate header Sume returns

What a client sees when it calls Sume's MCP endpoint with no token: the WWW-Authenticate challenge, its resource_metadata URL and scope, and the spec.

4 min readSume
All posts

A call to https://mcp.sume.com/mcp with no valid token returns 401 Unauthorized with a WWW-Authenticate header of the form Bearer resource_metadata="https://mcp.sume.com/.well-known/oauth-protected-resource/mcp", scope="mcp:read". The first parameter tells the client where to find the protected-resource metadata; the second tells it which scope to ask for. That is the whole discovery handshake an MCP client such as Claude Code, Codex, Cursor or Gemini CLI needs before it opens a browser.

The shape matches what the MCP authorization draft recommends, read on 2026-10-03. Sume's side is in MCP OAuth and API keys.

What does each part of the header do?

The draft says MCP servers MUST implement OAuth 2.0 Protected Resource Metadata (RFC 9728) and that clients MUST use it to discover the authorization server. It also says servers SHOULD put a scope parameter in the WWW-Authenticate header, and gives an example 401 with resource_metadata and scope="files:read". A client uses the challenged scope in its first authorization request when one is present.

Sume's header follows that pattern. The metadata URL it names returns resource, authorization_servers (the MCP origin itself), scopes_supported of mcp:read and mcp:write, bearer_methods_supported of header, and a resource_documentation link back to the OAuth page.

Challenge fields: spec guidance from the MCP authorization draft (modelcontextprotocol.io), Sume values from the MCP OAuth docs and package defaults, read 2026-10-03.
FieldSpec guidanceSume value
resource_metadataPoints to the protected-resource metadata documenthttps://mcp.sume.com/.well-known/oauth-protected-resource/mcp
scope in the 401Servers SHOULD include itmcp:read
resource in metadataCanonical URI of the MCP serverhttps://mcp.sume.com/mcp
authorization_serversAt least one entryhttps://mcp.sume.com
Development hostNot specifiedSame shape on https://mcp.dev.sume.com

Why does the 401 ask only for mcp:read?

Because read is the one scope every session needs. Sume's docs say mcp:read is required and read-only, and mcp:write is opt-in: the consent page shows Read locked on and a Write toggle that defaults off. Granting write always includes read. There is no mcp:paid scope; paid submits are governed by wallet admission and the idempotency_key rule instead.

So a client that follows the challenge asks for read, the user may add write on the consent page, and the token carries whatever was granted. If you want a session that can submit generations, either pick Write on that page or use an API key, which the docs say sees the full hosted tool set. Check which one you got by calling mcp_health and reading authenticated.auth_source.

What happens when the token is valid but short of scope?

That is a different response. The draft says a runtime request with too little scope SHOULD get 403 Forbidden with a WWW-Authenticate header carrying error="insufficient_scope" and the scopes needed. Sume's docs say a read-only session sees only read-only tools, and a mutating tool called without write returns insufficient_scope. A client that re-runs authorization for the extra scope will send the user back to the consent page, where Write can be switched on.

Plan for the other end of the token's life as well: Sume's OAuth access tokens last 3600 seconds, and the metadata offers only the authorization-code grant, so clients re-authorize after an hour rather than refresh.

How can I see the challenge myself?

Send one unauthenticated request and print the headers. The command below posts an empty JSON-RPC body; you should see the 401 status line and the www-authenticate header. Then fetch the metadata URL it names with a plain GET.

curl -si -X POST https://mcp.sume.com/mcp \
  -H 'content-type: application/json' \
  -H 'accept: application/json, text/event-stream' \
  -d '{}' | head -n 12

curl -s https://mcp.sume.com/.well-known/oauth-protected-resource/mcp

Does a development host behave the same way?

Per the OAuth docs, development uses the same shape on https://mcp.dev.sume.com, with its own protected-resource metadata URL under that host. The authorization server there is the dev MCP host itself, not www.dev, and the token audience is https://mcp.dev.sume.com/mcp. Point a test client at one host or the other, not both, because a token is issued for one resource.

Clients that cache discovery can hold on to the wrong host after you switch. If a sign-in lands on the wrong consent page, clear the client's stored OAuth state for that server name and run the login again. Remember that the production authorization server is the MCP host, so no step in the flow should send you to the app host.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume