microsoft-ads-mcp
# 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
Scored across 26 tools
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.
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.
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.
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).