Amazon Ads API 12 min read

Connect Claude to Amazon Ads and Seller Central (MCP Setup)

Amazon runs two MCP servers — one for Ads, one for the Selling Partner API — that let Claude query your accounts directly. The built-in connector flow fails with '400 Bad Request: An unknown scope was requested'. Here are the setup steps that work, then why the connector is broken and what the connection costs you in context.

Updated Aug 2026
Connect Claude to Amazon Ads and Seller Central (MCP Setup)

What These Servers Do #

Eight minutes, both servers set up from a clean machine — that is sections 1 to 4 below. The connector failure, the proxy internals and the context cost are written up only, further down.

Amazon runs two MCP servers. Connect one to Claude and you can ask questions about your account in plain English instead of writing API calls:

  • Adswhich campaigns are running in the US right now? Show me last month's spend by ad group.
  • Selling Partner APIhow many orders did I get in the last 7 days? What is my current FBA inventory?

MCP is just the format Amazon uses to describe its tools to an AI. You do not need to know anything about it to use this.

Before you start

You need API credentials Amazon has already approved — a client ID, a client secret and a refresh token, for whichever API you want. Three values. The browser sign-in route does not work; the section near the end explains why.

If you do not have credentials yet, start with the Advertising API onboarding guide — I have written up the direct-advertiser route through it separately. There is no shortcut around that step.

One more thing you need: the proxy script itself, which is the next section — one command.

Get the Proxy #

Make a folder and download the script into it. It is a single file with no dependencies beyond the Python standard library, so there is nothing to install.

mkdir -p ~/amazon-mcp && cd ~/amazon-mcp
curl -O https://www.databaaba.com/static/downloads/mcp_proxy.py

Check it runs:

python3 mcp_proxy.py --help

That folder is now your working directory for everything below — the credential files go in it, and the script reads them from alongside itself. Put it wherever you like; the setup commands work out the absolute path on their own, so you never type it.

Read the source first if you would rather see what you are running before you run it — it is about 200 lines, and How the proxy works walks through the two functions that matter.

Windows: use Git Bash or WSL for these commands, or download the file in a browser and cd to wherever it landed. Everything else in this post works unchanged.

Set Up Amazon Ads #

  1. Save your three credentials

    In the folder holding mcp_proxy.py. The single quotes are not optional — a refresh token contains a pipe character, and unquoted, your shell will treat everything after it as a command.

    cat > .env.ads <<'EOF'
    ADS_CLIENT_ID='amzn1.application-oa2-client.YOUR_ID'
    ADS_CLIENT_SECRET='amzn1.oa2-cs.v1.YOUR_SECRET'
    ADS_REFRESH_TOKEN='YOUR_REFRESH_TOKEN'
    EOF
    chmod 600 .env.ads
  2. Check Amazon accepts them

    Do this before touching Claude, so a bad credential shows up here rather than as a silent failure later.

    python3 mcp_proxy.py --server ads --readonly --selftest
    upstream : Amazon Ads MCP Server v1.0.0
    tools    : 110 total, 45 read-only
    mode     : READ-ONLY
    selftest ok
  3. Tell Claude about it

    Nothing to edit — run this from the same folder. It finds the proxy, finds Claude's config wherever your operating system keeps it, creates that file if it does not exist yet (on a fresh install it usually does not), and backs up anything already there before adding one entry.

    python3 - <<'EOF'
    import json, os, pathlib, shutil, sys
    
    SERVER = "ads"
    NAME   = "amazon-" + SERVER
    EXTRA  = ["--readonly"]
    
    proxy = pathlib.Path("mcp_proxy.py").resolve()
    if not proxy.exists():
        sys.exit("mcp_proxy.py not found. Run this from the folder you saved it in.")
    
    if sys.platform == "darwin":
        cfg = pathlib.Path.home() / "Library/Application Support/Claude/claude_desktop_config.json"
    elif sys.platform.startswith("win"):
        cfg = pathlib.Path(os.environ["APPDATA"]) / "Claude" / "claude_desktop_config.json"
    else:
        cfg = pathlib.Path.home() / ".config/Claude/claude_desktop_config.json"
    
    cfg.parent.mkdir(parents=True, exist_ok=True)
    config = {}
    if cfg.exists() and cfg.read_text().strip():
        shutil.copy(cfg, str(cfg) + ".backup")
        config = json.loads(cfg.read_text())
    
    config.setdefault("mcpServers", {})[NAME] = {
        "command": sys.executable,
        "args": [str(proxy), "--server", SERVER] + EXTRA,
    }
    cfg.write_text(json.dumps(config, indent=2))
    print("proxy  :", proxy)
    print("config :", cfg)
    print("servers:", ", ".join(config["mcpServers"]))
    EOF
    proxy  : /Users/you/amazon-mcp/mcp_proxy.py
    config : /Users/you/Library/Application Support/Claude/claude_desktop_config.json
    servers: amazon-ads

    If it says mcp_proxy.py not found, you are in the wrong directory — cd back to the folder you downloaded it into.

  4. Quit Claude completely and reopen it

    Cmd-Q on macOS, not closing the window. The config is read when the process starts, and a closed window is still the same process.

Click the tools icon. You should see amazon-ads. Ask it something real:

Which of my campaigns are running in the US right now?

Start read-only. Of the 110 tools, 63 change state and 10 delete things — campaigns, ad groups, targets, reports. The --readonly flag exposes only the 45 that read, which costs you nothing useful on day one. It filters on Amazon's own readOnlyHint label, so treat it as an accident-preventer rather than a security control; see the FAQ.

Set Up Seller Central (SP-API) #

Same three steps, with a different set of Seller Central credentials. The server is sellingpartner-ai.amazon.com.

  1. Save your SP-API credentials
    cat > .env.spapi <<'EOF'
    SPAPI_LWA_CLIENT_ID='amzn1.application-oa2-client.YOUR_ID'
    SPAPI_LWA_CLIENT_SECRET='amzn1.oa2-cs.v1.YOUR_SECRET'
    SPAPI_REFRESH_TOKEN='YOUR_REFRESH_TOKEN'
    EOF
    chmod 600 .env.spapi
  2. Check them
    python3 mcp_proxy.py --server spapi --selftest
    upstream : SpectrumAgenticInterfaceGateway v1.0.0
    tools    : 3 total
    selftest ok

    Three tools, where Ads had 110. That is not a smaller API — it is a different design, and it turns out to matter a great deal. More on that below.

  3. Add it next to the Ads entry

    The same block with one word changed. It merges, so the Ads server you added earlier survives.

    python3 - <<'EOF'
    import json, os, pathlib, shutil, sys
    
    SERVER = "spapi"
    NAME   = "amazon-" + SERVER
    EXTRA  = []
    
    proxy = pathlib.Path("mcp_proxy.py").resolve()
    if not proxy.exists():
        sys.exit("mcp_proxy.py not found. Run this from the folder you saved it in.")
    
    if sys.platform == "darwin":
        cfg = pathlib.Path.home() / "Library/Application Support/Claude/claude_desktop_config.json"
    elif sys.platform.startswith("win"):
        cfg = pathlib.Path(os.environ["APPDATA"]) / "Claude" / "claude_desktop_config.json"
    else:
        cfg = pathlib.Path.home() / ".config/Claude/claude_desktop_config.json"
    
    cfg.parent.mkdir(parents=True, exist_ok=True)
    config = {}
    if cfg.exists() and cfg.read_text().strip():
        shutil.copy(cfg, str(cfg) + ".backup")
        config = json.loads(cfg.read_text())
    
    config.setdefault("mcpServers", {})[NAME] = {
        "command": sys.executable,
        "args": [str(proxy), "--server", SERVER] + EXTRA,
    }
    cfg.write_text(json.dumps(config, indent=2))
    print("proxy  :", proxy)
    print("config :", cfg)
    print("servers:", ", ".join(config["mcpServers"]))
    EOF
    servers: amazon-ads, amazon-spapi

Quit and reopen Claude again, then:

How many orders did I get in the last 7 days?

Region note: a North America refresh token worked in testing. A European token against the same endpoint returned {"code":-32001,"message":"Authentication required"}. Whether that is a token-scope issue or genuine regional availability is untested — if you only hold an EU token, verify before building on it.

If Something Does Not Work #

SymptomCauseFix
Nothing appears in the tools iconClaude was closed, not quitCmd-Q, then reopen. Closing the window keeps the process alive.
selftest fails on the token exchangeWrong credential, or the app is not approved for that APIConfirm all three values, and that the application is approved for the API you are calling
Your other MCP servers vanishedThe config was overwritten instead of mergedRestore claude_desktop_config.json.backup, sitting next to the config
Half your token appears in a shell errorUnquoted refresh token — the pipe was read as a commandSingle-quote every value in the env file
Config file does not existClaude only creates it when a server is addedNothing to do — the snippet creates it and its parent folder

To check what is actually in the config:

cat "$HOME/Library/Application Support/Claude/claude_desktop_config.json"

Why the Connector Flow Fails #

The obvious route — Settings, Connectors, Add custom connector, paste the URL — returns this:

400 Bad Request
An unknown scope was requested

resource=https%3A%2F%2Fadvertising-ai.amazon.com
scope=advertising%3A%3Acampaign_management
errorMsg=lwa-invalid-parameter-bad-scope

Not your account, not your browser profile, not a typo. It fails for everyone, because two Amazon metadata documents contradict each other.

What the resource says it needs:

curl -s https://advertising-ai.amazon.com/.well-known/oauth-protected-resource
{
  "authorization_servers": ["https://lwa.amazon.com"],
  "scopes_supported": ["advertising::campaign_management"]
}

What that authorization server says it issues:

curl -s https://lwa.amazon.com/.well-known/oauth-authorization-server
{
  "issuer": "https://lwa.amazon.com",
  "scopes_supported": ["profile"],
  "code_challenge_methods_supported": ["S256"]
}

One scope: profile. Not the advertising scope the resource just demanded. And no registration_endpoint, so a client cannot register itself and ask to be granted one.

The MCP client asks LWA for a scope that LWA does not publish, and is rejected MCP client (Claude) Ads MCP resource advertising-ai.amazon.com LWA lwa.amazon.com 1. what do you need? 2. scope advertising::campaign_management, from LWA 3. may I have advertising::campaign_management? 4. 400 — unknown scope

That scope is only granted to an LWA application Amazon has manually approved for the Advertising API, and there is no self-service path to becoming one. The browser flow is not an easier route to the same permission — it is the same permission, requested by a client that is not eligible to hold it.

Which is why the setup above brings its own approved application instead.

How the Proxy Works #

If you already call the Advertising API, you hold credentials for an application Amazon approved. Those three values mint an access token the MCP server accepts, with no browser involved.

So the direction flips. Rather than Claude asking Amazon for permission, a small program on your machine holds the approved credentials, mints the token, and passes messages through.

Claude talks to a local proxy over stdio; the proxy talks to Amazon over HTTPS with a bearer token Claude app on your Mac local proxy holds your credentials Amazon MCP Amazon-hosted stdio HTTPS + bearer Claude sees an ordinary local server. Amazon sees an approved API client.

Two functions carry it. access_token() exchanges the refresh token for an access token and caches it until two minutes before expiry. forward() attaches that token as a bearer header, posts the JSON-RPC message upstream, and hands the reply back — unwrapping it first if the server answered as a Server-Sent Events stream, which it sometimes does.

One rule the whole thing depends on: log to stderr, never stdout. Stdout is the MCP channel, and a stray print corrupts the stream in a way that is genuinely annoying to debug.

The full source is here — about 200 lines, standard library only.

What the Connection Costs #

Before a model can use a tool it has to be told the tool exists — the name, what it does, and every field you can pass to it. That list sits in the context window and is re-sent with every message, because the Messages API is stateless. Tool definitions render at the front of the prompt on each request, not once at connect time.

So the size of the list is the cost of the connection. Measured 25 August 2026, tokenised with o200k_base:

ServerToolsTokensShare of a 200k window
Amazon Ads MCP110~96,10048%
Amazon SP-API MCP3~5090.3%

About 135 printed pages of tool definitions for Ads, against one. Nearly half the context window spent before the first question — and 94% of it is input schemas, the blank parameter fields, not the names or the descriptions. One tool, campaign_management-create_target, carries 51,595 characters of schema by itself: more than twenty times the entire SP-API catalogue, for a single operation.

This is a known problem across the MCP ecosystem rather than something specific to Amazon. Anthropic wrote about it in Code execution with MCP, and there is an open specification issue on tool-schema overhead. The figure usually cited as the alarming case is GitHub's server at roughly 55,000 tokens. Amazon Ads is close to double it.

Why three tools beats 110

SP-API is not cheaper because it does less — it covers more operations than the Ads server. It exposes three tools and looks the rest up on demand:

ToolWhat it does
search_toolsDescribe what you need in plain language; get ranked matches back
get_tool_schemaFetch the parameters for one named tool
call_toolRun it

The schemas still exist, fetched one at a time when needed rather than shipped in advance. call_tool's own schema is two fields — a tool name and an opaque params object — which is why the whole catalogue fits in half a page.

The trade is real in both directions. Ads is immediate, because everything is already known; SP-API pays two extra round trips before it can act, and needs to search well to find the right tool. But the context cost is paid on every turn while the discovery cost is paid once per new tool, so over a real conversation the second trade usually wins.

That is also where the protocol went: MCP added tool search in January 2026 for exactly this reason. If you are building an MCP server, copy this shape. It is the same instinct as choosing the narrowest data source that answers the question — the reasoning in AMS vs AMC applies to tool surfaces as much as to datasets.

Cutting the Cost #

  1. Keep --readonly

    45 tools instead of 110 takes the catalogue from roughly 96,000 tokens to about 17,500 — 48% of the window down to under 9%.

  2. Hand-pick what you use

    A working set of nine read tools — campaigns, ad groups, targets, ads, portfolios, reports, accounts — measured around 6,000 tokens. That is 3% of the window for most reporting work.

  3. Sort the tool list before handing it over

    Prompt caching is a byte-exact prefix match, and tool definitions sit at position zero of the prompt. The Ads server returns the same 110 tools in a different order on each connection — in testing, 22 of 110 positions moved between two calls a second apart, with per-tool JSON identical once sorted by name. Unsorted, every reconnect writes a fresh cache entry instead of reading the existing one.

    tools = sorted(response["result"]["tools"], key=lambda t: t["name"])

Worth knowing: caching changes the price of re-sending the catalogue, not the fact of it. Cached reads bill at roughly a tenth of base input rate, so running cost drops sharply after the first message — but the tokens still occupy the window every turn. The 48% figure is about space, not money.

One thing MCP does not change: the underlying API still throttles, and an agent fanning out across tools hits that faster than a person clicking through a console. The rate limits behave the way they always did.

FAQ #

How do I connect Claude to Amazon Ads?

Save your Advertising API client ID, client secret and refresh token to an env file, run a local proxy that mints an access token from them, and register that proxy in Claude's desktop config as an MCP server. The built-in connector flow does not work — it fails with an unknown-scope error before reaching your account.

Why does adding Amazon Ads MCP to Claude fail with an unknown scope error?

The Ads MCP resource requires the scope advertising::campaign_management and names lwa.amazon.com as its authorization server, but that server publishes only the profile scope and offers no dynamic client registration. A generic MCP client asks for a scope it can never be granted, and LWA returns 400 lwa-invalid-parameter-bad-scope.

Where is the Claude desktop config file, and what if it does not exist?

On macOS it is ~/Library/Application Support/Claude/claude_desktop_config.json; on Windows %APPDATA%\Claude\claude_desktop_config.json. Claude only creates it once a server has been added, so on a fresh install it is normal for the file to be missing — the setup snippet creates it and its parent folder.

Can I connect without Amazon API credentials?

No. The advertising scope is only issued to applications Amazon has manually approved, and no browser flow obtains it. You need an approved application and a refresh token first.

How many tokens does the Amazon Ads MCP server use?

Its tool list measured roughly 96,100 tokens in August 2026 — 110 tools, about 404,000 characters, or 48% of a 200,000-token context window, re-sent on every message. Around 94% of that is input schemas rather than names or descriptions. Filtering to the 45 read-only tools reduces it to about 17,500.

Does read-only mode make the connection safe?

It reduces accidents, not risk. The filter relies on Amazon's self-declared readOnlyHint label, and MCP annotations are hints rather than enforced guarantees — a tool can declare itself read-only and still write. Treat it as a convenience and a context-size reduction, not a security boundary.

Don't want to build this yourself?

I set this up for sellers and agencies every week. Book a free 30-minute audit of your Amazon data & PPC setup — you'll leave with a plan either way, whether we work together or not.

Found this helpful? Share it:

WhatsApp