> ## 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 Insert MCP

> The free MCP for monetizing AI-generated text with affiliate links

## Overview

**The free MCP for monetizing AI-generated text with affiliate links.**

Commerce Insert MCP is a **resolution + placement** MCP tool. Give `insert_product_links` a piece of AI-generated text and it returns affiliate offers to insert into it - the exact anchor text to hyperlink, its character offsets in the text you sent, and the product URL to point it at. Your text comes back unchanged; your app does the substitution.

It doesn't have to be a chat reply. Anything your model wrote is fair game:

* **Generated articles and roundups** - a programmatic "best running shoes" post, a buyer's guide, a product comparison
* **Newsletters and email copy** - a weekly digest that names a few products
* **Social posts and captions** - short-form copy with a product mention in it
* **Chat and assistant replies** - the classic case: your assistant recommends something, you link it
* **Product descriptions, summaries, scripts** - any generated prose where a real product gets named

<Warning>
  **Send generated text, not the prompt that produced it.** This is the single most common integration mistake. `message` is the model's *output* - the sentence that names a product - not the instruction or user question that asked for it. "Write me a post about running shoes" has nothing in it to link.
</Warning>

It's the third tool on the same server as [Commerce Extract](/guides/commerce-extract) and [Commerce Match](/guides/commerce-match): Extract finds product mentions with no offers attached, Match turns a single phrase you already picked into a shoppable listing, and Insert does both steps end-to-end on a full passage - find the mention, resolve it, and hand back a ready-to-insert link. All three tools live on the same server behind the same `cak_` access key, so connecting once gets you all three.

Unlike Commerce Match, which returns untagged URLs, Commerce Insert applies your team's own Amazon Associates tag - you earn on the links it returns. See [Set Your Amazon Affiliate Tag](#set-your-amazon-affiliate-tag).

<Warning>
  **Amazon US is the catalog live today.** There is no marketplace parameter on the tool - the catalog comes from your team's settings. The `country` and `ip` parameters describe your end user for your team's country rules; they do not switch marketplace.
</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 analyzes text you send it.
</Note>

## Get Your Access Key

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

1. Log into [app.getchatads.com](https://app.getchatads.com)
2. Open **Commerce Insert**
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.

## Set Your Amazon Affiliate Tag

Insert is the one commerce tool that returns commission-bearing links, so the tag is what makes it pay. Set it under **Offer Settings** on the **Commerce Insert** tab in [app.getchatads.com](https://app.getchatads.com), alongside marketplace targeting, category rules, and product filters - those settings shape what the tool returns.

* **Without a tag the tool still works**, it just returns plain, untagged Amazon URLs. Nothing errors and nothing is blocked; you simply don't earn on them. Set the tag before you ship.
* **Tags are per marketplace, with no cross-marketplace fallback.** A US tag is applied to `amazon.com` links only and does nothing for `amazon.co.uk`, and vice versa. A URL whose marketplace has no tag of its own comes back untagged rather than borrowing another marketplace's.

## Connect

Commerce Insert runs on the **same MCP server as Commerce Extract and Commerce Match**. If you've already connected it, `insert_product_links` is there too - skip this section. Add the server once; one entry serves all three 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 `insert_product_links` is available.

## Tool

| Tool                   | Params                                                                                                                                                                                                                                                                                                                         | What it returns                           |
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------- |
| `insert_product_links` | `message` (required) - the AI-generated text to monetize; `ip`/`country` (optional) - geo-filtering; `extraction_mode`/`resolution_mode` (optional) - pipeline control; `max_offers`, `max_products_per_offer` (optional) - result sizing; `metadata` (optional object, max 10KB) - arbitrary data echoed back on the response | A `data.status` and a `data.offers` array |

| Param                    | Type              | Description                                                                                                                                                                                                                                                 |
| ------------------------ | ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `message`                | string (required) | The **AI-generated text** you want to monetize - an article, a post, a newsletter section, an assistant reply. Pass the model's output, not the prompt that produced it. Subject to your team's configured message length limit (default 10,000 characters) |
| `ip`                     | string (optional) | An IP address for geo-filtering, e.g. `"8.8.8.8"`                                                                                                                                                                                                           |
| `country`                | string (optional) | ISO 3166-1 alpha-2 country code, e.g. `"US"`, `"GB"`                                                                                                                                                                                                        |
| `extraction_mode`        | string (optional) | `"none"` skips extraction and treats the whole message as the product query; `"standard"` (default) runs normal extraction                                                                                                                                  |
| `resolution_mode`        | string (optional) | `"none"` runs extraction only, with nothing resolved; `"standard"` (default) resolves matches into offers                                                                                                                                                   |
| `max_offers`             | number (optional) | Maximum number of affiliate offers to return, 1-5. Default `5`                                                                                                                                                                                              |
| `max_products_per_offer` | number (optional) | Max products per offer carousel, 1-3. Default `3`                                                                                                                                                                                                           |

Each offer:

| Field                       | Type    | Description                                                                                                                                                                                            |
| --------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `link_text`                 | string  | The exact phrase from your `message` to hyperlink - insert the link around this text verbatim                                                                                                          |
| `match_start` / `match_end` | number  | Character offsets of `link_text` in the `message` you sent, so you can splice the link in without a string search. `match_end` is exclusive. Omitted when unavailable (e.g. `extraction_mode: "none"`) |
| `is_branded`                | boolean | Whether `link_text` itself names a brand                                                                                                                                                               |
| `term_brand`                | string  | The brand attributed to this offer, when known                                                                                                                                                         |
| `products`                  | array   | One or more matching products, best pick first. `products[0].url` is the link to use                                                                                                                   |

Each product carries `title`, `url`, `image`, `brand_name`, `category`, `price`, `currency`, `stars`, and `reviews`. Fields with no value are omitted.

### Example

Calling the tool with:

```json theme={null}
{
  "message": "Our top pick for commuters is the Bose QuietComfort Ultra earbuds, which deliver the best noise cancellation in the category."
}
```

returns:

```json theme={null}
{
  "data": {
    "status": "partial_fill",
    "offers": [
      {
        "link_text": "Bose QuietComfort Ultra earbuds",
        "match_start": 34,
        "match_end": 65,
        "is_branded": true,
        "term_brand": "Bose",
        "products": [
          {
            "title": "Bose QuietComfort Ultra Bluetooth Earbuds...",
            "url": "https://www.amazon.com/dp/B0CD2FSRDD/?tag=youraffiliatetag-20",
            "brand_name": "Bose",
            "category": "Electronics"
          }
        ]
      }
    ]
  },
  "error": null,
  "meta": {
    "request_id": "60556e82-ec0b-425b-8289-b95395db8943",
    "timestamp": "2026-07-23T14:42:01Z"
  }
}
```

Splicing that back into your text gives you:

```text theme={null}
Our top pick for commuters is the [Bose QuietComfort Ultra earbuds](https://www.amazon.com/dp/B0CD2FSRDD/?tag=youraffiliatetag-20), which deliver the best noise cancellation in the category.
```

The tool returns the links, not rewritten text - you own the final copy, so you decide the markup, the placement, and whether to use a given link at all. That's what makes it drop into a publishing pipeline as easily as a chat loop.

The JSON above is the text response - parse it from the tool result's text content. Anything you passed as `metadata` comes back on a top-level `metadata` field of that response.

## Response Statuses

`data.status` tells you what happened. **Only `filled` and `partial_fill` carry offers; every other status below is a successful "nothing to link" response with an empty `offers` array, not an error - don't retry it.**

| Status                                           | Meaning                                                                                        |
| ------------------------------------------------ | ---------------------------------------------------------------------------------------------- |
| `filled`                                         | All requested offers came back                                                                 |
| `partial_fill`                                   | Some, but not all, requested offers came back                                                  |
| `no_offer`                                       | Nothing worth linking - no product mention cleared the bar, or the text isn't shopping-related |
| `message_too_long`                               | Over your team's message length limit (10,000 characters by default)                           |
| `blocked_keyword`                                | The text tripped your team's blocked-keyword rules                                             |
| `language_not_allowed`                           | The detected language isn't in your team's allowed set                                         |
| `country_not_allowed` / `ip_country_not_allowed` | The `country` you passed, or the country behind `ip`, isn't in your team's allowed set         |
| `no_brand_found`                                 | Brand-only mode is on for your team and the text names no brand                                |

The content-filter and brand-only screens above only run when `extraction_mode` is `standard` (the default). Setting `extraction_mode: "none"` skips straight to resolution, so `blocked_keyword`, `language_not_allowed`, the two country statuses, and `no_brand_found` can't come back. The `message_too_long` cap applies either way.

Client errors - a missing `message`, an unknown mode - come back the other way: `data` is `null` and `error` carries a code and message. Those are worth fixing, not retrying.

## Limits

* **Message length:** 10,000 characters per call by default. There is no minimum word count - a single product name is a valid message.
* **Requests:** the free tier includes 500 requests per month. Every call counts, including ones that return no offers. [Get in touch](https://www.getchatads.com/contact) to raise your cap - tell us roughly what volume you're expecting.
* Commerce Insert shares one usage pool with [Commerce Extract](/guides/commerce-extract) and [Commerce Match](/guides/commerce-match) 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 the **Commerce Insert** tab.
* Your team's blocked-keyword, language, country, category, and product-filter rules still apply - they're the same rules configured under **Offer Settings** on the Commerce Insert tab. Content rules surface as a `data.status`, not an error.

## Troubleshooting

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

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

### "Message is required"

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

### The URLs come back with no `tag=` parameter

Your team has no Amazon Affiliate Tag set for that marketplace, so the link is returned untagged and earns nothing. Add one under **Offer Settings** on the **Commerce Insert** tab - see [Set Your Amazon Affiliate Tag](#set-your-amazon-affiliate-tag).

### Text that clearly names a product returns `no_offer`

In order of what usually fixes it:

1. **Check you sent the generated text, not the prompt.** A prompt or user question has no product mention in it to link.
2. **Check the casing.** The same extraction engine backs all three tools and capitalization is a real signal - see [Casing Is a Signal](/guides/commerce-extract#casing-is-a-signal).
3. **Check the product is in the catalog.** Amazon US today; some products legitimately aren't there.

### "Daily request limit exceeded" / "Monthly request limit exceeded" / "Per-minute rate limit exceeded"

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

### "API key disabled. Contact support."

Your key's team has been disabled. Email [chris@getchatads.com](mailto:chris@getchatads.com).

### 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?"
