MCP Tools Reference
The server (serverInfo.name: "aon") speaks stateless JSON-RPC 2.0 over
Streamable HTTP and answers initialize, notifications/initialized,
tools/list, and tools/call. The Hosted AON endpoint currently exposes five
tools: the four named by the current MCP tools reference, plus
aon_get_category_schema, an optional Hosted category-guidance extension.
Other deployments can expose a different extension set, so discover that
extension through tools/list before calling it.
This page mirrors tools/list
Descriptions and schemas below match what the server itself returns from
tools/list — that response is always the authority if the two ever drift.
aon_search_offers
Search real, buyable product and service offers. Returns pricing plus a trackable link for each offer. Call it when the user shows purchase intent ("which laptop under $800", "cheapest CRM for a 3-person team", "credit card with lounge access").
The arguments are an AgentOffer Query request object — the same shape the
REST /v1/offers/query endpoint takes. The minimum valid call:
{
"intent": {
"content": [{ "type": "input_text", "text": "noise cancelling headphones under $300" }]
}
}Arguments
| Field | Type | Notes |
|---|---|---|
intent.content | array, required | The user's current text and/or images: at most one text item, single line, 1–200 characters, plus up to four image items. Text shape: { "type": "input_text", "text": "..." }. Image shape: { "type": "input_image", "image_url": "https://example.com/photo.jpg" }, or use data:image/<subtype>;base64,<data> in image_url. Each base64 data payload supports at most 524288 characters (512 × 1024), excluding the prefix. |
intent.provenance | enum | Who produced this intent: user_expressed or inferred_context. inferred_context requires confidence; user_expressed must not carry it. |
intent.confidence | number | Only with inferred_context. Greater than 0, at most 1. |
intent.origin[] | array (max 3) | Echo back the query_helper.origin entries of any suggestion the user accepted — see the Usage Guide. Items: { "kind": "offer" | "category" | "topic" | "query_helper", "id": "..." }. |
intent.signals.budget | object | { "max": number, "currency": "USD" } (uppercase ISO 4217). max and currency are required as a pair; omit the whole budget signal when the user's currency is unknown. The server does not infer currency from language or region. Forwarded into the query pipeline; no ordering promise. |
intent.signals.purchase_stage | enum | exploring | comparing | ready_to_buy. |
intent.signals.timeframe | enum | now | this_week | this_month | later. |
placement_id | string | Optional. Your placement id; takes precedence over the X-AON-Placement-Id header. Omit it (and the header) to run in anonymous mode, which earns nothing. |
request_id | string | Your idempotency key. Reuse it to retry the same query; send a new id when the query changes. request_id should be an unguessable value (UUID) — it doubles as a lookup key for the cached response. See idempotency rules. |
context.session_id | string | Stable, unguessable id for this conversation — use a fresh unique value such as a UUID and reuse it across rounds. With a user identity, cross-round de-duplication engages when both are present; in anonymous mode (no user identity) de-duplication and intent memory are keyed by this id alone, so a guessable value (e.g. session-1) would mix your history with other callers'. |
context.session.previous_request_id | string | data.request_id of the previous round, so offers already shown are not repeated. |
context.session.recent_topics[] | string[] | Up to 10 distilled topic phrases (50 chars each) from the recent conversation. |
context.user_profile.location_ids[] | string[] | 1–10 numeric AON Location Registry ids for the viewer's current location, most specific first. Takes precedence over country. |
context.user_profile.country | string | Viewer country, uppercase ISO 3166-1 alpha-2 (e.g. US). Used when location_ids is absent. |
context.user_profile.verified_age_over | integer | Age (13–120) you have verified the viewer is at least. Offers whose min_age is above it are excluded; omit when unverified and age is not evaluated. |
context.user_profile.user_pseudo_id | string | AON private extension. Fallback only — the x-aon-user-pseudo-id HTTP header always wins over this field. |
constraints.category_ids[] | string[] | AON Taxonomy v1 ids, e.g. finance.credit_lending. Copy ids from aon_resolve_category — an unknown id comes back as a correction, not results. |
constraints.excluded_category_ids[] | string[] | Taxonomy ids to leave out of results. Parent ids exclude descendant offer categories. |
force_offer | boolean (default false) | When true, permits a qualified fallback offer if the exact query has no match. It never bypasses eligibility, freshness, sensitive-category, or action gates, so results may still be empty. |
response_options.thinking_mode | boolean (default true) | Set false to drop the per-offer match_reason explanation. |
pagination.limit | integer 1–50 | Max offers to return (default 3, or 20 for Flight; values above 50 are clamped, not rejected). Also accepted by the hosted REST Query API. |
pagination.cursor | string | Opaque value: copy next_cursor from the previous response back unchanged. Never parse or build it. offset is not part of the tool: for ordinary recommendation queries an offset greater than 0 (nested or top-level) is a BAD_REQUEST tool error and offset: 0 is treated as the first page; Offer Wall placements still accept a deprecated offset; offset together with cursor is a BAD_REQUEST tool error. Errors: INVALID_CURSOR (400), PAGINATION_EXPIRED (410, start again from the first page). Use a new request_id per page. |
sort | enum | AON private extension. Only "recommended" is supported today; any other value is treated as unset and reported in extra.hints. |
Identify your placement with the X-AON-Placement-Id HTTP header (or the
placement_id argument, which wins over the header). We recommend always
sending it: without a placement the call runs in anonymous mode and its
earnings cannot be attributed to your application. Send the
header on each tools/call request; it is not remembered from initialize.
The placement decides which application receives attribution, and it must be
active, or the call returns INVALID_PLACEMENT. Consumer MCP /mcp and its
variant paths accept the same header. Use a new request_id when changing the
placement.
aon_search_offers, aon_resolve_category, and aon_get_category_schema are
identified by your placement id and can all be called without an API key;
the placement may also be omitted:
- Registered mode: send your placement id in the
X-AON-Placement-Idheader; the placement alone identifies your application and routes attribution and earnings. A non-empty placement that is malformed, unknown or inactive returnsINVALID_PLACEMENT. - Anonymous mode: with no placement (empty or whitespace-only counts as
not provided) the request is served through the AON default placement. The
aon_search_offersresponse carriesextra.identity.mode="anonymous"plus a hint to register a placement (the category tools carry no identity marker); no earnings accrue. Anonymous calls share one application rate limit bucket, andrequest_idis echoed but never replayed: every call is computed fresh, and a retry recomputes. For multi-turn memory in anonymous mode passcontext.session_idor thex-aon-user-pseudo-idheader.
If anonymous mode is unavailable on the deployment, a request without identity
returns 401 UNAUTHORIZED. Write tools, aon_submit_feedback and
aon_manage_watch, require an active placement in the X-AON-Placement-Id
header on every call. No API key is needed. Missing or blank headers return
401 UNAUTHORIZED; malformed, unknown or inactive placements return
INVALID_PLACEMENT. Body/query placement ids, API keys and anonymous fallback
do not replace this header. The placement's application and developer must be
allowed to serve traffic, and the application's normal MCP rate limit applies.
OfferWall placements apply their configured selection and sorting rules. Other
placements, including AI Assistant and Content Assistant, associate the query with
placement statistics while preserving normal recommendations and refinement
suggestions (data.engagement).
Response
The tool result's content[0].text is a JSON document in the standard AON
response envelope:
data.offers[]— each offer withoffer_info.title,offer_info.description,offer_info.category, optionaloffer_info.commercial.price, merchant or provider details underentity(includingentity.name), amatch_reason, and anactionwhosepayload.urlis the tracked link you should surface verbatim.data.request_id— pass it ascontext.session.previous_request_idnext round; it is also your retry key.data.protocol_version,data.language.data.engagement— optional block of follow-up suggestions (refinements[],followup_topics[]), each carrying alabeland aquery_helper— see the Usage Guide.data.empty_reason— present whenoffersis empty; an empty list is a real answer, not an error.extra.hints[]— corrections for any argument that was tolerated rather than applied (see degradation).
Generic Offer projection
data.offers[] uses the Generic Query Offer projection. It may include the
AON-authored response field offer_info.commercial.display_price, but it does
not expose Partner supply extensions offer_info.details,
offer_info.commercial.price.tax_status, or
offer_info.commercial.quote. Those omissions do not imply that AON lacks
the richer source facts.
aon_resolve_category
Turn a free-text product or service description into AON Taxonomy v1 category
ids that are safe to pass to aon_search_offers. If this endpoint lists the
optional aon_get_category_schema extension, its input also accepts a resolved
id from this tool. Call the resolver whenever you would otherwise be guessing
at a category id — the taxonomy is fixed, and invented ids come back as
corrections instead of results.
| Field | Type | Notes |
|---|---|---|
query | string, required | What the user is shopping for, in words: "hiking boots", "team chat software", "credit card". A category id or a legacy alias also resolves. |
Returns matches (up to 3 candidates, best first, each with category_id,
display_name, and a 0–1 score) plus a note explaining the match. When
nothing matches exactly, the closest candidates still come back with a
"no exact match" note — a misspelled or unusual phrase gets a usable
suggestion rather than an error.
aon_get_category_schema
Hosted deployment extension
The current Hosted AON MCP endpoint returns this category-guidance extension
from tools/list. Call it only after confirming the connected endpoint lists
it. Its standalone result provides clarification guidance; it does not add a
decision_factors field to the search request or response.
Get the decision factors buyers weigh inside one AON Taxonomy v1 category, so you can ask the right clarifying question before searching. Call it when intent is vague ("I need a card", "looking for software") — each factor comes with concrete options to choose between.
| Field | Type | Notes |
|---|---|---|
category_id | string, required | AON Taxonomy v1 id such as finance.credit_lending or computers_electronics.computers.software. Pass "all" to list the categories that currently ship a schema. Use aon_resolve_category to get an id from free text. |
Categories without a schema return a plain note, not an error — searching still works without one.
aon_submit_feedback
Requires X-AON-Placement-Id with an active placement; no API key.
Submit an explicit user feedback action for an AON offer. Call it only after the user clearly dismisses an offer or says they are not interested — never infer feedback from silence or other behavior.
Early scaffold
The current release acknowledges the call with a success envelope but does not persist feedback or change offer delivery yet — the workflow behind it is rolling out.
| Field | Type | Notes |
|---|---|---|
target.kind | "offer", required | Feedback currently targets an offer. |
target.id | string, required | The offer id returned by AON. |
feedback | enum, required | dismissed hides the item temporarily; not_interested cancels the default watch for the target. |
idempotency_key | string | Optional caller-generated key, reserved for idempotent processing once persistence lands. |
aon_manage_watch
Requires X-AON-Placement-Id with an active placement; no API key.
Restore or cancel the default watch for an AON offer or category. Call it only when the user explicitly asks to resume or stop receiving changes — eligible search results establish the default watch automatically. The same early-scaffold status applies: the call is acknowledged with success, but watch state is not persisted yet.
| Field | Type | Notes |
|---|---|---|
operation | enum, required | watch restores or enables the target watch; unwatch cancels it. |
target.kind | enum, required | offer or category. |
target.id | string, required | The target id returned by AON. |
idempotency_key | string | Optional caller-generated key, reserved for idempotent processing once persistence lands. |
Errors
| Condition | What you get |
|---|---|
| Unknown method | JSON-RPC error -32601 |
| Unknown tool / missing params | JSON-RPC error -32602 |
Malformed search body (missing intent.content, wrong structure) | In-band text result explaining the minimum valid shape |
Unknown category_ids entry | In-band correction with valid candidates |
Rate limit exceeded on tools/call | HTTP 429 with Retry-After and JSON-RPC error -32000 — readable by the model; see FAQ |
| Server-side validation unavailable | JSON-RPC error -32603 (fail-closed) |