Skip to content

feat(webhooks): drop extra='allow' token round-trip once adcp#4339 lands #638

@bokelley

Description

@bokelley

Tracking issue for adcontextprotocol/adcp#4339 — promoting the echoed authentication token from an undocumented additionalProperties: true round-trip to a typed property in mcp-webhook-payload.json.

Blocked on

adcontextprotocol/adcp#4339. Nothing to do here until the spec change merges and the schema cache updates.

What changes here when 4339 lands

  1. Regenerate types. Once the spec PR merges, scripts/regenerate_* (or the existing schema sync flow) will produce a McpWebhookPayload whose token is a typed field (Annotated[str | None, Field(...)] = None) instead of an extras-bag entry.

  2. Drop the extras path in create_mcp_webhook_payload. In src/adcp/webhooks.py, the current builder body has a special-case for token:

    # `token` isn't a typed schema field but is accepted via `extra='allow'`;
    # it round-trips through `model_dump`. Tracked upstream for promotion to
    # a typed field on `mcp-webhook-payload.json`.
    extras: dict[str, Any] = {}
    if token is not None:
        extras["token"] = token

    That block goes away. token joins the other typed fields in the model_validate call.

  3. Verify wire parity. The serialized output should be byte-identical pre/post — extra='allow' already round-tripped the field. Add a regression test that a payload built via the typed kwarg matches a hand-built dict on the wire.

  4. Cross-reference downstream. salesagent and any other adopter that reads payload.get("token") from to_wire_dict(...) keeps working (no change in dict shape). Adopters using payload.token as an attribute now get a typed access path instead of model_extra["token"].

Non-goals

  • No behavior change. This is purely typing/ergonomics — token is still optional, still echoed verbatim, still matches the contract in push-notification-config.json.
  • No deprecation needed; the kwarg signature stays the same.

How we'll know it's ready

McpWebhookPayload.model_fields includes token (currently it doesn't — the field surfaces only via model_extra).

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions