Skip to main content
This page defines the normative algorithm for extracting AdCP success response data from MCP tool results. For error extraction, see Transport Error Mapping.

Layer Separation

Clients MUST check isError before deciding which extraction path to use. A response with isError: true MUST NOT be processed as a success response, even if it contains structuredContent with non-error data.

Extraction Algorithm

Clients MUST extract AdCP data from MCP tool results in this order:
  1. Guard: reject error responses. If isError is truthy, return null. Error extraction is a separate path.
  2. structuredContent — If present and is a non-array object, return it. If the only key is adcp_error, return null (this is an error response missing the isError flag).
  3. Text fallback — Iterate content[] items in array order. For each item where type === 'text', enforce the configured response-size limit, then attempt JSON.parse. If the result is a non-array object, return it. Skip items that fail to parse, parse as non-objects, or contain only an adcp_error key.
  4. No structured data found — Return null. The response is plain text with no machine-readable AdCP data.

Extraction Paths

structuredContent (Preferred)

MCP 2025-03-26 introduced structuredContent for typed tool results. AdCP servers return the full response payload here:
The structuredContent object IS the AdCP response — task-specific fields (products, media_buy_id, status, etc.) are at the top level, not nested. When structuredContent carries the authoritative success payload, content MAY contain a terse human-readable summary. Producers SHOULD NOT serialize the complete AdCP payload again into content[].text; doing so doubles the wire bytes and model-context cost without adding information. A server supporting an older MCP client that cannot read structuredContent MAY instead put the JSON payload in text as the fallback form below and omit structuredContent. It should not emit both full copies.

Text Fallback

Older MCP servers (pre-2025-03-26) serialize the response as JSON in content[].text:
Clients parse the first text item that yields a JSON object. When both structuredContent and text JSON exist, structuredContent takes precedence.

Relationship to Error Extraction

Success and error extraction are complementary:

Security Considerations

Seller-Controlled Data

All data in structuredContent and content[].text is seller-controlled. The same prompt injection and data boundary requirements from Transport Error Mapping apply.

Size Limits

For pageable reads and other read-only tasks that support field projection, producers SHOULD target at most 128 KiB per serialized MCP response; see Managing response size. Clients SHOULD independently enforce a streamed limit on the complete serialized MCP message before buffering or JSON decoding. The recommended client safety limit is 4 MiB (4,194,304 bytes). For text fallback, also check the content[].text size before the inner JSON.parse, against that same limit rather than a tighter one — for a server that returns only content[].text, that item is the entire response, so a sub-limit figure there would silently become the effective cap. The larger safety limit is not a producer target: it bounds hostile or buggy input after normal interoperability guidance has failed. The streamed limit is the MCP instance of the general client obligation to bound every agent response: count bytes as they arrive and abort rather than buffer-then-check, pre-reject an over-limit Content-Length, bound raw and decoded bytes, pair the cap with a deadline, bound JSON depth and node count after the cap passes, and fail with a distinct error instead of truncating. It applies to every MCP response the client reads — tools/call, tools/list, initialize, and the transport-native tasks/get and tasks/result results that carry an async CallToolResult. Leaving the async retrieval path unbounded is the same exhaustion with one extra hop. A Streamable HTTP server MAY answer a POST with a single application/json body or with an SSE stream (text/event-stream), and the bound applies to both — a server does not escape it by choosing SSE. On the SSE path it applies to each event and to the cumulative bytes the client retains for one request, carried across Last-Event-ID resumption rather than reset by it, so an oversized result cannot be split across many frames or across a reconnect. On a non-HTTP transport (stdio) there is no Content-Length to pre-reject; the streaming count and the per-message bound still apply. Clients SHOULD make the limit configurable per agent and per call. 4 MiB is the MCP default and is also the protocol-wide ceiling on a default, so a client raises the limit for a specific agent or a specific call rather than shipping a larger default. Implementations are free to default lower; the 4 MiB figure bounds hostile or buggy input after normal interoperability guidance has failed, and is not a size a producer may aim at.

Prototype Pollution

Clients MUST NOT merge extracted response objects into application state via Object.assign or spread without filtering keys. Seller-controlled keys like __proto__ or constructor can trigger prototype pollution. Validate against the expected task response schema before merging.

Type Confusion

Clients MUST check isError before success extraction. Without this guard, a client could process an error response as success data, leading to incorrect business logic (e.g., treating a RATE_LIMITED error as product data).

Client Library Requirements

Client libraries that implement this spec MUST:
  1. Check isError before extraction. Return null for error responses.
  2. Prefer structuredContent. Only fall back to text parsing when structuredContent is absent.
  3. Validate parsed text. Only accept non-array objects from JSON.parse. Reject arrays, strings, numbers, booleans, and null.
  4. Handle adcp_error-only structuredContent. When structuredContent contains only an adcp_error key, return null — this is an error response that may be missing the isError flag.
  5. Do not require duplicated success data. Treat summary-only content[].text as normal whenever structuredContent is present; never compare it with, or expect it to reproduce, the structured payload.

Test Vectors

Machine-readable test vectors are available at /static/test-vectors/mcp-response-extraction.json. Each vector contains:
  • path: extraction path (structuredContent or text_fallback)
  • response: the MCP tool result envelope
  • expected_data: the AdCP data that should be extracted (or null)
Client libraries SHOULD validate their extraction logic against these vectors.

See Also