You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
When a platform method raises `AdcpError(code="MEDIA_BUY_NOT_FOUND", ...)`, the framework today projects it onto the MCP wire as a TEXT payload like `MEDIA_BUY_NOT_FOUND[media_buy_id]: ...`. The structured `CallToolResult.structuredContent.adcp_error.code` field that the AdCP wire spec defines is NOT populated.
Documented as a known limitation in `src/adcp/server/translate.py:246-250`:
Carries `isError=True` AND a structured `adcp_error` object on the same envelope — but `_make_error_result` (`mcp/server/lowlevel/server.py:467`) drops `structuredContent` for error results, so we can't reach...
Why this is biting us now
The AdCP storyboard runner's compliance checks include JSON-pointer assertions like `/adcp_error/code` to verify spec-conformant error responses. With the current text-only projection:
A seller correctly raising `MEDIA_BUY_NOT_FOUND` for an unknown media_buy_id passes the behavioral check (rejected the request)
But fails the wire-shape check (`/adcp_error/code` returns `actual: mcp_error` instead of `MEDIA_BUY_NOT_FOUND`)
This was just surfaced by the multi_platform_seller storyboard fix-pack (PR #508): residual storyboard failures aren't mock bugs — they're SDK wire-projection gaps. Every adopter using `adcp.server.serve` has the same gap.
Proposed fix
Migrate the error-result construction to use FastMCP's path that preserves `structuredContent` on `isError=True` results. The framework should populate:
Where the structured fields are derived from the raised `AdcpError` instance.
Acceptance criteria
`AdcpError` raised from any platform method projects to `structuredContent.adcp_error` with all spec-defined fields (`code`, `message`, `recovery`, optional `field`/`details`)
Storyboard runner's `/adcp_error/code` JSON-pointer assertions pass for correctly-raised errors
Text fallback in `content[]` preserved for human-readable display
Existing tests stay green
Reference: storyboard runner artifacts from multi_platform_seller showing `actual: mcp_error` failures
Upstream issue: adcp-client#1527 (storyboard runner UX) — once this lands, the storyboard runner's structured error checks become useful as a regression gate
Motivation
When a platform method raises `AdcpError(code="MEDIA_BUY_NOT_FOUND", ...)`, the framework today projects it onto the MCP wire as a TEXT payload like `MEDIA_BUY_NOT_FOUND[media_buy_id]: ...`. The structured `CallToolResult.structuredContent.adcp_error.code` field that the AdCP wire spec defines is NOT populated.
Documented as a known limitation in `src/adcp/server/translate.py:246-250`:
Why this is biting us now
The AdCP storyboard runner's compliance checks include JSON-pointer assertions like `/adcp_error/code` to verify spec-conformant error responses. With the current text-only projection:
This was just surfaced by the multi_platform_seller storyboard fix-pack (PR #508): residual storyboard failures aren't mock bugs — they're SDK wire-projection gaps. Every adopter using `adcp.server.serve` has the same gap.
Proposed fix
Migrate the error-result construction to use FastMCP's path that preserves `structuredContent` on `isError=True` results. The framework should populate:
```json
{
"isError": true,
"structuredContent": {
"adcp_error": {
"code": "MEDIA_BUY_NOT_FOUND",
"message": "...",
"recovery": "correctable",
"field": "media_buy_id",
"details": { ... }
}
},
"content": [{"type": "text", "text": ""}]
}
```
Where the structured fields are derived from the raised `AdcpError` instance.
Acceptance criteria
Refs