Skip to content

compliance runner injects idempotency_key on read tools that don't need it #4539

@bokelley

Description

@bokelley

Problem

The compliance storyboard runner (in `@adcp/client`) injects `idempotency_key` on every MCP tool call, including read-only tools like `get_products` and `get_adcp_capabilities` that have no idempotent semantics.

Sellers using Python frameworks with strict defaults (FastMCP, Pydantic `extra='forbid'`) hit `ValidationError` before their handler runs, even though AdCP schemas explicitly allow `additionalProperties: true` and the handler would otherwise just ignore the field.

Originally surfaced as #4399. Closed PR #4405 attempted to fix this via Python-side docs guidance, but that treats the symptom rather than the cause — every Python implementer would have to absorb the workaround independently.

Why the storyboards aren't at fault

Storyboard YAML `sample_request` blocks for read tools do not include `idempotency_key`. The injection happens at runner dispatch time:

```
storyboard YAML → runner builds payload → injects idempotency_key → MCP tool/call
^^^^^^^^^^^^^^^^^^^^^^^^
should be conditional on tool semantics
```

Proposed fix

The runner should not inject `idempotency_key` on read tools. Concretely:

  1. In `@adcp/client`: when dispatching a tool call, check whether the tool is read-only (heuristic: tool name starts with `get_` / `list_`, OR check the tool's declared schema for absence of `idempotency_key` in `properties`). Skip injection on read tools.
  2. Spec clarification: codify "`idempotency_key` SHOULD NOT appear on read-tool requests; if it does, handlers MUST ignore it." in the idempotency docs so we have a normative anchor.

Out of scope

Refs

— Filed during triage 2026-05-13

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions