fix(server): protocol-polish follow-ups from PR #341#342
Merged
Conversation
ad-tech-protocol-expert called out three follow-ups from PR #341. This PR ships #2 + #3 with concrete fixes; #1 (MCP structuredContent migration) is documented as known-bridge — needs lowlevel Server.call_tool refactor. #3 — Truncation marker buyer-parseability. Pre-fix the MCP ToolError text-suffix path emitted bare '...' as the truncation marker, making buyer json.loads throw JSONDecodeError with no signal of why. Now emits a sentinel object: {_truncated: true, _reason: 'size' | 'non_serializable', _partial: '...'} — ALWAYS valid JSON. Buyers split on '\nDetails: ' prefix, json.loads the tail, and branch on the marker. Iterative fit replaces naive head-room subtract so quote/backslash escaping in _partial doesn't blow past the cap. #2 — caused_by.type Python-only debug breadcrumb. Documented in _internal_error_details that this field is a debug hint for the seller dev reading their own server logs, NOT a cross-language contract. JS sellers won't emit Python-typed exception names. Buyers wanting structured retry/fix/abandon semantics should read 'recovery' (terminal/correctable/transient), which IS the spec contract. #1 — MCP structuredContent migration. Documented as bridge in _to_mcp's docstring with the file:line citation of FastMCP's lossy _make_error_result. The protocol-correct fix needs lowlevel Server.call_tool registration so we can return CallToolResult directly with structuredContent=adcp_error + isError=True; deferred to a separate effort because it touches the FastMCP→ lowlevel boundary throughout serve.py. Tests: 1 updated (truncation now asserts parseable sentinel), 1 new (unserializable details emits sentinel, not malformed JSON). Test count: 2883 (was 2882). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Latest Emma matrix run (post-#341/#342) caught three small DX items all four backends agreed on. Fold into PR #342 since it's the same scope (protocol-polish follow-ups). 1. examples/hello_seller.py:222 — wire-field bug. Stub returned {deliveries: [...]} but the schema at schemas/cache/media-buy/get-media-buy-delivery-response.json requires media_buy_deliveries. A buyer copying this example would get INVALID_RESPONSE on call. Sales 9/10 P1. 2. examples/hello_seller.py docstring overclaims. Module docstring said Three platform methods (get_products, create_media_buy, get_media_buy_delivery) but the class actually implements all five required sales-non-guaranteed methods (per REQUIRED_METHODS_PER_SPECIALISM, validated at boot). Trim the claim to match reality. 3. serve() boot log line. Two of four matrix backends flagged silent-boot — adopters had to curl to confirm the listener was up. Now logs one INFO line at the bind boundary: MCP listening on http://host:port/mcp (transport=streamable-http) for MCP, A2A listening on http://0.0.0.0:port/ for A2A. Framework-controlled (uvicorn's startup log can be filtered/ quieted; this line always lands). Test count: 2883 (existing test_get_media_buy_delivery_returns_zeros updated to assert the spec field name; pins drift). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
ad-tech-protocol-expert called out three follow-ups from PR #341's review before the wire shape becomes de-facto convention. This PR ships the two with concrete fixes; the third (MCP
structuredContentmigration) needs a lowlevelServer.call_toolrefactor and is documented as known-bridge.#3 — Truncation marker buyer-parseability
Pre-fix the MCP ToolError text-suffix path emitted bare
...as the truncation marker, which made buyerjson.loadsthrowJSONDecodeErrorwith no signal of why. Now emits a sentinel object:{"_truncated": true, "_reason": "size" | "non_serializable", "_partial": "..."}— always valid JSON. Buyers split on\nDetails:prefix,json.loadsthe tail, and branch on the marker. Iterative fit replaces naive head-room subtract so quote/backslash escaping in_partialdoesn't blow past the cap.#2 —
caused_by.typecross-language documentationDocumented in
_internal_error_detailsthat this field is a debug hint for the seller dev reading their own server logs, NOT a cross-language contract. JS sellers won't emit Python-typed exception names. Buyers wanting structured retry/fix/abandon semantics should readrecovery(terminal/correctable/transient), which IS the spec contract.#1 — MCP
structuredContentmigration (deferred + documented)_to_mcp's docstring now cites FastMCP's lossy_make_error_result(mcp/server/lowlevel/server.py:467) as the reason text-suffix is the working bridge. The protocol-correct fix needs lowlevelServer.call_toolregistration so we can returnCallToolResult(structuredContent={"adcp_error": ...}, isError=True)directly. Deferred to a separate effort — touches the FastMCP→lowlevel boundary throughout serve.py.Test plan
...suffix)🤖 Generated with Claude Code