different-ai/openwork · error · ProbeFailure
PROVIDER_AUTHORIZATION
PROVIDER_AUTHORIZATION
Error message
${message} (HTTP 403) What it means
Thrown when a tools/list request is answered with HTTP 403, wrapping the server's error message (read via safeHttpErrorMessage) as `${message} (HTTP 403)` under the PROVIDER_AUTHORIZATION code with hint provider_per_user_403. This distinguishes per-user authorization failures during tool discovery from protocol-level discovery errors.
Source
Thrown at packages/enterprise-mcp-mock-server/src/testing/probe.ts:811
startedAt = Date.now()
const toolNames = new Set<string>()
const discoveredTools: MockTool[] = []
const cursors = new Set<string>()
let cursor: string | undefined
let catalogComplete = false
for (let page = 0; page < 25; page += 1) {
if (cursor) {
if (cursors.has(cursor)) throw new ProbeFailure("MCP_TOOL_DISCOVERY", "mcp_pagination_loop", "Tool catalog repeated a cursor")
cursors.add(cursor)
}
const listRawResponse = await fetchStep(mcpUrl, {
method: "POST",
headers: sessionHeaders,
body: JSON.stringify({ jsonrpc: "2.0", id: 10 + page, method: "tools/list", params: cursor ? { cursor } : {} }),
}, "MCP_TOOL_DISCOVERY", overallDeadline)
if (listRawResponse.status === 403) {
const message = await safeHttpErrorMessage(listRawResponse, "PROVIDER_AUTHORIZATION", "provider_per_user_403")
throw new ProbeFailure("PROVIDER_AUTHORIZATION", "provider_per_user_403", `${message} (HTTP 403)`)
}
const listResponse = await expectOk(listRawResponse, "MCP_TOOL_DISCOVERY")
const envelope = await parseRpc(listResponse, "MCP_TOOL_DISCOVERY")
if (envelope.id !== 10 + page) {
throw new ProbeFailure("MCP_TOOL_DISCOVERY", "mcp_tools_discovery", "tools/list response JSON-RPC id did not match the request")
}
if (envelope.error) throw new ProbeFailure("MCP_TOOL_DISCOVERY", "mcp_tools_discovery", envelope.error.message)
const result = parseAt(
toolsListResultSchema,
envelope.result,
"MCP_TOOL_DISCOVERY",
"mcp_tools_discovery",
"tools/list result did not match the required shape",
)
if (result.nextCursor && cursors.has(result.nextCursor)) {
throw new ProbeFailure("MCP_TOOL_DISCOVERY", "mcp_pagination_loop", "Tool catalog repeated a cursor")
}
for (const rawTool of result.tools) {View on GitHub (pinned to 2b7df46e8a)
Solutions
- Grant the probe's identity the scopes/entitlements needed for tools/list
- Regenerate the synthetic access token with the correct scopes and audience
- Verify server-side authorization policy for per-user tool access
- Check token audience/resource claims match what the MCP resource expects
Example fix
// before
token = issueToken({ scopes: ["mcp:read"] })
// after
token = issueToken({ scopes: ["mcp:read", "mcp:tools:list"] }) Defensive patterns
Strategy: try-catch
Validate before calling
const requiredScopes = ["mcp:tools:list"]
const missing = requiredScopes.filter((s) => !tokenScopes.includes(s))
if (missing.length) throw new Error(`token missing scopes: ${missing.join(",")}`) Type guard
null
Try / catch
try {
await probeEnterpriseMcpMockServer(scenario)
} catch (e) {
if (e instanceof ProbeFailure && e.code === "PROVIDER_AUTHORIZATION") {
console.error("Per-user authorization denied (403):", e.message)
}
} Prevention
- Issue probe tokens with the scopes/entitlements the resource requires
- Verify token audience/resource indicator before running the probe
- Grant the test account tool-catalog access in admin config
When it happens
Trigger: The synthetic access token used by the probe lacks the scope/entitlement required to list tools on the target MCP resource, and the server responds 403 to the tools/list POST.
Common situations: OAuth token issued without the required tool-catalog scope; per-user entitlement not granted to the probe's test account; admin disabled tool access for the user; wrong audience/resource indicator so authorization falls through to a blanket denial.
Understand the failure class
- HTTP status errors: handling 4xx and 5xx responses — how to handle 4xx and 5xx responses properly.
Related errors
- MCP_PROVIDER_HTTP_403
- The MCP provider did not return an authorization URL.
- MCP_PROVIDER_AUTH_REQUIRED
- invalid_mcp_token_payload
- invalid_mcp_connection_payload
AI-assisted analysis of different-ai/openwork@2b7df46e8a (2026-09-01).
Data as JSON: /api/errors/1441dc27d61a2dca.
Report an issue: GitHub.