> ## Documentation Index
> Fetch the complete documentation index at: https://docs.getchatads.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Commerce Match MCP

> Turn a product phrase into shoppable merchant listings over one MCP tool

## Overview

Commerce Match MCP is a **resolution-only** MCP tool. Give `find_product_matches` a single product phrase and it returns up to three matching product listings, best pick first - title, image, brand, category, and a product page URL you can link straight to. Every match resolves against the catalog of a merchant you already work with, and the `url` comes back untagged, so you append your own affiliate tag or link as-is - there is no new affiliate account to sign up for and no ChatAds tag in the response.

It's the inverse of [Commerce Signals](/guides/commerce-signals): Signals finds the product mentions inside a block of text, Match turns one of those phrases into something shoppable. Both tools live on the same server behind the same `cak_` access key, so connecting once gives you both.

<Warning>
  **Amazon US is the catalog live today.** The resolution engine is catalog-agnostic, but Amazon US is currently the only catalog wired up, so every match returns `merchant: "amazon"` with a US `url`. There is no country or marketplace parameter.
</Warning>

<Note>
  This is a **different server** from the [MCP Data Connector](/guides/mcp-data-connector). That one is read-only access to your own widget data with a `uk_` user key. This one takes a `cak_` team access key and matches text you send it.
</Note>

## Get Your Access Key

Commerce Match MCP authenticates with a team **access key** (`cak_...`) in the `x-api-key` header - the same key type Commerce Signals uses. If you already hold one, reuse it.

1. Log into [app.getchatads.com](https://app.getchatads.com)
2. Open **Commerce Match**
3. In the **Access Keys** card, click **Create Key**

You can hold as many access keys as you have clients - one per MCP client is a good default, so you can revoke them independently. Widget keys (`cwk_...`) and user keys (`uk_...`) do not work here.

## Connect

Commerce Match runs on the **same MCP server as Commerce Signals**. If you've already connected it, `find_product_matches` is there too - skip this section. Add the server once, under whatever name you like; one entry serves both tools.

In Claude Code it's one command. Most other clients (Claude Desktop, Cursor, Windsurf, etc.) take the JSON block - drop the `transport` field if your client rejects it:

<CodeGroup>
  ```bash Claude Code theme={null}
  claude mcp add --transport http chatads-commerce https://api.getchatads.com/tools/mcp/mcp --header "x-api-key: cak_your_access_key"
  ```

  ```json JSON config theme={null}
  {
    "mcpServers": {
      "chatads-commerce": {
        "url": "https://api.getchatads.com/tools/mcp/mcp",
        "transport": "http",
        "headers": {
          "x-api-key": "cak_your_access_key"
        }
      }
    }
  }
  ```
</CodeGroup>

It's a Streamable HTTP MCP server, so there's nothing to install locally and no Node or Python dependency - one URL in a config file. Restart your client and `find_product_matches` is available.

## Tool

| Tool                   | Params                                                                                                                                  | What it returns                                              |
| ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------ |
| `find_product_matches` | `term` (required) - a product name or phrase to match; `context` (optional) - surrounding text containing that term, to disambiguate it | Up to 3 product matches in a `matches` array, plus a `count` |

| Param     | Type              | Description                                                                                                                                                                                                                                                                                                                                        |
| --------- | ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `term`    | string (required) | The product name or phrase to match, e.g. "Bose QuietComfort Ultra earbuds". Brand specificity belongs here - a term naming its brand matches far better than a bare category noun. Capped at 100 characters; a longer term is truncated at a word boundary, not rejected                                                                          |
| `context` | string (optional) | The surrounding text the term came from, used to disambiguate its category and vertical. It **must contain `term` verbatim** - it's the passage the term was pulled from, not background you write yourself. If you have no surrounding text, omit it. Only the 500 characters either side of the term are used; the rest is ignored, not rejected |

If `term` appears more than once in `context`, only the **first occurrence** is used. The words immediately around that occurrence are what drive the category and vertical signals, so a `context` where the same phrase appears twice under different brands or in two unrelated topics resolves against the first one and ignores the rest. When that matters, trim `context` down to the passage you actually mean. The response carries no offsets, so there's no way to tell after the fact which occurrence was used. Everything outside 500 characters either side of that occurrence is dropped before matching, so trimming a long `context` yourself is optional - it changes which passage is used, not whether the call succeeds.

Each match:

| Field        | Type   | Description                                                                   |
| ------------ | ------ | ----------------------------------------------------------------------------- |
| `title`      | string | The merchant's product title                                                  |
| `image`      | string | Product image URL                                                             |
| `brand_name` | string | The product's brand                                                           |
| `url`        | string | Merchant product page URL. Untagged - no affiliate account required           |
| `category`   | string | Catalog main/department category for this product                             |
| `merchant`   | string | Which merchant the match came from. Branch on this field rather than assuming |

The response is a `matches` array of 0 to 3 items plus a `count`. `matches[0]` is the best pick. An empty `matches` array is a success, not an error - it means we found no confident match for that term, and retrying won't change that.

### Example

Calling the tool with:

```json theme={null}
{
  "term": "Bose QuietComfort Ultra earbuds",
  "context": "The Bose QuietComfort Ultra earbuds are great for commuting."
}
```

returns:

```json theme={null}
{
  "data": {
    "matches": [
      {
        "title": "Bose QuietComfort Ultra Bluetooth Earbuds...",
        "image": "https://m.media-amazon.com/images/I/51example.jpg",
        "brand_name": "Bose",
        "url": "https://www.amazon.com/dp/B0CD2FSRDD",
        "category": "Electronics",
        "merchant": "amazon"
      }
    ],
    "count": 1
  },
  "error": null,
  "meta": {
    "request_id": "60556e82-ec0b-425b-8289-b95395db8943",
    "timestamp": "2026-07-23T14:42:01Z",
    "version": "1.0.0"
  }
}
```

The JSON above is the text response. Clients that support MCP structured tool output also receive the `data` payload directly as structured content - the bare `{"matches": [...], "count": n}` object, matching the tool's declared output schema. Same envelope shape as [Commerce Signals](/guides/commerce-signals).

## Limits

* **Input length:** `term` is capped at 100 characters and `context` at 500 characters either side of the term's first occurrence. Over-cap input is truncated or windowed, not rejected - the call still succeeds. Near-miss copies (smart quotes, extra whitespace, invisible characters, markdown wrapping) are normalized before the containment check, so they match rather than erroring.
* **Requests:** the free tier includes 500 requests per month. Every call counts, including ones that return zero matches. [Get in touch](https://www.getchatads.com/contact) to raise your cap - tell us roughly what volume you're expecting.
* Commerce Match shares one usage pool with Commerce Signals and the rest of your team's API usage, and the same per-minute burst limit. Your current month's usage is shown at the top of both the **Commerce Match** and **Commerce Signals** tabs - same team-wide figure either way.
* Your team's blocked-keyword and language content rules still apply. Text that trips one returns an empty `matches` array rather than an error.

## Troubleshooting

### "This tool requires a cak\_ API key"

You connected with a user key (`uk_...`). Commerce Match MCP takes a team access key (`cak_...`) - create one on the **Commerce Match** or **Commerce Signals** tab.

### "term is required"

The `term` argument was missing, empty, or whitespace only. An empty term is a client error, not an empty-matches success.

### "term must appear in context"

The `context` you sent doesn't contain `term` verbatim. `context` is the passage the term was pulled from, not a slot for background you write separately. Near-miss copies - smart quotes, extra whitespace, invisible characters, markdown wrapping - are normalized on both fields first, so this error means the term genuinely isn't there. Fix the input or drop `context` and send `term` alone; it's an `INVALID_INPUT` client error, so retrying the same call won't help.

### "Extraction backend temporarily unavailable - please retry"

A `SERVICE_UNAVAILABLE` error means the matching service didn't respond. It's deliberately surfaced as an error rather than silently returning zero matches, so a retry is safe and correct here.

### "Daily request limit exceeded" / "Monthly request limit exceeded"

You've used your plan's allowance. See [Limits](#limits).

### An obvious product returns `"count": 0`

We had no confident match for that phrase in the catalog. In order of what usually fixes it:

1. **Put the brand in `term`.** "Bose QuietComfort Ultra earbuds" matches far better than "earbuds".
2. **Check the casing.** The same scoring engine backs both tools, and capitalization is a real signal - see [Casing Is a Signal](/guides/commerce-signals#casing-is-a-signal).
3. **Trim `context`** to the passage the term actually came from, so the category signals around it are the right ones.

Some products legitimately aren't in the catalog. An empty `matches` array is a success - treat it as "no link for this one" and move on rather than retrying.

### Tool not appearing in your MCP client

1. Verify the URL is exactly: `https://api.getchatads.com/tools/mcp/mcp`
2. If your client's config uses a `transport` field, it should be `"http"`
3. Confirm the key in `x-api-key` starts with `cak_`
4. Restart your MCP client completely
5. Ask: "What tools do you have access to?"
