different-ai/openwork · error · ProbeFailure

AUTH_RESOURCE_DISCOVERY

AUTH_RESOURCE_DISCOVERY

Error message

Unauthenticated MCP probe returned HTTP ${challengeResponse.status}, not 401

What it means

The probe first hits the MCP endpoint unauthenticated and requires the OAuth-protected-resource discovery handshake: the server MUST respond 401 so the client can learn the resource metadata from WWW-Authenticate. Any other status means the auth challenge contract is broken, so the probe fails in AUTH_RESOURCE_DISCOVERY with subcode oauth_discovery_resource.

Source

Thrown at packages/enterprise-mcp-mock-server/src/testing/probe.ts:522

          origin: baseUrl.origin,
        },
        body: JSON.stringify({
          jsonrpc: "2.0",
          id: 0,
          method: "initialize",
          params: {
            protocolVersion: scenario.protocol.version,
            capabilities: {},
            clientInfo: { name: "enterprise-mcp-probe", version: "0.1.0" },
          },
        }),
      },
      "AUTH_RESOURCE_DISCOVERY",
      overallDeadline,
    )
    await discardResponseBody(challengeResponse, "AUTH_RESOURCE_DISCOVERY", "oauth_discovery_resource")
    if (challengeResponse.status !== 401) {
      throw new ProbeFailure("AUTH_RESOURCE_DISCOVERY", "oauth_discovery_resource", `Unauthenticated MCP probe returned HTTP ${challengeResponse.status}, not 401`)
    }
    const challengeHeader = challengeResponse.headers.get("www-authenticate") ?? ""
    const metadataMatch = /resource_metadata="([^"]+)"/.exec(challengeHeader)
    const metadataUrlValue = metadataMatch?.[1]
    if (!metadataUrlValue) {
      throw new ProbeFailure("AUTH_RESOURCE_DISCOVERY", "oauth_discovery_resource", "MCP 401 challenge did not provide resource_metadata")
    }
    const resourceMetadataUrl = assertPinnedOrigin(metadataUrlValue, baseUrl, "AUTH_RESOURCE_DISCOVERY")
    const expectedMetadataPath = `/.well-known/oauth-protected-resource${profile.endpointPath}`
    if (resourceMetadataUrl.pathname !== expectedMetadataPath) {
      throw new ProbeFailure("AUTH_RESOURCE_DISCOVERY", "oauth_discovery_resource", "MCP challenge pointed to unexpected protected-resource metadata")
    }
    const resourceResponse = await expectOk(
      await fetchStep(resourceMetadataUrl, undefined, "AUTH_RESOURCE_DISCOVERY", overallDeadline),
      "AUTH_RESOURCE_DISCOVERY",
    )
    const resourceMetadata = parseAt(
      protectedResourceMetadataSchema,

View on GitHub (pinned to 2b7df46e8a)

Solutions

  1. Configure the MCP endpoint to return HTTP 401 with a WWW-Authenticate header for requests lacking a Bearer token.
  2. Replace 403 responses on unauthenticated access with 401 per RFC 6750 / MCP auth spec.
  3. Disable login-page redirects for the MCP route so API clients receive the 401 challenge.
  4. Verify auth middleware ordering so the challenge runs before other handlers can return 200/500.

Example fix

// before
if (!token) return res.status(403).json({ error: "forbidden" })
// after
if (!token) return res.status(401).set("www-authenticate", `Bearer resource_metadata="${metadataUrl}"`).end()
Defensive patterns

Strategy: validation

Validate before calling

const res = await fetch(mcpUrl)
if (res.status !== 401) throw new Error(`Unauthenticated MCP request must return 401, got ${res.status}`)
if (!res.headers.get("www-authenticate")) throw new Error("Missing WWW-Authenticate challenge header")

Try / catch

try {
  const result = await probeEnterpriseMcpMockServer({ baseUrl })
} catch (e) {
  if (e instanceof ProbeFailure && e.phase === "AUTH_RESOURCE_DISCOVERY") {
    console.error("Server did not issue a proper 401 OAuth challenge:", e.message)
  } else throw e
}

Prevention

When it happens

Trigger: The unauthenticated GET/POST probe of the MCP endpoint returns 200 (no auth enforced), 403 (rejected without challenge), 302 (redirected to a login page), or 500 instead of 401.

Common situations: Server misconfigured to serve the MCP endpoint without auth, a middleware returning 403 Forbidden instead of 401 Unauthorized, or auth handled by a UI redirect rather than a 401 challenge.

Understand the failure class

Related errors


AI-assisted analysis of different-ai/openwork@2b7df46e8a (2026-09-01). Data as JSON: /api/errors/54a44baa538369d4. Report an issue: GitHub.