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
- Configure the MCP endpoint to return HTTP 401 with a WWW-Authenticate header for requests lacking a Bearer token.
- Replace 403 responses on unauthenticated access with 401 per RFC 6750 / MCP auth spec.
- Disable login-page redirects for the MCP route so API clients receive the 401 challenge.
- 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
- Return 401 (never 403 or a redirect) for unauthenticated MCP requests
- Verify auth middleware order so the challenge is emitted before other handlers
- Add a unit test asserting an unauthenticated request yields 401 + WWW-Authenticate
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
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- OpenWork-managed MCP OAuth is currently available for local
- OpenWork-managed OAuth requires a remote MCP URL.
- Authorization for ${input.connectionName} did not finish. Co
- MCP_OAUTH_CONFIGURATION_REQUIRED
- MCP_OAUTH_ISSUER_MISMATCH
AI-assisted analysis of different-ai/openwork@2b7df46e8a (2026-09-01).
Data as JSON: /api/errors/54a44baa538369d4.
Report an issue: GitHub.