different-ai/openwork · error · ExternalMcpDiagnosticError

MCP_PROVIDER_INVALID_PARAMS|MCP_PROVIDER_HTTP_403|MCP_PROVIDER_HTTP_429

MCP_PROVIDER_INVALID_PARAMS|MCP_PROVIDER_HTTP_403|MCP_PROVIDER_HTTP_429

Error message

MCP provider tool execution failed (${result})

What it means

When Den executes a tool on an external MCP provider via client.callTool and the provider responds with isError true, providerToolDiagnosticError converts the result into a diagnostic error. The message embeds the provider's serialized result, and the code can be one of MCP_PROVIDER_INVALID_PARAMS, MCP_PROVIDER_HTTP_403, or MCP_PROVIDER_HTTP_429 depending on what the provider reported (tool call timeout is EXTERNAL_MCP_TOOL_CALL_TIMEOUT_MS = 120s).

Source

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

  let operationError: unknown
  try {
    await runExternalMcpRequestWithinDeadline({
      deadline,
      diagnostic,
      phase: "MCP_INITIALIZE",
      operation: (options) => client.connect(transport, options),
    })
    diagnostic.passed("MCP_INITIALIZED", "protocol_ready")
    diagnostic.begin("MCP_TOOL_EXECUTION")
    const result = await runExternalMcpRequestWithinDeadline({
      deadline,
      diagnostic,
      phase: "MCP_TOOL_EXECUTION",
      requestTimeoutMs: EXTERNAL_MCP_TOOL_CALL_TIMEOUT_MS,
      operation: (options) => client.callTool({ name: input.toolName, arguments: input.args }, undefined, options),
    })
    if (result.isError) {
      throw providerToolDiagnosticError({ tracker: diagnostic, result })
    }
    diagnostic.passed("PROVIDER_EXECUTION", "operation_ready")
    return result
  } catch (error) {
    operationError = error
    throw diagnostic.error(error)
  } finally {
    try {
      await client.close()
    } catch (error) {
      if (!operationError) throw diagnostic.error(error, "SHUTDOWN")
    }
  }
}

export function callExternalMcpTool(input: ExternalMcpToolCallInput) {
  return runExternalMcpToolCall(input)
}

View on GitHub (pinned to 2b7df46e8a)

Solutions

  1. Inspect the embedded provider result in the message; fix the tool arguments to match the tool's declared input schema.
  2. For HTTP_403: reconnect the provider via the Connect flow and verify the granted OAuth scopes include the tool.
  3. For HTTP_429: reduce call frequency / add backoff and retry later.
  4. Re-run tool discovery to pick up changed schemas, then retry the call.

Example fix

// before: args guessed from memory
run: callTool({ name: 'sheet.append', arguments: { row: data } })
// after: validate against the tool's schema from tools/list
run: callTool({ name: 'sheet.append', arguments: { values: data } }) // matches inputSchema.properties.values
Defensive patterns

Strategy: try-catch

Validate before calling

// validate args against the tool's inputSchema before calling
const parsed = toolInputSchema.safeParse(args)
if (!parsed.success) throw new Error(`invalid args for ${toolName}: ${parsed.error.message}`)

Type guard

function isProviderErrorResult(r: unknown): r is { isError: true; content: unknown } {
  return typeof r === 'object' && r !== null && 'isError' in r && (r as { isError: boolean }).isError === true
}

Try / catch

try {
  result = await client.callTool({ name, arguments: args })
} catch (error) {
  const code = (error as { code?: string }).code ?? ''
  if (code === 'MCP_PROVIDER_HTTP_429') await backoffAndRetry()
  else if (code === 'MCP_PROVIDER_HTTP_403') promptReconnect()
  else if (code === 'MCP_PROVIDER_INVALID_PARAMS') fixArgsAgainstSchema()
  else throw error
}

Prevention

When it happens

Trigger: Calling a marketplace/external MCP tool where the provider replies with an error result: invalid arguments against the tool's input schema (INVALID_PARAMS), the provider rejecting the request with HTTP 403 (authz/permission), or HTTP 429 (rate limit) during the callTool operation.

Common situations: Sending arguments that don't match the tool's schema (missing required field, wrong type); OAuth token for the connection lacking scope for the tool; hitting the provider's rate limit from bursts or shared egress IPs; provider-side breaking changes to the tool's parameters.

Related errors


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