different-ai/openwork · error

MCP_PROVIDER_HTTP_403

MCP_PROVIDER_HTTP_403

Error message

MCP_PROVIDER_HTTP_403

What it means

MCP_PROVIDER_HTTP_403 is raised when an MCP tool discovery or tool execution request receives HTTP 403 from the provider. It is classified as PROVIDER_AUTHORIZATION / provider_policy_denied and is non-retryable with the provider admin as owner: authentication passed far enough to reach an authorization check, but the provider's role, ACL, or application permission policy denies this specific operation.

Source

Thrown at ee/apps/den-api/src/capability-sources/external-mcp-diagnostics.ts:965

    // enterprise providers: only a Bearer/insufficient_scope challenge means
    // token validation; an ordinary tools/* 403 is usually an ACL/role denial.
    if (status === 401 || input.bearerChallenge || input.insufficientScope) {
      return {
        phase: "AUTH_RESOURCE_VALIDATION",
        category: input.insufficientScope ? "oauth_insufficient_scope" : "oauth_resource_rejected",
        code: input.insufficientScope ? "MCP_OAUTH_INSUFFICIENT_SCOPE" : `MCP_OAUTH_HTTP_${status}`,
        retryable: status === 401,
        actionOwner: input.insufficientScope ? "organization_admin" : "member",
        operatorAction: input.insufficientScope
          ? "Grant the provider scopes required by this MCP resource and reconnect."
          : "Reconnect the provider account and verify token audience, tenant, and resource binding.",
      }
    }
    if (status === 403 && (phase === "MCP_TOOL_DISCOVERY" || phase === "MCP_TOOL_EXECUTION")) {
      return {
        phase: "PROVIDER_AUTHORIZATION",
        category: "provider_policy_denied",
        code: "MCP_PROVIDER_HTTP_403",
        retryable: false,
        actionOwner: "provider_admin",
        operatorAction: "Grant the provider role, ACL, or application permission required for this operation.",
      }
    }
  }
  if (status >= 400) {
    return {
      phase,
      category: "http_failure",
      code: `MCP_HTTP_${status}`,
      retryable: status === 408,
      actionOwner: "provider_admin",
      operatorAction: "Inspect provider and proxy logs for the failing HTTP request using the diagnostic reference.",
    }
  }
  if (phase.startsWith("MCP_") && input.contentType === "text/html") {
    return {

View on GitHub (pinned to 2b7df46e8a)

Solutions

  1. Grant the provider role, ACL, or application permission required for this specific discovery/execution operation.
  2. Confirm which identity the gateway presents to the provider and check its permissions in the provider's admin console.
  3. Re-run the operation after the grant is applied; retries without a permission change will keep failing with 403.

Example fix

// before: token scoped to viewer role calling a mutating tool
await client.callTool({ name: 'delete-record', arguments })
// after: provider admin grants editor role / tool permission, then it succeeds
await client.callTool({ name: 'delete-record', arguments })
Defensive patterns

Strategy: try-catch

Validate before calling

// fail fast: check the identity's granted scopes against the tool's requirement before executing
if (!grantedScovers.includes(tool.requiredPermission)) {
  throw new Error(`missing provider permission ${tool.requiredPermission}`)
}

Type guard

function isProviderAuthzDenied(d: { code: string }): boolean {
  return d.code === 'MCP_PROVIDER_HTTP_403'
}

Try / catch

try {
  return await client.callTool(req)
} catch (e) {
  if (isProviderAuthzDenied(e.diagnostic)) {
    // non-retryable: escalate to provider admin for role/ACL grant
    escalateToProviderAdmin({ operation: req.name, diagnostic: e.diagnostic })
  }
  throw e
}

Prevention

When it happens

Trigger: Calling tools/list (MCP_TOOL_DISCOVERY) or a tool invocation (MCP_TOOL_EXECUTION) against a provider that returns 403 — e.g. the provider token authenticates but the account lacks the role/permission for that tool, or the app is not allow-listed for that operation.

Common situations: Provider API key issued for a read-only role used for a write tool; provider-side ACL changes removing a service account's access; a new tool added on the provider that the existing integration app is not permissioned for; expired or rotated grants on the provider tenant.

Related errors


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