different-ai/openwork · error · ProbeFailure
MCP resource rejected the synthetic access token with HTTP $
Error message
MCP resource rejected the synthetic access token with HTTP ${initializeRawResponse.status} What it means
During MCP_INITIALIZE, the probe sends an initialize JSON-RPC request with the freshly obtained access token. If the MCP resource server rejects it with 401 or 403, the probe classifies it as AUTH_RESOURCE_VALIDATION: 403 maps to subcode oauth_insufficient_scope and 401 to oauth_wrong_audience. The message embeds the HTTP status: `"MCP resource rejected the synthetic access token with HTTP ${initializeRawResponse.status}"`. This means the token was issued but does not satisfy the resource server's audience or scope requirements.
Source
Thrown at packages/enterprise-mcp-mock-server/src/testing/probe.ts:738
origin: baseUrl.origin,
}
startedAt = Date.now()
const initializeRawResponse = await fetchStep(mcpUrl, {
method: "POST",
headers: rpcHeaders,
body: JSON.stringify({
jsonrpc: "2.0",
id: 1,
method: "initialize",
params: {
protocolVersion: scenario.protocol.version,
capabilities: {},
clientInfo: { name: "enterprise-mcp-probe", version: "0.1.0" },
},
}),
}, "MCP_INITIALIZE", overallDeadline)
if (initializeRawResponse.status === 401 || initializeRawResponse.status === 403) {
throw new ProbeFailure(
"AUTH_RESOURCE_VALIDATION",
initializeRawResponse.status === 403 ? "oauth_insufficient_scope" : "oauth_wrong_audience",
`MCP resource rejected the synthetic access token with HTTP ${initializeRawResponse.status}`,
)
}
const initializeResponse = await expectOk(initializeRawResponse, "MCP_INITIALIZE")
sessionId = initializeResponse.headers.get("mcp-session-id") ?? ""
negotiatedProtocolHeader = initializeResponse.headers.get("mcp-protocol-version") ?? scenario.protocol.version
const initializeEnvelope = await parseRpc(initializeResponse, "MCP_INITIALIZE")
if (initializeEnvelope.error) {
const versionEvidence = z.object({ supportedVersions: z.array(z.string()).min(1) }).safeParse(initializeEnvelope.error.data)
throw versionEvidence.success || initializeEnvelope.error.message === "Unsupported MCP protocol version"
? new ProbeFailure("MCP_VERSION", "mcp_version", initializeEnvelope.error.message)
: new ProbeFailure("MCP_INITIALIZE", "mcp_initialize", initializeEnvelope.error.message)
}
if (initializeEnvelope.id !== 1) {
throw new ProbeFailure("MCP_INITIALIZE", "mcp_initialize", "Initialize response JSON-RPC id did not match the request")
}View on GitHub (pinned to 2b7df46e8a)
Solutions
- Ensure the token request includes resource: <mcpUrl> and that the AS embeds that audience in the access token so the resource server's 401 audience check passes.
- For 403, add the required scopes to scenario.oauth.authorizationScopes (or grant them on the AS side) so the token carries the scopes the MCP resource enforces.
- Compare the resource server's token-validation config (issuer, audience, required scopes) with the mock AS's issued claims and reconcile the two.
Example fix
// before
authorizeUrl.searchParams.set("scope", "read") // resource requires mcp:tools
// after
authorizeUrl.searchParams.set("scope", "read mcp:tools") Defensive patterns
Strategy: validation
Validate before calling
// decode the access token JWT and check claims before calling initialize
const claims = JSON.parse(Buffer.from(accessToken.split('.')[1], 'base64url').toString())
if (claims.aud !== mcpUrl) throw new Error(`token aud ${claims.aud} != resource ${mcpUrl}`)
if (!requiredScopes.every(s => (claims.scope ?? '').split(' ').includes(s))) throw new Error('token missing required scopes') Try / catch
try {
await probeEnterpriseMcpMockServer(scenario)
} catch (e) {
if (e instanceof ProbeFailure && e.message.includes('rejected the synthetic access token with HTTP 403')) {
console.error('insufficient scope: add required scopes to scenario.oauth.authorizationScopes', e)
} else if (e instanceof ProbeFailure && e.message.includes('with HTTP 401')) {
console.error('wrong audience: pass resource=<mcpUrl> in the token request', e)
} else throw e
} Prevention
- Always pass the MCP URL as the resource/audience parameter in token requests.
- Keep the resource server's required scopes in sync with scenario.oauth.authorizationScopes.
- Verify issued token claims (aud, scope, iss) against the resource server's validation config in CI.
When it happens
Trigger: initializeRawResponse.status is 401 or 403 when POSTing the MCP initialize request with `authorization: Bearer ${accessToken}` at probe.ts:734-740.
Common situations: Authorization server issuing tokens with the wrong `aud` (not equal to the MCP URL passed as the `resource` parameter); token missing the scopes the MCP resource requires; resource-server token-validation middleware (audience/scope checks) tightened while the mock AS lagged behind; clock skew making the token seem invalid.
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/11517b84fe48c7ef.
Report an issue: GitHub.