# MCP Tools Reference

Source: https://docs.aon.pro/mcp/tools

> Derived from the same AON Docs release as the source page.

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:

```json
{
  "intent": {
    "content": [{ "type": "input_text", "text": "noise cancelling headphones under $300" }]
  }
}
```

### Arguments

| Field | Type | Notes |
| --- | --- | --- |
| `intent.content` | array, **required** | The user's intent. One item, single line, under 200 characters — a sentence, not a keyword list. Item shape: `{ "type": "input_text", "text": "..." }`. |
| `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](https://docs.aon.pro/mcp/guide#the-guidance-loop). 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`. |
| `request_id` | string | Your idempotency key. Reuse it to retry the _same_ query; send a new id when the query changes. See [idempotency rules](https://docs.aon.pro/mcp/guide#request_id-idempotency). |
| `placement_id` | string | Optional ad placement id. Takes precedence over the `x-placement-id` HTTP header. The placement must be active and belong to the application associated with the API key. |
| `context.session_id` | string | Stable id for this conversation. Send it — cross-round de-duplication only engages when both this and a user identity are present. |
| `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.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 | _AON private extension._ Max offers to return (default 5, hard cap 50). |
| `pagination.offset` | integer ≥ 0 | _AON private extension._ Offers to skip — page through a category with `limit: 50` and `offset: 0/50/100`. |
| `sort` | enum | _AON private extension._ Only `"recommended"` is supported today; any other value is treated as unset and reported in `extra.hints`. |

You can configure a default placement with the `x-placement-id` HTTP header on Query and MCP requests. Send the header on each `tools/call` request; it is not remembered from `initialize`. An explicit body `placement_id` takes precedence (for MCP, `params.arguments.placement_id`). Consumer MCP `/mcp` and its variant paths also accept this header and the `placement_id` tool argument. If neither is supplied, the existing network query behavior applies. Use a new `request_id` when changing the placement.

OfferWall placements apply their configured selection and sorting rules. Other placements, including AI Offer 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 with `offer_info.title`, `offer_info.description`, `offer_info.category`, optional `offer_info.commercial.price`, merchant or provider details under `entity` (including `entity.name`), a `match_reason`, and an `action` whose `payload.url` is the **tracked link you should surface verbatim**.
-   `data.request_id` — pass it as `context.session.previous_request_id` next 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 a `label` and a `query_helper` — see the [Usage Guide](https://docs.aon.pro/mcp/guide#the-guidance-loop).
-   `data.empty_reason` — present when `offers` is 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](https://docs.aon.pro/mcp/guide#tolerant-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`

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`

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` | JSON-RPC error `-32000` over HTTP 200 — readable by the model; see [FAQ](https://docs.aon.pro/mcp/faq) |
| Server-side validation unavailable | JSON-RPC error `-32603` (fail-closed) |

[Learn the guidance loop →](https://docs.aon.pro/mcp/guide)
