A coding agent wiring Google Authorized Buyers integration calls validate_bid_request on the RTBlint MCP server. The tool returns "valid": true. The payload still fails on Google's side.
The request is not malformed OpenRTB. It is the wrong contract for the exchange you are targeting:
{
"id": "req-1",
"at": 3,
"imp": [{
"id": "1",
"banner": { "w": 300, "h": 250 }
}]
}
at: 3 is FIXED_PRICE in Google's Authorized Buyers OpenRTB guide. The IAB spec's auction type value set is {1, 2} plus vendor values from 500 upward. Three sits in the gap. Without Google's profile declared, a linter correctly flags it as illegal.
The imp is also missing ext.billing_id. Google documents that array as required: the billing IDs a winning bid may attribute the impression to. The specification treats it as an optional extension. A spec-only validator has nothing to complain about.
profile is not dialect
MCP exposes both knobs on validate_bid_request and validate_bid_response:
-
dialect:spec-json(integer flags likesecure: 1) vsproto-json(boolean flags for gRPC protobuf JSON). -
profile:spec(default),google-ab,prebid-server,xandr, ormagnite.
Dialect is encoding. Profile is the extra protocol an exchange publishes on top of the same JSON shape. Google Authorized Buyers still uses integer flags. It still needs profile=google-ab because the auction type table and required extensions differ.
An agent that learned OpenRTB from spec PDFs and training snapshots will produce at: 1 or at: 2 and skip billing_id. An agent that learned from Google's docs will emit at: 3 and expect billing fields. Point both at MCP with defaults and only the second payload looks broken, even though only the first is deliverable to Google without fixes.
What the default tool call actually checks
I maintain RTBlint, an open source OpenRTB linter. The hosted MCP server wraps the same core as the CLI and the browser tester.
Against the default profile:
$ rtblint validate bid.json
FAILED (OpenRTB 2.6-202606 bid request): 1 error(s), 0 warning(s).
- [error] at: at is 3, which is not among the allowed values {1, 2}.
(openrtb.value.invalid) · spec 3.2.1
No mention of billing_id, because the spec does not require it.
Pass the profile Google documents:
$ rtblint validate --profile google-ab bid-with-at3.json
FAILED (OpenRTB 2.6-202606 bid request): 1 error(s), 0 warning(s).
- [error] imp[0].ext.billing_id: Google Authorized Buyers requires
imp.ext.billing_id. (openrtb.profile.field_required) · profile google-ab
$ rtblint validate --profile google-ab google-ready.json
OK (OpenRTB 2.6-202606 bid request): no issues found.
Same JSON. Three different verdicts depending on whether you declared the exchange protocol.
Over MCP the shape is identical. The agent passes profile in the tool arguments:
{
"payload": "{ ... }",
"profile": "google-ab"
}
The OpenRTB MCP validator docs and the full MCP tool reference list every argument. The server card at /.well-known/mcp/server-card.json enumerates the profile enum for clients that auto-wire tools.
Why this shows up on agent loops
Registering an MCP server is not validating against the exchange that will receive the traffic. get_adcp_capabilities tells an AdCP pipeline that RTBlint computes openrtb_error_count and related metrics. It does not pin google-ab, prebid-server, or any other profile. Discovery answers what the tool can do, not which protocol variant your deployment targets.
That gap matters in agentic buying stacks where the same MCP host validates bid requests coming out of an AdCP media buy. The AdCP to OpenRTB mapping guide is where field-level translation lives. Profile selection is the step after mapping: once the object looks like OpenRTB, you still have to name the exchange extras.
Prebid Server is the same class of bug under a different profile. Each imp must name a bidder or stored request, and several Prebid-only extensions become required. Xandr expects ext.appnexus.seller_member_id. Magnite expects ext.rp identity fields. Default profile=spec validates none of that.
How I wire it in practice
For a human review pass, paste request and response into the tester with the profile dropdown set to Google AB. The UI surfaces the same rule ids as MCP.
For CI or a local agent loop:
$ cargo install rtblint
$ rtblint validate --profile google-ab --type request req.json
The CLI docs cover batch mode, version pinning, and dialect flags. The OpenRTB overview ties profiles, dialects, and dated spec snapshots together.
If payloads must not leave the network, run rtblint-mcp over stdio with the same tool names. The hosted endpoint may store stripped samples under its privacy policy; local stdio does not.
The short version
validate_bid_request without profile checks the IAB specification, not Google Authorized Buyers, not Prebid Server, not Xandr, not Magnite.
For Google AB, pass profile=google-ab before you trust valid: true. FIXED_PRICE (at: 3) becomes legal. Missing Imp.ext.billing_id becomes an error instead of silence.
An MCP tool registration proves the agent can call a validator. It does not prove the validator ran against the exchange that will answer the auction.
RTBlint is independent of Google and IAB Tech Lab. The rule ids above cite the public spec and Google's OpenRTB guide because that is where the requirements live.
Top comments (0)