Skip to main content
When a buyer agent calls an AdCP seller, the response can range from a few seller-planned proposals to a wholesale mirror containing detailed product, signal, and placement metadata. This page covers the controls that keep those responses right-sized—and the client-side projection that matters most.

Interoperability size target

MCP hosts and gateways impose different undocumented response ceilings. For pageable reads and other read-only tasks that offer field projection, AdCP producers SHOULD keep each serialized MCP response at or below 128 KiB (131,072 bytes). This is an interoperability target, not permission for a client to allocate without bounds: clients SHOULD still enforce the streamed whole-message cap described in MCP response extraction, which is itself one instance of the general client obligation to bound every agent response. That cap defaults to 4 MiB, which is also the ceiling on what any client default may be. The 32x gap between the two numbers is not slack a producer may spend: 128 KiB is what a cooperating producer aims at, and 4 MiB is what a client tolerates from one that is hostile or broken. For those read paths, use the task’s cursor, reduce the requested fields or breakdowns, or return a smaller schema-valid page with continuation metadata before the response exceeds 128 KiB. Do not invent a partial response for a task whose schema does not define one. Do not apply the 128 KiB target by turning a completed mutation into an error. If a producer can determine before execution that it cannot return the mutation’s required result within a host limit, it MUST reject the request before side effects. Once side effects occur, it MUST return the schema-valid committed result or a task-defined asynchronous handoff; it must not report failure merely to satisfy the size target. tools/list is cursor-pageable at the MCP layer even though it is not an AdCP task. Servers SHOULD paginate the live tool catalog so each page remains under the same 128 KiB target. Clients that need the complete catalog MUST follow nextCursor until it is absent. Capability-selected tool registration and concise x-tool-summary descriptions reduce each page further; do not publish the full AdCP catalog, response schemas, or long reference prose in a session’s tools/list result. An unpaginated catalog that embeds projected inputSchema documents grows fast: AdCP’s own reference controller projects to 1,220,495 bytes, nearly ten times the 128 KiB target, and a reference seller implementation has served a 23 MB tools/list — past any client cap, which made that agent unreachable rather than merely slow. Pagination is what keeps tools/list inside the target; staying inside the client cap as well is the floor, not the goal.

Discovery responses stay small

Discovery is where an oversized response stops being a degraded experience and becomes a dead end. tools/list, get_adcp_capabilities, and the A2A agent card are the first bytes any counterparty reads from you, and the read aborts mid-body with no adcp_error to branch on. Every later size control on this page assumes discovery already succeeded. Agents SHOULD keep all three surfaces well under the default client cap, and SHOULD paginate a large catalog rather than serve it whole. Only one of these targets is a normative constant; the other two are editorial: Read the agent-card row as a target, not a threshold. A client MUST NOT reject an agent card at 64 KiB — the applicable bound is the 4 MiB client default, and an agent serving a larger card is conformant. The target exists because the card is fetched pre-authentication by every counterparty and every crawler, and because it has no narrowing lever at all: a plain GET, with the authenticated extended card larger rather than smaller. get_adcp_capabilities is the sharpest of the three, because 64 KiB is not merely a client default there. The signing-key discovery path fetches capabilities under MAX_CAPABILITIES_BYTES without narrowing, so a document above that budget fails with request_signature_capabilities_unreachable and the agent’s signing keys stop resolving — immediately for any verifier without a live cached mapping, and within one cache cycle for the rest. That binds any agent that signs requests or webhooks, or that publishes identity.key_origins. A purely non-signing agent is bounded only by the client default, but holding 64 KiB is what lets it start signing later without a discovery break. A buyer can narrow an ordinary capabilities call with protocols[]; the signing-key path cannot. Practical levers, in the order worth reaching for:
  1. Register tools by capability. Publish the tools this session can actually call, not the full AdCP catalog. This is usually the single largest reduction.
  2. Keep tool descriptions terse. Use x-tool-summary; reference documentation by link rather than inlining it. Long reference prose in a tool description is paid for on every session.
  3. Do not inline response schemas. Projected inputSchema documents are the usual reason a catalog clears a megabyte.
  4. Paginate what remains. tools/list is cursor-pageable at the MCP layer; clients that need the whole catalog follow nextCursor until it is absent.
  5. Trim capability declarations to what you support. A capabilities document is a declaration, not a product catalog — move anything enumerable behind a task that can paginate.
Not every byte is self-declared. Two fields enumerate relationships a counterparty asserts: media_buy.portfolio.publisher_domains and signals.data_provider_domains are populated from those counterparties’ own adagents.json, which any domain owner writes unilaterally and without your consent. Mirror either one wholesale and a stranger can inflate your capabilities document past 64 KiB — and since the signing-key path does not narrow, what breaks is your signature verification, a cache cycle after the fact. From 3.3 a normative byte budget caps any single counterparty-asserted field at 8,192 bytes and both together at 16,384, measured as uncompressed serialized JSON; the structural bounds (100 unique entries, 253 chars each) are graded by the conformance storyboard and become schema constraints in 4.0. Select what you actually represent rather than reflecting whatever asserts you; where the real set does not fit, truncate and set publisher_domains_complete: false (or data_provider_domains_complete: false) so buyers resolve authorization per-publisher instead of reading your sample as an allowlist. See Response size bounds. One known tension. creative.supported_formats is the 3.2 source of truth for format discovery — it replaced the pageable list_creative_formats task — so a creative agent with a real format catalog is pushed toward a large capabilities document by the same spec that asks it to stay under 64 KiB. Declare the format contracts you actually build, and track #8198. Note that the budgets above are sub-caps, not an allowance: bounding the counterparty-asserted fields does not buy headroom for a catalog, and a document that clears 64 KiB on self-declared content alone fails the same way. A seller whose discovery response only succeeds against a buyer who raised its cap has not shipped a working integration. It works against that one buyer, against the defaults of none.

Wire response ≠ model context

The single most important point: the bytes on the wire are not what your model has to consume. AdCP responses are structured data. An MCP response arrives as structuredContent — typed JSON that the client parses before any model sees it. An A2A response pairs a human-readable TextPart with an authoritative DataPart. In both cases, a well-built client stores the full response and projects or summarizes it before prompting the next model turn.
If your agent is forwarding raw tool results into the model context unchanged, the fix is in the client, not the protocol. Store the response, extract what the model needs for its next decision, and reference the stored data by ID when details are needed later.
Naive-host caveat. Some MCP hosts pass the entire structuredContent blob into the model context as-is. If you control the host, project before prompting. If you don’t, the controls below become your primary defense against oversized context.

Ask for a plan when you want curation

Use request_proposals when the seller should turn a campaign brief into a small set of actionable plans:
The seller returns immutable draft proposals rather than a catalog page. Use typed refine_proposals requests to narrow the plan without retransmitting the full source response. Use list_products instead when the buyer wants published offers or maintains a wholesale mirror. A mirror is a feed-synchronization topology, not a cheaper proposal mode.

fields selector for lightweight discovery

When you only need a subset of published product data, pass fields to list_products:
This is useful when:
  • Your agent is scanning multiple sellers and only needs IDs and prices for initial comparison
  • You want to skip heavy fields like product_card, product_card_detailed, placements, or signal metadata
  • You’re building a summary view before drilling into specific products
Without fields, the seller returns the full product object — including visual card definitions, placement specs, and any bundled signal metadata. For a first-pass discovery across multiple sellers, that’s more data than you need.

Pagination for cardinality control

list_products uses cursor-based pagination: Response: Pass next_cursor into the next list_products request. A mirror stores feed_version with its cache_scope and uses account-level product webhooks for routine changes. Conditional reads with if_feed_version repair gaps or confirm that a selected feed is unchanged; they do not replace a healthy webhook stream. Paginate; do not ask buyers to raise their limits. A seller whose catalog does not fit inside one response SHOULD return a smaller page with next_cursor rather than emit a single large one. Buyers bound the size of every agent response they read and surface an over-limit response as an error, not as a truncated page, so an oversized reply is not a slow success — it is a failure, and it arrives as a mid-body connection abort rather than as a protocol error the buyer can interpret. A page size that only works against a buyer who raised its limit for you is not interoperable. The same holds for the cursor-pageable tools/list catalog and for every other pageable read in this specification.

Truncation flags on delivery

get_media_buy_delivery returns breakdown arrays (by geo, by creative, by day, etc.) that can grow large. Each breakdown array has a sibling boolean flag — by_geo_truncated, by_creative_truncated, etc. — that tells you whether the returned rows are the complete set or just the top-N: When a flag is true, the returned rows are ordered by the applied sort metric in the applied direction (descending by default — the most significant breakdowns; sort_direction: "asc" deliberately returns the least significant, e.g. worst performers) and the tail is omitted. The response echoes the applied sort per breakdown (by_X_sorted_by / by_X_sort_direction), so a fallback to spend is visible. This is by design: delivery breakdowns are for optimization decisions, not archival reporting. If you need the full dataset, use the seller’s native reporting API.

Putting it together

A token-efficient AdCP integration follows this pattern:
  1. Use request_proposals for seller curation. Ask for plans instead of downloading a feed and prompting a model to rediscover seller expertise.
  2. Use typed refine_proposals. Carry proposal IDs and changes, not the full prior response, into the next turn.
  3. Store raw responses client-side. Don’t feed full product objects into the model context. Extract what matters, summarize the rest.
  4. Read truncation flags before paginating delivery. If by_geo_truncated: false, you already have everything — no need for follow-up calls.
  5. Treat wholesale as synchronization. Bootstrap with list_products, apply product webhooks, and use versioned reads for repair.

Discovery and planning

Choose published offers, wholesale mirroring, or seller-planned proposals.

list_products reference

Field selection, cursor pagination, feed versions, and mirror repair.

Delivery reporting

Breakdown arrays, truncation flags, and sort semantics.

How agents communicate

MCP vs A2A transport and how responses are structured.

Media products

Product structure, product_card vs product_card_detailed, and rendering.