Skip to main content
Glama
james-julius

microsoft-ads-mcp

by james-julius
README.md
# microsoft-ads-mcp

An [MCP](https://modelcontextprotocol.io) server for the **Microsoft Advertising
(Bing Ads) API**. Gives an MCP client (Claude Code, Claude Desktop, etc.) live
read **and** management access to your Microsoft Advertising accounts —
reporting, campaign structure, and full write operations.

Works with Microsoft Advertising accounts that sign in with **Google** (the
default) or with a **Microsoft** account.

> ⚠️ This server can change live campaigns and **spend real money** (enabling
> campaigns, raising budgets). Tools that affect spend are clearly marked and the
> server is designed to keep newly-created entities paused by default — but treat
> it like giving an assistant the keys to your ad account.

## Tools

**Read / analytics**
| Tool | Description |
|------|-------------|
| `list_accounts` | Accounts the signed-in user can access |
| `list_campaigns` | Campaigns in an account |
| `list_ad_groups` | Ad groups in a campaign |
| `list_keywords` | Keywords in an ad group |
| `list_ads` | Ads in an ad group |
| `list_negative_keywords` | Campaign-level negatives |
| `performance_report` | account / campaign / ad_group / ad / keyword / search_term / geographic reports, predefined or custom date ranges, any aggregation |
| `find_wasted_spend` | Search terms that spent with no conversions (negative-keyword candidates) |

**Write / management**
| Tool | Description |
|------|-------------|
| `set_campaign_status` | Pause / enable a campaign |
| `set_campaign_budget` | Set daily budget |
| `set_ad_group_status` | Pause / enable an ad group |
| `set_keyword` | Update keyword status / bid |
| `add_negative_keywords` / `remove_negative_keywords` | Manage negatives |
| `create_campaign` | New Search campaign (paused) |
| `create_ad_group` | New ad group (paused) |
| `add_keywords` | Add keywords |
| `add_responsive_search_ad` | Add a Responsive Search Ad |

**Higher-level (composite)**
| Tool | Description |
|------|-------------|
| `account_overview` | One call: account KPIs + per-campaign breakdown + flags (zero-conversion spenders, budget-limited campaigns) |
| `compare_periods` | Last N days vs the preceding N days, with deltas and % change |
| `optimization_audit` | Prioritized action list: waste, low quality score, high CPA, scale candidates, budget-limited campaigns |
| `search_term_harvest` | Converting search queries not yet keywords — suggestions to add |
| `apply_negatives_from_waste` | Turn wasted search terms into negative keywords (dry-run by default) |
| `build_search_campaign` | Create a whole campaign (campaign + ad group + keywords + RSA) in one call, paused |

Report numbers come back already typed (floats/ints; percentages as plain
numbers, e.g. `1.89` means 1.89%).

## How auth works

Microsoft Advertising has **no app-only flow** — every call needs a delegated
user token. You authorize **once**; the refresh token is stored at
`~/.config/microsoft-ads-mcp/tokens.json` (mode `0600`) and the server silently
exchanges it for access tokens thereafter. You also need a Microsoft Advertising
**developer token**.

Choose a provider with `MSADS_AUTH_PROVIDER`:
- **`google`** (default) — for Ads accounts created via "Sign in with Google".
- **`microsoft`** — for Ads accounts backed by an Entra or personal Microsoft account.

## Prerequisites

1. A **Microsoft Advertising account** you can sign into.
2. A **developer token**: sign in at <https://developers.ads.microsoft.com/>,
   and request a token (production tokens for accounts you own are granted
   immediately). This is separate from OAuth.
3. **Python 3.10–3.13** (the `bingads` SOAP stack isn't happy on 3.14 yet).

## Install

```bash
git clone https://github.com/james-julius/microsoft-ads-mcp.git
cd microsoft-ads-mcp
python3 -m venv .venv
.venv/bin/pip install -e .
cp .env.example .env   # then edit .env
```

## Configure auth

### Option A — Google (default)

The Microsoft Advertising API accepts Google sign-in (SDK ≥ 13.0.26), so you can
authenticate with the same Google account you use at ads.microsoft.com.

1. In the [Google Cloud Console](https://console.cloud.google.com): pick/create a project.
2. **APIs & Services → OAuth consent screen** → *Internal* (Workspace org) or
   *External* + add your email as a Test user. Scopes are just `openid email
   profile` (nothing sensitive — no Google verification needed).
3. **Credentials → Create credentials → OAuth client ID** → Application type
   **Web application** → Authorized redirect URI **`http://localhost:8400`** → Create.
4. Put the values in `.env`:
   ```ini
   MSADS_AUTH_PROVIDER=google
   MSADS_DEVELOPER_TOKEN=your-developer-token
   MSADS_GOOGLE_CLIENT_ID=xxxx.apps.googleusercontent.com
   MSADS_GOOGLE_CLIENT_SECRET=GOCSPX-xxxx
   ```

### Option B — Microsoft (Entra)

1. [Entra portal](https://entra.microsoft.com) → **App registrations → New registration**.
   - Supported account types: *Accounts in any org directory and personal Microsoft accounts*.
   - **Authentication → Add a platform → Mobile and desktop applications** →
     redirect `http://localhost:8400`; set **Allow public client flows = Yes**.
2. **API permissions → Add → APIs my organization uses →** "Microsoft Advertising
   API" (or the `ads.microsoft.com/msads.manage` scope).
3. Put the values in `.env`:
   ```ini
   MSADS_AUTH_PROVIDER=microsoft
   MSADS_DEVELOPER_TOKEN=your-developer-token
   MSADS_CLIENT_ID=your-application-client-id
   MSADS_TENANT=common
   # For a confidential (Web) app instead of public client, also set:
   # MSADS_CLIENT_SECRET=...
   # MSADS_REDIRECT_URI=http://localhost:8400
   ```

## Authorize (one time)

```bash
.venv/bin/microsoft-ads-auth
```

This opens your browser on a loopback redirect, captures the auth code locally
(nothing to copy/paste), and saves the refresh token.

## Register with your MCP client

### Claude Code
```bash
claude mcp add microsoft-ads -s user -- /absolute/path/to/microsoft-ads-mcp/.venv/bin/microsoft-ads-mcp
```

### Claude Desktop
Add to `claude_desktop_config.json`:
```json
{
  "mcpServers": {
    "microsoft-ads": {
      "command": "/absolute/path/to/microsoft-ads-mcp/.venv/bin/microsoft-ads-mcp"
    }
  }
}
```
Restart Claude Desktop.

The server finds its `.env` from the project root, so no env vars are needed in
the client config.

## Example prompts

- "List my Microsoft Ads campaigns and their last-30-day spend and conversions."
- "Find wasted spend in the last 30 days and suggest negative keywords."
- "Add 'free' and 'jobs' as phrase negatives to campaign X."
- "Create a paused Search campaign 'Brand' with a $10 daily budget."

## Configuration reference

| Env var | Default | Notes |
|---------|---------|-------|
| `MSADS_AUTH_PROVIDER` | `google` | `google` or `microsoft` |
| `MSADS_DEVELOPER_TOKEN` | — | required |
| `MSADS_GOOGLE_CLIENT_ID` / `_SECRET` | — | required for Google |
| `MSADS_CLIENT_ID` | — | required for Microsoft |
| `MSADS_TENANT` | `common` | Microsoft only |
| `MSADS_CLIENT_SECRET` / `MSADS_REDIRECT_URI` | — | Microsoft confidential app |
| `MSADS_LOOPBACK_PORT` | `8400` | must match the registered redirect |
| `MSADS_ENVIRONMENT` | `production` | `production` or `sandbox` |
| `MSADS_TOKEN_FILE` | `~/.config/microsoft-ads-mcp/tokens.json` | refresh-token store |

## License

MIT — see [LICENSE](LICENSE).

TDQS

A3.7/5.0

Scored across 26 tools

Disambiguation4/5

Tools are mostly distinct with clear resource/action pairing (list_campaigns vs list_ad_groups vs set_campaign_status). A few analytics tools (account_overview, performance_report, compare_periods) have overlapping report-like purposes but their descriptions clarify different use cases.

Naming Consistency3/5

The majority use verb_noun (list_*, set_*, add_*, create_*), but several key tools break the pattern with noun-first names (performance_report, account_overview, optimization_audit, search_term_harvest). This mixed convention is readable but not fully predictable.

Tool Count4/5

26 tools exceeds the typical 3-15 sweet spot, but the breadth of Microsoft Ads management (accounts, campaigns, ad groups, keywords, ads, negatives, shared lists, reporting, optimization) justifies the count. Each tool serves a distinct purpose; none are redundant.

Completeness4/5

Core lifecycle coverage is solid: create/list/set-update for campaigns, ad groups, keywords, and ads, plus negative keyword management and rich reporting. Minor gaps include no way to delete keywords/ads, no ad group bid update after creation, and shared list management limited to adding negatives (no remove/create/delete list tools).

Maintenance

ActivityInactive
ResponsivenessNo issues