Skip to content

Latest commit

 

History

History
418 lines (299 loc) · 16.5 KB

File metadata and controls

418 lines (299 loc) · 16.5 KB

Agent Ad Protocol (AAP) v0.1

An Open Protocol for Ad-Supported AI Agent Tools

Status: Draft Version: 0.1.0 Date: 2026-03-30 Authors: Graham McCain (chartlibrary.io)


1. Overview

AI agents consume tools. Tool providers need revenue. Subscription paywalls create friction that limits adoption, especially for tools agents discover and call dynamically.

The Agent Ad Protocol (AAP) defines a standard way for tool providers to return data alongside a sponsored message. The agent's host application renders the ad to the human user and fires a verification callback. The tool provider logs the verified impression and credits the request.

The value exchange is simple:

  • Tool providers monetize free-tier usage without paywalls
  • Agents get unrestricted access to data they need
  • Advertisers reach humans at the moment of relevant intent
  • Users get free tools in exchange for seeing a labeled, non-intrusive ad

AAP is transport-agnostic. It works with MCP tool responses, REST APIs, A2A agent messages, or any JSON-returning interface.

Design Principles

  1. Ads are metadata, not content. Tool output is never modified by advertising. The _aap field sits alongside data, never inside it.
  2. Privacy by default. No user PII flows to advertisers. Ad matching uses query context categories, not user identity.
  3. Human-in-the-loop. Ads target the human reviewing agent output, not the agent itself. Agents MUST NOT interpret or act on ad content.
  4. Opt-out always available. Users can disable AAP rendering in their host application. Tool providers must still return data (possibly degraded) when ads are declined.

2. Protocol Flow

User                Agent              Tool Provider         Ad Network
 |                    |                      |                     |
 |  "find NVDA        |                      |                     |
 |   patterns"        |                      |                     |
 |───────────────────>|                      |                     |
 |                    |  tool_call(NVDA)     |                     |
 |                    |─────────────────────>|                     |
 |                    |                      |  match_ad(context)  |
 |                    |                      |────────────────────>|
 |                    |                      |  ad payload         |
 |                    |                      |<────────────────────|
 |                    |  { data, _aap }      |                     |
 |                    |<─────────────────────|                     |
 |  data + [Sponsored]|                      |                     |
 |<───────────────────|                      |                     |
 |                    |  POST verify_endpoint|                     |
 |                    |─────────────────────>|                     |
 |                    |  204 No Content      |                     |
 |                    |<─────────────────────|                     |

Step-by-step:

  1. Agent calls tool as normal (MCP tools/call, REST request, etc.)
  2. Tool provider selects a relevant ad based on query context (not user identity)
  3. Tool returns its normal response with an additional _aap field
  4. Host application detects _aap and renders the sponsored message, visually separated from tool data
  5. Once the ad is rendered (visible to the user), the host fires a POST to verify_endpoint with the token
  6. Tool provider validates the token, logs the impression, and optionally credits the request against usage limits

3. Response Schema

The _aap field is a JSON object appended to the tool's normal response. It MUST NOT alter the structure of the tool's existing output.

{
  "data": {
    "...normal tool response..."
  },
  "_aap": {
    "version": "0.1",
    "ad_id": "ad_8f3k2j",
    "advertiser": "Acme Brokerage",
    "message": "Commission-free options trading. Open an account today.",
    "url": "https://acmebrokerage.com/signup?ref=aap_chartlib",
    "image_url": "https://cdn.adnetwork.com/acme/banner_300x50.png",
    "verify_endpoint": "https://api.chartlibrary.io/aap/verify",
    "token": "eyJhbGciOiJIUzI1NiJ9.eyJhaWQiOiJhZF84ZjNrMmoiLCJ0aWQiOiJ0XzkyOGYzIiwiZXhwIjoxNzQzMzIwMDAwfQ.abc123",
    "expires_at": "2026-03-30T12:00:00Z",
    "mode": "ungated",
    "context_categories": ["finance", "trading", "equities"]
  }
}

Field Reference

Field Type Required Description
version string yes AAP spec version. Currently "0.1".
ad_id string yes Unique identifier for this ad creative.
advertiser string yes Display name of the advertiser.
message string yes Ad copy. Max 280 characters. Plain text only.
url string yes Click-through URL. Must be HTTPS.
image_url string no Optional banner image. Max 300x50px. Must be HTTPS.
verify_endpoint string yes URL to POST verification callback. Must be HTTPS.
token string yes Single-use JWT for impression verification.
expires_at string yes ISO 8601 timestamp. Token and ad are invalid after this time. Max 1 hour from issuance.
mode string yes "ungated" or "gated". See Section 7.
context_categories array no Categories used for ad matching. Informational only.

4. Verification Flow

Verification proves that a human saw the ad. Without it, agents could silently strip ads while consuming free data.

Request

POST /aap/verify HTTP/1.1
Host: api.chartlibrary.io
Content-Type: application/json

{
  "token": "eyJhbGciOiJIUzI1NiJ9..."
}

Response

HTTP/1.1 204 No Content

Or on failure:

HTTP/1.1 410 Gone

{
  "error": "token_expired",
  "message": "This verification token has already been used or has expired."
}

Token Rules

  • Single-use. A token MUST be rejected after its first successful verification.
  • Time-bound. Tokens expire at expires_at. Tool providers SHOULD set expiry to 5-60 minutes.
  • Signed. Tokens MUST be cryptographically signed (e.g., HMAC-SHA256 JWT) so they cannot be forged.
  • Opaque to hosts. Host applications MUST treat tokens as opaque strings. They MUST NOT decode, modify, or cache tokens.

What Counts as a Valid Impression

A valid impression requires:

  1. The _aap block was rendered in a UI visible to a human user
  2. The ad was visually distinct from tool output (see Section 6)
  3. The verification POST was fired after rendering, before expires_at
  4. The token had not been previously verified

Host applications MUST NOT fire verification for background/automated agent runs where no human is reviewing output.


5. Ad Matching

AAP is opinionated about privacy: ad targeting uses query context, not user identity.

How It Works

  1. The tool provider (or its ad network) examines the query parameters — what the user searched for, which tool was called, what data was requested.
  2. Based on this context, a relevant ad is selected. A stock chart query gets a brokerage ad, not a shoe ad.
  3. The context_categories field documents what categories were used, for transparency.

What MUST NOT Be Shared with Advertisers

  • User name, email, or any PII
  • User's conversation history
  • Other tool outputs from the same session
  • Geographic location (unless the tool inherently requires it)
  • Device fingerprints

What MAY Be Shared with Advertisers

  • The tool name that was called
  • Anonymized, aggregated context categories (e.g., "finance", "equities")
  • Impression counts and verification rates (aggregate, not per-user)

Tool providers are the ad matching layer. Advertisers see aggregate reporting, not individual queries.


6. Host Application Requirements

Host applications (Claude Desktop, ChatGPT, Cursor, custom agent UIs) that support AAP MUST follow these rendering rules.

Rendering Rules

  1. Visual separation. The ad MUST be rendered in a distinct container, visually separated from tool output by a border, background color change, or whitespace.

  2. "Sponsored" label. The ad container MUST include the word "Sponsored" or "Ad" in a visible label.

  3. No interleaving. The ad MUST NOT be placed between lines of tool output. It should appear below or beside the tool response, never inside it.

  4. Click-through. If url is present, the ad message or a "Learn more" link should be clickable/tappable, opening the URL in an external browser.

  5. Image handling. If image_url is present, display it within the ad container. If the image fails to load, fall back to text-only rendering. Images MUST NOT auto-play, animate, or produce sound.

  6. Dismissal. Users SHOULD be able to dismiss or collapse the ad after it has been rendered. Dismissal does not revoke the impression — if verification was already fired, it stands.

Example Rendering (Text Mode)

Chart Library - NVDA Pattern Analysis (2026-03-28)

Top 5 similar patterns found. Average 3-day forward return: +2.1%
Historical win rate: 7 of 10 similar patterns moved higher.

┌─ Sponsored ──────────────────────────────────────────────┐
│  Acme Brokerage — Commission-free options trading.       │
│  Open an account today. [Learn more]                     │
└──────────────────────────────────────────────────────────┘

Opt-Out

Host applications MUST provide a user-accessible setting to disable AAP ad rendering. When disabled:

  • The host strips _aap from responses before displaying them
  • No verification callback is fired
  • Tool providers MAY return degraded data (fewer results, no AI summaries, etc.) but MUST still return a usable response

7. Gated vs. Ungated Modes

AAP supports two modes to balance user friction against impression confidence.

Ungated Mode ("mode": "ungated")

  • Full tool data is returned alongside the ad
  • Verification is best-effort: the host SHOULD fire the callback, but data is usable regardless
  • Use when: Adoption and low friction matter more than guaranteed impressions
  • Tradeoff: Non-compliant hosts can strip ads and consume data for free
{
  "data": { "matches": [...], "forward_returns": {...} },
  "_aap": { "mode": "ungated", "..." : "..." }
}

Gated Mode ("mode": "gated")

  • The response includes a data_preview (partial/summary data) and an encrypted_data blob
  • Full data is unlocked only after successful verification
  • The verification response returns a decryption_key
{
  "data_preview": {
    "match_count": 10,
    "summary": "10 similar patterns found. Verify to see full results."
  },
  "encrypted_data": "base64-encoded-encrypted-blob...",
  "_aap": { "mode": "gated", "..." : "..." }
}

Gated verification response:

HTTP/1.1 200 OK
Content-Type: application/json

{
  "decryption_key": "base64-encoded-AES-256-key",
  "algorithm": "AES-256-GCM"
}

The host application decrypts encrypted_data with the provided key and displays the full result.

  • Use when: Revenue certainty matters, or the tool's data is high-value
  • Tradeoff: Higher friction. Hosts must implement decryption. Background/automated agents cannot use gated tools without a human in the loop.

8. Privacy Principles

  1. No PII in transit. The _aap field and verification callback carry no user-identifying information. The token encodes the ad and request context, not the user.

  2. Context, not identity. Ad matching is based on what was queried, not who queried it. This is analogous to search ads (matching intent) rather than display ads (matching profiles).

  3. Aggregation only. Advertisers receive aggregate impression and click reports. They do not receive per-query logs.

  4. Data minimization. Tool providers SHOULD log only what is necessary for billing and fraud prevention: token hash, timestamp, verification status.

  5. User control. Users can opt out of AAP ads in their host application settings. Opting out may result in degraded tool responses but MUST NOT result in blocked access.

  6. No cross-tool tracking. Tool providers MUST NOT correlate AAP impressions across different tool providers to build user profiles.


9. Full Example: Chart Library

A complete request/response cycle using Chart Library's MCP server.

Tool Call (MCP tools/call)

{
  "method": "tools/call",
  "params": {
    "name": "search_pattern",
    "arguments": {
      "symbol": "NVDA",
      "date": "2026-03-28"
    }
  }
}

Tool Response

{
  "content": [
    {
      "type": "text",
      "text": "{\"matches\":[{\"symbol\":\"AMD\",\"date\":\"2024-06-12\",\"distance\":0.42,\"forward_return_3d\":3.1},{\"symbol\":\"NVDA\",\"date\":\"2023-11-08\",\"distance\":0.45,\"forward_return_3d\":5.2},{\"symbol\":\"TSM\",\"date\":\"2025-01-15\",\"distance\":0.48,\"forward_return_3d\":-1.4}],\"summary\":{\"avg_3d_return\":2.3,\"win_rate\":0.7,\"sample_size\":10}}"
    }
  ],
  "_aap": {
    "version": "0.1",
    "ad_id": "ad_bkr_9x2m",
    "advertiser": "Acme Brokerage",
    "message": "Trade NVDA options commission-free. No minimums.",
    "url": "https://acmebrokerage.com/trade/NVDA?ref=aap_chartlib",
    "verify_endpoint": "https://api.chartlibrary.io/aap/verify",
    "token": "eyJhbGciOiJIUzI1NiJ9.eyJhaWQiOiJhZF9ia3JfOXgybSIsInRpZCI6InRfMDAzOCIsImV4cCI6MTc0MzMyOTIwMH0.kL3xWz",
    "expires_at": "2026-03-30T12:00:00Z",
    "mode": "ungated",
    "context_categories": ["finance", "equities", "NVDA"]
  }
}

Host Renders

The host application displays the pattern analysis results normally, then renders the sponsored block below:

NVDA (2026-03-28) — 10 similar patterns found

  #1  AMD  2024-06-12   distance: 0.42   3-day return: +3.1%
  #2  NVDA 2023-11-08   distance: 0.45   3-day return: +5.2%
  #3  TSM  2025-01-15   distance: 0.48   3-day return: -1.4%
  ...

  Average 3-day return: +2.3%  |  Win rate: 7 of 10

  ┌─ Sponsored ────────────────────────────────────────────┐
  │  Acme Brokerage — Trade NVDA options commission-free.  │
  │  No minimums. [Learn more]                             │
  └────────────────────────────────────────────────────────┘

Host Fires Verification

POST https://api.chartlibrary.io/aap/verify
Content-Type: application/json

{"token": "eyJhbGciOiJIUzI1NiJ9..."}
HTTP/1.1 204 No Content

The impression is logged. Chart Library credits this API call against the user's free tier. Acme Brokerage sees +1 impression in their aggregate dashboard.


10. Implementor Notes

For Tool Providers

  • Start with ungated mode. It has zero adoption friction and works with any host that simply passes through JSON.
  • Return _aap only when you have a relevant ad. Do not return empty or placeholder ads.
  • Set token expiry to 15 minutes as a reasonable default.
  • Track verification rate. If it drops below 20%, most hosts are stripping ads — consider gated mode for high-value endpoints.

For Host Applications

  • Detecting _aap is a single key check on every tool response. The rendering cost is minimal.
  • Fire verification asynchronously. Do not block the user on the callback.
  • Respect expires_at. Do not fire verification for stale ads.
  • If you cache tool responses, do not replay ads on cache hits.

For Advertisers

  • You are buying intent-matched impressions in a new channel: AI agent interactions.
  • You receive aggregate reporting only. There is no user-level targeting or retargeting.
  • Creative is text-first (280 chars max). This is a constraint, not a limitation — concise copy in a high-intent context converts well.

License

This specification is released under CC BY 4.0. Anyone may implement, extend, or build on AAP with attribution.


AAP is maintained at github.com/grahammccain/agent-ad-protocol. File issues, propose changes, or join the discussion.