Bug
ADCPClient.get_products() in v7.0.0-rc drops valid canonical format_options and can return an empty product list with FORMAT_PROJECTION_FAILED diagnostics.
Reproduction
Return a valid canonical product from an adapter:
TaskResult(
status=TaskStatus.COMPLETED,
success=True,
data={
"products": [{
"product_id": "p1",
"name": "Product 1",
"description": "A test product",
"publisher_properties": [
{"selection_type": "all", "publisher_domain": "pub.example.com"}
],
"format_options": [{
"format_option_id": "p1-display",
"format_kind": "image",
"params": {"width": 300, "height": 250},
}],
"delivery_type": "non_guaranteed",
"pricing_options": [{
"pricing_model": "cpm",
"pricing_option_id": "po1",
"currency": "USD",
}],
"reporting_capabilities": {
"available_reporting_frequencies": ["daily"],
"expected_delay_minutes": 0,
"timezone": "UTC",
"supports_webhooks": False,
"available_metrics": ["impressions"],
"date_range_support": "date_range",
},
}]
},
)
Calling the primary get_products() method produces no usable canonical product. Direct GetProductsResponse.model_validate() of the response succeeds.
Root cause
_canonicalize_get_products_result() first parses every response as LegacyGetProductsResponse. The generated legacy ProductFormatDeclaration does not declare canonical format_kind or params, so Pydantic discards them before project_legacy_product() runs. The projector consequently receives entries such as:
{"format_option_id": "p1-display", "canonical_formats_only": false, "experimental": false}
instead of the canonical declaration sent on the wire.
Expected behavior
The primary canonical client should parse a valid canonical GetProductsResponse without passing it through a lossy legacy model. Legacy-only responses should continue through the existing projection path.
Impact
Canonical-only sellers can return a valid wire response while Python v7.0.0-rc buyers silently lose those products. Raw MCP consumers are unaffected; the regression is in the high-level Python client canonicalization path.
Bug
ADCPClient.get_products()inv7.0.0-rcdrops valid canonicalformat_optionsand can return an empty product list withFORMAT_PROJECTION_FAILEDdiagnostics.Reproduction
Return a valid canonical product from an adapter:
Calling the primary
get_products()method produces no usable canonical product. DirectGetProductsResponse.model_validate()of the response succeeds.Root cause
_canonicalize_get_products_result()first parses every response asLegacyGetProductsResponse. The generated legacyProductFormatDeclarationdoes not declare canonicalformat_kindorparams, so Pydantic discards them beforeproject_legacy_product()runs. The projector consequently receives entries such as:{"format_option_id": "p1-display", "canonical_formats_only": false, "experimental": false}instead of the canonical declaration sent on the wire.
Expected behavior
The primary canonical client should parse a valid canonical
GetProductsResponsewithout passing it through a lossy legacy model. Legacy-only responses should continue through the existing projection path.Impact
Canonical-only sellers can return a valid wire response while Python
v7.0.0-rcbuyers silently lose those products. Raw MCP consumers are unaffected; the regression is in the high-level Python client canonicalization path.