MCP Ad Format Specification v1.0
Status: Draft (g1.network, 2026-05-11). Phase 0.5 deliverable.
Authors: g1-adtech team
Submission target: IAB Tech Lab draft extension (no acceptance dependency — we ship our own).
Implements: OpenRTB 2.6 + imp.mcp extension + ext.agent + bid response markdown payload.
Reference implementation: @theg1team/openrtb v0.1.0 (g1-platform/packages/openrtb/).
Spec lifetime: SemVer; breaking changes = major bump + 12mo deprecation notice.
Abstract
MCP Ads define a programmatic ad format for AI-agent surfaces — surfaces где user interaction happens through an LLM-backed client (Claude.ai, Cursor, agent-served chat, MCP-protocol tools) rather than a traditional web/PWA/app surface. The format extends OpenRTB 2.6 with an imp.mcp BidRequest extension carrying conversational context, an ext.agent identifier identifying the AI client, and a structured BidResponse payload (markdown + image URL + JSON metadata) suitable for inline rendering inside an LLM response stream.
Three properties make MCP Ads different from traditional ad formats и motivate this spec:
- Inventory location — the ad surface is не a DOM tree or video player; it’s a token stream rendered by an LLM client. Display semantics are textual + image links, no iframe/SafeFrame/MRAID.
- Targeting signal — the primary signal is the conversational context at the moment of the ad request, not page URL / search query / app screen.
- Billing trust root — beacons are unreliable (AI clients may strip URLs, cache, dedup). Billing source-of-truth is an explicit SDK render-confirmation POST; beacons are 0.5x weight fallback only.
This spec specifies wire format, AI client authentication, render-confirmation semantics, user opt-out, localization, brand safety, frequency capping, and compliance disclosure.
1. Terminology
AI client / client app — a software product that renders MCP Ads inside its responses (e.g., Claude.ai web/desktop, Cursor IDE, third-party agent surface). Identified by client_app slug; whitelisted server-side before serving.
MCP gateway — mcp.g1.network; the entry point for AI clients calling ads_serve_for_context. Validates the client JWT and forwards to RTB.
Conversation — an AI-client-managed session с stable identifier (conversation_id UUID v4). Bounds frequency-cap, vertical-lock, и skip-flag scope.
BidRequest (BR) / BidResponse (BResp) — OpenRTB 2.6 message envelopes. Per this spec, imp.mcp extension carries MCP-specific signals; bid.ext.mcp carries the response payload.
Render confirmation (RC) — POST /api/v1/mcp-ads/render-confirm from the AI client SDK with signed imp_id + render timestamp. RC is the billing source of truth.
Beacon — HTTP GET pixel embedded in the markdown body, fired only by AI clients that preserve URLs. Counted as 0.5x impression weight (fallback only); no charge if RC missing.
Sponsored label — mandatory localized disclosure (“Sponsored”, “Реклама”, “Werbung”, …) rendered inline по FTC Endorsement Guides + EU DSA Article 26.
2. Scope
In scope:
- OpenRTB 2.6 BidRequest extension for MCP inventory (
imp.mcp,ext.agent). - BidResponse markdown + image URL + JSON metadata payload contract.
- AI client SDK authentication (OAuth client_credentials → short-lived JWT).
- Render-confirmation POST endpoint contract.
- User skip mechanism (g1-side flag).
- Frequency capping rules (per conversation + density).
- Brand safety (per-conversation IAB v3 vertical lock + sensitive-cat cooldown).
- Mandatory
Sponsoredlabel с per-locale localization.
Out of scope (deferred):
- Voice mode (SSML payload) — Phase 11+.
- LLM-tied creative templates (
{{user_topic}}etc.) — Phase 9+ optional advertiser feature. - Click attribution conventions — defined separately (signed
click_tokenreferenced here; cross-funnel handling lives в g1-affiliates spec). - ads.cert wire-level signature for MCP BR — uses existing ads.cert 1.0 spec (
@theg1team/openrtb/ads-cert).
3. Architecture overview
┌─────────────────────┐
│ AI client (e.g. │
│ Claude.ai, Cursor) │
└──────────┬──────────┘
│ 1. ads_serve_for_context (MCP tool call)
│ headers: x-mcp-ads-client-token (JWT)
▼
┌─────────────────────┐
│ mcp.g1.network │ ← OAuth client_credentials issuer
│ gateway │ ← JWT validation
└──────────┬──────────┘
│ 2. BidRequest (OpenRTB 2.6 + imp.mcp)
▼
┌─────────────────────┐
│ rtb.g1.network │ ← contextual targeting + vertical lock
│ │ ← own LLM context verifier (Claude Haiku)
│ │ ← DV/IAS pre-flight (creative side)
│ │ ← per-client_app QPS quota + burst
└──────────┬──────────┘
│ 3. BidResponse (markdown + image + JSON metadata)
▼
┌─────────────────────┐
│ AI client renders │
│ inline + 'Sponsored' │
│ label localized │
└──────────┬──────────┘
│ 4a. render-confirm POST (billing source of truth)
│ 4b. (fallback) beacon GET on markdown URL
▼
┌─────────────────────┐
│ adserver.g1.network │ ← record impression
│ │ ← signed click_token redirect on click
└─────────────────────┘
4. BidRequest extensions
4.1 imp.mcp
The mcp extension lives at Imp.ext.mcp in the OpenRTB 2.6 BidRequest. Presence of imp.mcp signals an MCP impression и triggers MCP-specific bidding/serving paths.
| Field | Type | Required | Description |
|---|---|---|---|
context_summary | string ≤2048 | yes | LLM-friendly excerpt of recent conversation turns. Used для contextual targeting + re-classification on EVERY bid (no caching). |
conversation_id | string (UUID v4) | yes | Stable per-conversation identifier. Drives freq cap + competitive separation (vertical lock) + skip flag scope. |
message_index | int ≥0 | yes | 0-indexed message count within conversation. Used для ad density rule (см. § 8). |
agent | AgentExt | yes | AI agent identity (см. § 4.2). |
locale | string (BCP-47) | optional | Conversation locale (e.g., en-US, pt-BR, ja-JP). Drives Sponsored label localization. |
user_id_hash | string (64 hex chars) | optional | SHA-256 hash of stable g1-side user_id. Drives skip flag lookup в mcp_ads_user_prefs (см. § 7). Required для skip-eligible inventory. |
ext | object | optional | Reserved for non-IAB extensions (e.g., vendor-specific scoring hints). |
4.2 ext.agent (AgentExt)
The agent identity is part of imp.mcp.agent (and MAY be additionally surfaced at top-level ext.agent for non-MCP envelopes referencing the same AI client).
| Field | Type | Required | Description |
|---|---|---|---|
kind | "web" | "mcp" | yes | mcp = AI-agent-served surface; web = traditional inventory (legacy compat). |
model | string | optional | Model name as known to the AI client (e.g., claude-opus-4-7, gpt-4o). Used для audit + ML segmentation. |
client_app | string | yes | Approved AI client app slug (matches mcp_ai_clients_whitelist.client_app_id). |
Important: agent is self-attested by the AI client. The trust root is the JWT transported in x-mcp-ads-client-token (см. § 6), not agent.client_app. Receivers SHOULD compare agent.client_app against the JWT’s sub claim and reject mismatches.
4.3 Example BidRequest (MCP impression)
{
"id": "auction-01HXYZ123ABC",
"imp": [
{
"id": "imp-1",
"bidfloor": 1.50,
"bidfloorcur": "USD",
"ext": {
"mcp": {
"context_summary": "User is planning a 5-day trip to Tokyo in November, asking about JR Pass pricing and best neighborhoods to stay in for first-time visitors.",
"conversation_id": "550e8400-e29b-41d4-a716-446655440000",
"message_index": 7,
"agent": {
"kind": "mcp",
"model": "claude-opus-4-7",
"client_app": "claude-ai"
},
"locale": "en-US",
"user_id_hash": "a3f5b7c9d1e2f4a6b8c0d2e4f6a8b0c2d4e6f8a0b2c4d6e8f0a2b4c6d8e0f2a4"
}
}
}
],
"site": null,
"user": {
"consent": "CPxxx.YAAAAAAAAA"
},
"regs": {
"gdpr": 1,
"gpp": "DBABL~BVQqAAAAAgA.QA",
"gpp_sid": [7]
},
"source": {
"schain": {
"complete": 1,
"nodes": [{ "asi": "mcp.g1.network", "sid": "g1-mcp-ads-pub", "hp": 1 }]
}
},
"at": 1,
"tmax": 100,
"cur": ["USD"]
}
5. BidResponse contract
5.1 bid.ext.mcp (BidMcpPayload)
The response payload lives at Bid.ext.mcp. Bid.adm MAY be empty или contain a legacy-compat markdown fallback (matching bid.ext.mcp.markdown). When both are present, bid.ext.mcp wins.
| Field | Type | Required | Description |
|---|---|---|---|
markdown | string ≤4096 | yes | Markdown body. MAY reference image_url. NO inline base64 images. |
image_url | string (URL) | optional | Image pointer (R2 signed URL, CDN, or absolute https://). |
advertiser | string | yes | Advertiser display name (matches dsp_advertisers.name). |
cta | string | optional | Call-to-action text (e.g., "Get 20% off →"). MAY appear в markdown directly. |
click_token | string | yes | HMAC-SHA256 signed click token (см. § 9). Required for click attribution. |
sponsored_label | string | yes (defaults "Sponsored") | Localized disclosure string. Rendered by AI client. См. § 9. |
sponsored_label_locale | string (BCP-47) | optional | Matched against imp.mcp.locale. |
integrity_hash | string (hex) | optional | Hash of canonical advertiser metadata. Used for tamper-detect post-render. |
5.2 Markdown rules
- MUST be valid CommonMark.
- MUST contain
sponsored_labeltext rendered inline (typically as the first non-image element). - MUST NOT contain
<script>tags,<iframe>,<form>, or any HTML element other than<br>,<em>,<strong>,<sub>,<sup>,<u>,<del>. AI clients SHOULD sanitize defensively. - Image links use
image_urlfield, not inline base64. - Click links MUST use signed
click_tokenURL (см. § 9). Direct advertiser-domain links are PROHIBITED.
5.3 Example BidResponse
{
"id": "auction-01HXYZ123ABC",
"cur": "USD",
"seatbid": [
{
"seat": "dsp.g1.network",
"bid": [
{
"id": "bid-9X",
"impid": "imp-1",
"price": 2.40,
"adid": "ad-tokyo-jr-pass-2026",
"adomain": ["jrpass.com"],
"crid": "creative-jr-pass-v3-en",
"lurl": "https://dsp.g1.network/lurl?bid=${AUCTION_LOSS}",
"mtype": 1,
"ext": {
"mcp": {
"markdown": "**Sponsored** · 🚆 **JR Pass — your unlimited bullet train ticket for Japan.** Pre-order online, save up to 25% vs. station prices. Valid 7/14/21 days. [Get yours →](https://adserver.g1.network/click?t=eyJ...signed...)",
"image_url": "https://cdn.g1.network/r2/creative/jrpass-2026-banner.webp",
"advertiser": "Japan Rail Pass Official",
"cta": "Get yours →",
"click_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpbXBfaWQiOiI...",
"sponsored_label": "Sponsored",
"sponsored_label_locale": "en-US",
"integrity_hash": "3a7f9b2c1d8e4f5a6b9c2d8e1f4a7b3c"
}
}
}
]
}
]
}
5.4 No-bid
A no-bid response uses standard OpenRTB nbr codes. MCP-specific reasons MAY use vendor-specific codes ≥200 (e.g., MCP_SKIPPED = 250 for user_id_hash matching skip flag).
6. AI client authentication
Each MCP BidRequest from an AI client MUST include the header:
x-mcp-ads-client-token: <JWT>
The JWT is issued by auth.g1.network (g1-auth-oidc) via the OAuth 2.0 client_credentials flow. Properties:
- Issuer (
iss):https://auth.g1.network/ - Subject (
sub): the approvedclient_appslug (e.g.,"claude-ai") - Audience (
aud):mcp.g1.network - Issued at (
iat): seconds since epoch - Expiration (
exp):iat + 300(5 minutes). Tokens beyond 5 min are rejected. - Algorithm: RS256, signed by
auth.g1.networkJWKS (/.well-known/jwks.json). - Claims:
client_app— same assub, redundancy for ergonomic accessscopes— array MUST includeads:serve-for-contextjti— nonce, used for replay detection (5-minute window)
6.1 Validation
Receivers (gateway + RTB runtime) MUST:
- Reject if JWT signature does not validate against current
auth.g1.networkJWKS. - Reject if
expis in the past or > 5 min in the future. - Reject if
aud≠mcp.g1.networkoriss≠https://auth.g1.network/. - Reject if
scopesdoes not includeads:serve-for-context. - Reject if
imp.mcp.agent.client_app≠ JWTsub. - Reject if same
jtiwas seen in the last 5 minutes (replay). - SHOULD enforce per-client_app QPS quota (см.
mcp_ai_clients_whitelist.qps_quota+qps_burst).
6.2 Defense in depth
JWT is the trust root. Whitelist (mcp_ai_clients_whitelist.status = 'approved') and behavior heuristics (fingerprint anomalies, sudden QPS spikes, geographic inconsistencies) are defense-in-depth layers. None of them alone is sufficient.
7. Skip mechanism
7.1 g1-side flag
Users may opt out of MCP Ads. The flag lives server-side в mcp_ads_user_prefs table:
mcp_ads_user_prefs:
user_id_hash TEXT PRIMARY KEY, -- SHA-256 hex (64 chars)
skip BOOL NOT NULL DEFAULT FALSE,
updated_at TIMESTAMP NOT NULL
The flag is NOT tied to any AI client subscription. AI clients pass imp.mcp.user_id_hash in the BidRequest; the RTB backend looks up the flag и returns no-bid (nbr = 250 MCP_SKIPPED) if skip = TRUE.
7.2 Setting the flag
Users set the flag via:
cmp.g1.network/preferencesself-service portal (DSAR-adjacent UI).- API call to
cmp-api.g1.network/api/v1/mcp-ads/skip(OIDC user JWT). - AI client may surface the toggle in its own UI; on toggle, the AI client SHOULD POST to the same endpoint on the user’s behalf.
7.3 Privacy
user_id_hash is a one-way SHA-256 of an internal stable identifier. The hash space is sufficient (2^256) to make rainbow-table attacks infeasible. The plaintext user_id is never sent to AI clients; only the hash.
8. Frequency capping + density
8.1 Rules
| Rule | Default value | Configurable |
|---|---|---|
| Min interval | 1 ad per conversation baseline | yes (per ad-unit) |
| Density | 1 additional ad per 50 messages в long conversations | yes |
| Hard cap | 5 ads per conversation total | yes |
| Per-user cap | 10 ads per user per 24h across all conversations | yes |
| Vertical lock | 1 IAB v3 vertical per conversation (см. § 9) | yes |
8.2 Enforcement
Enforcement uses mcp_ads_impressions (Turso) + Durable Object freq-cap state keyed by conversation_id + user_id_hash (if present). Fallback to ip_hash если neither.
8.3 Density formula
ads_allowed_so_far(message_index) = 1 + floor((message_index - 1) / 50)
ads_served_so_far(conversation_id) = count(mcp_ads_impressions WHERE conversation_id = ?)
serve_eligible = ads_served_so_far < min(ads_allowed_so_far, hard_cap)
9. Brand safety
9.1 Per-conversation vertical lock
The first won impression in a conversation establishes the IAB v3 vertical (category lock). Subsequent impressions within that conversation MUST share or be a sibling of the locked vertical (competitive separation). Stored в mcp_ads_conversations.locked_iab_v3_cat.
9.2 Re-classification on every bid
imp.mcp.context_summary is sent through the own LLM context verifier (Claude Haiku) on EVERY bid request — no caching. Output: IAB v3 cat list + sensitive-cat flag.
9.3 Sensitive-cat cooldown
If the verifier marks the conversation context as sensitive (e.g., IAB v3 Sensitive Social Issues, Adult Content, Crime & Public Safety, …), the conversation enters a 24-hour cooldown during which no ads are served, regardless of advertiser bid.
9.4 Mandatory Sponsored label
Per FTC Endorsement Guides и EU DSA Article 26, every served ad MUST include a localized “Sponsored” label inline в the markdown body. The label MUST be visually distinguishable (bold or italic acceptable). Default English text "Sponsored"; per-locale overrides specified in bid.ext.mcp.sponsored_label field. Recommended locale values:
| BCP-47 | Label |
|---|---|
en-US / en-GB | Sponsored |
de-DE | Werbung |
es-ES | Patrocinado |
fr-FR / fr-CA | Sponsorisé |
pt-BR | Patrocinado |
ja-JP | スポンサー |
zh-Hant | 贊助內容 |
9.5 Click token
bid.ext.mcp.click_token is a JWT-style signed token (HMAC-SHA256, see @theg1team/openrtb/ads-cert) containing:
| Claim | Description |
|---|---|
imp_id | Impression UUID |
creative_id | dsp_creatives.id |
advertiser_id | dsp_advertisers.id |
dest_url | Destination URL after redirect |
iat | Issued at |
exp | Issued at + 7 days |
The click endpoint (adserver.g1.network/click?t=<token>) verifies signature, records the click in mcp_ads_clicks, и 302-redirects to dest_url.
10. Render confirmation
10.1 Endpoint
POST https://adserver.g1.network/api/v1/mcp-ads/render-confirm
Content-Type: application/json
x-mcp-ads-client-token: <JWT, same format as § 6>
10.2 Payload
{
imp_id: string, // UUID v4 of the served impression
rendered_at: number, // Unix milliseconds; must be ≤30s from now
client_token: string, // SDK's JWT (redundant w/ header; verified)
viewability?: number // [0..1], optional SDK-measured viewability
}
10.3 Semantics
- A successful RC counts as 1.0x impression weight для billing.
- Receivers MUST verify:
- JWT signature + claims (см. § 6).
imp_idexists inmcp_ads_impressionstable withserved_creativematching the request.rendered_atis within ±60s of server time.- RC has not already been recorded для same
imp_id(deduplication).
- If RC is missing within 30 seconds of bid response, beacon GET MAY count як 0.5x weight fallback.
- If neither RC nor beacon arrives within 5 minutes, impression is recorded but not billed (drop).
10.4 Response
200 OK
{
"recorded": true,
"billed_weight": 1.0
}
4xx если invalid (no body charging):
400 → schema/JWT invalid
404 → imp_id not found
409 → already confirmed (deduplication)
422 → rendered_at outside window
11. Errors + NBR codes
Standard OpenRTB nbr reason codes apply (см. @theg1team/openrtb NBR constants). MCP-specific reasons (vendor-extension codes ≥200):
| Code | Symbol | Reason |
|---|---|---|
| 200 | BLOCKED_ADVERTISER | Bid blocked by bcat / badv |
| 201 | BLOCKED_CATEGORY | IAB v3 category blocked |
| 202 | NO_CREATIVE_MATCH | No eligible creative |
| 203 | NO_BID_BUDGET | Advertiser budget exhausted |
| 204 | BELOW_FLOOR | Bid below floor |
| 250 | MCP_SKIPPED | User has skip flag set (§ 7) |
| 251 | MCP_SENSITIVE_COOLDOWN | Conversation в sensitive-cat cooldown (§ 9.3) |
| 252 | MCP_VERTICAL_LOCKED | Locked vertical mismatch (§ 9.1) |
| 253 | MCP_FREQ_CAP_HIT | Conversation or user freq cap exhausted (§ 8) |
| 254 | MCP_JWT_INVALID | Client JWT failed verification (см. § 6.1) |
| 255 | MCP_CLIENT_NOT_WHITELISTED | client_app not approved или suspended |
| 256 | MCP_QPS_QUOTA_EXCEEDED | Per-client_app QPS quota hit |
12. Compliance
12.1 FTC Endorsement Guides (US)
Every served ad MUST display a clear, unambiguous “Sponsored” label (§ 9.4). The label MUST appear inline within the rendered content, not in a hover-state or expandable section.
12.2 EU DSA Article 26
Same requirement; for European jurisdictions, also requires reasoning why the ad is shown to a particular user available на demand. This is provided via:
- Aggregate transparency report at
docs.g1.network/adtech/mcp-ads/transparency(refreshed quarterly). - Per-impression reasoning available at
/api/v1/mcp-ads/impressions/<imp_id>/why(OIDC user JWT).
12.3 Consent + GDPR
- The TC string (
User.consent) and GPP string (Regs.gpp+gpp_sid) MUST be passed in BidRequest for EU/UK/CH jurisdictions. - If
Regs.gdpr = 1and no purpose-1 (storage/access) consent, contextual targeting is allowed ноuser_id_hashlookup для skip-flag MUST be skipped (user is treated as opted-out).
12.4 Children (COPPA)
If Regs.coppa = 1, MCP Ads MUST NOT serve.
12.5 Material adverse change notice
If the AI client’s terms или ad rendering behavior materially changes, the AI client MUST notify g1 ≥30 days в advance (re: mcp_ai_clients_whitelist.docusign_envelope_id).
13. Security considerations
- Prompt injection в
context_summary— Adversarial users may craft conversation context to influence bidding (e.g., insert fake brand mentions). Counter: own LLM context verifier (§ 9.2) treats context as untrusted input; never executes / interprets it як instructions. - JWT replay —
jti+ 5-min window (§ 6.1.6). - Click token forgery — HMAC-SHA256 секрет rotated 30d.
- Render confirmation forgery — RC requires valid JWT + matching
imp_id(which was returned only to the JWT subject). Cross-client RC submission is rejected (§ 10.3). - Beacon stripping — Acknowledged. RC is primary billing path; beacon is fallback. Persistent beacon-only patterns from a
client_appSHOULD trigger billing dispute review. user_id_hashcorrelation — Hash is one-way; AI clients cannot recoveruser_id. Multipleuser_id_hash-es from same user across AI clients are unlinked (differentuser_idper AI client identity binding, when applicable).- MCP gateway abuse — Per-
client_appQPS quotas + circuit breakers (§ 6.1.7). Outliers fed in real-time to anomaly detection (Axiomg1-trace-idcorrelation).
14. Localization registry
Initial 7 supported locales (Phase 5b launch = EN; Phase 6 GA adds remaining 6):
| BCP-47 | Sponsored label | Cooldown text key | Active phase |
|---|---|---|---|
en-US | Sponsored | mcp.cooldown.en | 5b pilot |
en-GB | Sponsored | mcp.cooldown.en | 6 GA |
de-DE | Werbung | mcp.cooldown.de | 6 GA |
es-ES | Patrocinado | mcp.cooldown.es | 6 GA |
fr-FR | Sponsorisé | mcp.cooldown.fr | 6 GA |
pt-BR | Patrocinado | mcp.cooldown.pt-BR | 6 GA |
ja-JP | スポンサー | mcp.cooldown.ja | 6 GA |
zh-Hant | 贊助內容 | mcp.cooldown.zh-Hant | 6 GA |
Registry maintained at docs.g1.network/adtech/mcp-ads/spec/v1.0#locales. Additions require:
- Native speaker review (g1 team or partner-provided).
- Sponsored label confirmed to meet local regulatory disclosure norms.
- PR + 14-day comment period before merge.
15. Worked example end-to-end
Step 1 — AI client (Claude.ai) prepares MCP tool call:
- User conversation in flight; message_index=7
- Claude.ai SDK assembles context_summary, conversation_id, user_id_hash
- SDK requests JWT from auth.g1.network/oauth/token (client_credentials)
- SDK calls mcp.g1.network MCP tool ads_serve_for_context with JWT header
Step 2 — mcp.g1.network gateway:
- Validates JWT (sig, exp ≤5min, aud, scopes includes ads:serve-for-context)
- Looks up client_app="claude-ai" in mcp_ai_clients_whitelist → status=approved
- QPS check (claude-ai: 500/sec quota, 50/sec burst)
- Builds OpenRTB 2.6 BidRequest with imp.mcp from tool inputs
- Forwards to rtb.g1.network
Step 3 — rtb.g1.network:
- context_summary → Claude Haiku verifier → IAB v3 cats = [Travel, Asia]
- locked_iab_v3_cat (from mcp_ads_conversations) is empty → no conflict
- Sensitive flag: false
- user_id_hash → mcp_ads_user_prefs lookup → skip=false
- Freq cap: conversation has 0 prior impressions; 1+floor(6/50) = 1 allowed; OK
- Auction: 3 advertisers bid; jrpass.com wins at $2.40
- Creative pre-flight: DV/IAS green; creative-jr-pass-v3-en
- Returns BidResponse with bid.ext.mcp payload
Step 4 — adserver.g1.network records impression:
- imp_id generated (UUID v4); inserted into mcp_ads_impressions
- mcp_ads_conversations.locked_iab_v3_cat set to "Travel" (first impression)
- Click token generated (HMAC-SHA256, exp +7d)
- BidResponse returned to gateway → AI client
Step 5 — AI client renders ad:
- Markdown rendered inline в response stream:
"**Sponsored** · 🚆 **JR Pass...** [Get yours →](https://adserver.g1.network/click?t=eyJ...)"
- Image displayed from image_url
- SDK fires render-confirm POST с imp_id + rendered_at + JWT
Step 6 — adserver records confirmation:
- RC validated; mcp_ads_impressions.confirmed_at set
- billed_weight = 1.0
Step 7 — user clicks:
- GET adserver.g1.network/click?t=<token>
- Token verified; mcp_ads_clicks row inserted; cross-funnel link checked
- 302 redirect to jrpass.com/?utm_source=g1mcp&...&click_id=<imp_id>
Step 8 — advertiser postback (conversion later):
- POST traffic.g1.network/conversions/postback with HMAC X-Signature
- cross-funnel attribution applied (DSP > affiliate > organic precedence)
- dsp_capi_events row inserted
16. Implementation references
- Schemas (Zod):
@theg1team/openrtbv0.1.0 —ImpMcpSchema,AgentExtSchema,BidMcpPayloadSchema,RenderConfirmSchema. - ads.cert / click-token helpers:
@theg1team/openrtb/ads-cert.ts—signMessage,verifyMessage, constant-time compare. - Reference SDK: TypeScript reference SDK ships в
g1-mcp-ads-clientrepo (Phase 5b). Python + Go + MCP-native added Phase 6 GA. - Server-side validation:
@theg1team/api-corev0.7.x —authMiddleware+ JWKS viaAUTH_OIDCservice binding. - Storage: Turso shared schema tables
mcp_ai_clients_whitelist,mcp_ads_conversations,mcp_ads_impressions,mcp_ads_clicks,mcp_ads_user_prefs(см. FINAL-PLAN §11).
17. Change log
- v1.0 (2026-05-11) — Initial draft. Incorporates Phase 0.5 outcomes G5 (render-confirm POST as billing source of truth), G6 (OAuth client_credentials JWT mandatory), G12 (g1-side skip flag, not subscription-bound).
- v0.1 (2026-05-10) — Internal draft (this file’s predecessor); described in
@theg1team/openrtbv0.1.0 Zod schemas.
18. References
- IAB Tech Lab OpenRTB 2.6 (Apr 2024) — https://iabtechlab.com/standards/openrtb/
- IAB Tech Lab Supply Chain Object 1.0
- IAB Tech Lab ads.cert 1.0
- IAB TCF v2.2 / Global Privacy Platform 1.0
- OAuth 2.0 RFC 6749 + Client Credentials Grant RFC 6749 §4.4
- JSON Web Token RFC 7519
- FTC Endorsement Guides (16 CFR 255)
- EU DSA (Regulation 2022/2065), Article 26
- CommonMark Spec 0.30
- BCP-47 Language Tags
19. Submitted-to-IAB checklist
- Draft circulated internally (DPO + lawyer review).
- Email submission к standards@iabtechlab.com referencing OpenRTB 2.6 extension pattern.
- Mark spec status в repo как
Submitted to IAB Tech Lab (no acceptance dependency). - Public hosting at
docs.g1.network/adtech/mcp-ads/spec/v1.0confirmed. - PR в
https://github.com/InteractiveAdvertisingBureau/AdCOMor appropriate IAB GitHub if community-PR pattern. - Track community feedback за 60 days; iterate в v1.1 if needed.