Paid Media MCP
by arcticgreyy
README.md
# Paid Media MCP
A [Model Context Protocol (MCP)](https://modelcontextprotocol.io) server template for paid media teams. Connect Claude to your campaign data, team structure, performance history, attribution models, reporting templates, asset library, test-and-learn history, audience library, and measurement setup — so it can answer questions, write reports, debug tracking issues, and assist with analysis directly in your workflow.
**This is a template.** The example data is for a fictional e-commerce company ("Acme Corp"). You replace it with your own.
---
## Table of Contents
1. [What this does](#what-this-does)
2. [Quick start](#quick-start)
3. [Filling in your data](#filling-in-your-data)
- [metadata.json](#metadatajson)
- [accounts.json](#accountsjson)
- [teams.json](#teamsjson)
- [team-members.json](#team-membersjson)
- [campaigns.json](#campaignsjson)
- [historical-performance.json](#historical-performancejson)
- [attribution-models.json](#attribution-modelsjson)
- [reporting-templates.json](#reporting-templatesjson)
- [assets.json](#assetsjson)
- [testing.json](#testingjson)
- [audiences.json](#audiencesjson)
- [measurement.json](#measurementjson)
4. [What Claude can do](#what-claude-can-do)
- [Tools](#tools)
- [Resources](#resources)
- [Prompts](#prompts)
5. [Example conversations](#example-conversations)
6. [Connecting to live APIs](#connecting-to-live-apis)
7. [Troubleshooting](#troubleshooting)
8. [Project structure](#project-structure)
---
## What this does
When connected to Claude, this MCP server gives Claude real knowledge of your paid media operation:
- **Your campaigns** — platforms, budgets, objectives, targeting, funnel stage, status
- **Your team structure** — who manages what, their KPIs, platforms, and responsibilities
- **Your performance data** — historical metrics you've loaded, with automatic aggregation
- **Your attribution setup** — how you measure conversions, window settings, model comparisons
- **Your reporting formats** — templates for weekly team reports, executive decks, pacing dashboards
Without this, Claude can only give generic paid media advice. With it, Claude can say:
> "Looking at your Q2 Meta prospecting campaign, it's running a 2.4x ROAS against your 4.0x target. The retargeting campaign is at 12.3x, which suggests the prospecting pool may be too cold — worth tightening the lookalike to 1% and suppressing recent purchasers."
---
## Quick start
### Prerequisites
- [Node.js 18+](https://nodejs.org/)
- [Claude Desktop](https://claude.ai/download) (for connecting Claude)
- Git
### Step 1 — Clone and install
```bash
git clone https://github.com/arcticgreyy/paidmedia-mcp.git
cd paidmedia-mcp
npm install
```
### Step 2 — Fill in your data
Edit the JSON files in the `data/` folder. Each file has detailed examples. See the [Filling in your data](#filling-in-your-data) section for field-by-field guidance.
At minimum, fill in:
- `data/metadata.json` — your company name
- `data/accounts.json` — your ad accounts
- `data/teams.json` — your team(s)
The server will start even if other files are missing or partially filled.
### Step 3 — Build
```bash
npm run build
```
For development without building (requires `tsx`):
```bash
npm run dev
```
### Step 4 — Connect to Claude Desktop
Open your Claude Desktop config file:
- **Mac:** `~/Library/Application Support/Claude/claude_desktop_config.json`
- **Windows:** `%APPDATA%\Claude\claude_desktop_config.json`
Add the following (replace the paths with your actual absolute paths):
```json
{
"mcpServers": {
"paid-media": {
"command": "node",
"args": ["/absolute/path/to/paidmedia-mcp/dist/index.js"],
"env": {
"PAID_MEDIA_DATA_DIR": "/absolute/path/to/paidmedia-mcp/data"
}
}
}
}
```
**To find your absolute path**, run this from the project folder:
```bash
pwd
```
Copy the output and append `/dist/index.js` for the `args` value and `/data` for `PAID_MEDIA_DATA_DIR`.
### Step 5 — Restart Claude Desktop
Fully quit and reopen Claude Desktop. You should see a hammer icon (🔨) in the chat input — click it to verify the paid-media tools are listed.
### Updating data
After editing files in `data/`, restart Claude Desktop (or the MCP server process) for changes to take effect. The server loads data files at startup.
---
## Filling in your data
### `metadata.json`
Basic company info. Used in report headers and resource descriptions.
```json
{
"metadata": {
"company_name": "Your Company Name",
"industry": "E-commerce",
"primary_currency": "USD",
"fiscal_year_start": "01-01",
"last_updated": "2026-05-31"
}
}
```
| Field | Required | Notes |
|---|---|---|
| `company_name` | Yes | Appears in Claude's context |
| `industry` | No | Helps Claude give relevant benchmarks and advice |
| `primary_currency` | Yes | ISO 4217 code (USD, EUR, GBP, etc.) |
| `fiscal_year_start` | Yes | MM-DD format |
| `last_updated` | Yes | ISO date — update when you refresh data |
---
### `accounts.json`
One entry per ad account. Each account belongs to exactly one team.
```json
{
"accounts": [
{
"id": "acc_brand_gads",
"name": "Brand — Google Ads",
"platform": "google_ads",
"platform_account_id": "123-456-7890",
"team_id": "team_brand",
"status": "active",
"currency": "USD",
"timezone": "America/New_York",
"monthly_budget": 50000,
"notes": "Brand campaigns only"
}
]
}
```
| Field | Required | Notes |
|---|---|---|
| `id` | Yes | Your internal ID — used in campaigns.json and teams.json |
| `name` | Yes | Human-readable name for Claude to display |
| `platform` | Yes | See [platform values](#platform-values) below |
| `platform_account_id` | Yes | The actual ID shown in the platform UI (e.g. Google Ads customer ID) |
| `team_id` | Yes | Must match an `id` in `teams.json` |
| `status` | Yes | `active` or `inactive` |
| `currency` | Yes | ISO 4217 |
| `timezone` | Yes | IANA timezone string |
| `monthly_budget` | No | Used for pacing analysis |
| `notes` | No | Free text — Claude reads this |
**Platform values:** `google_ads` · `meta` · `dv360` · `youtube` · `linkedin` · `tiktok` · `twitter_x` · `pinterest` · `snapchat` · `amazon` · `other`
---
### `teams.json`
One entry per media team. This is where you capture the strategic context Claude needs to give relevant advice.
```json
{
"teams": [
{
"id": "team_brand",
"name": "Brand & Awareness",
"description": "Manages upper-funnel brand campaigns focused on reach and video.",
"objectives": ["awareness", "reach", "video_views"],
"primary_kpis": ["impressions", "reach", "cpm", "brand_lift"],
"account_ids": ["acc_brand_gads", "acc_brand_dv360"],
"member_ids": ["user_sarah", "user_james"],
"lead_id": "user_sarah",
"platforms": ["google_ads", "dv360", "youtube"],
"reporting_cadence": "weekly",
"budget_owner": "vp_marketing",
"notes": "Brand lift studies run quarterly. All campaigns follow brand safety guidelines."
}
]
}
```
| Field | Required | Notes |
|---|---|---|
| `id` | Yes | Referenced by accounts and campaigns |
| `objectives` | Yes | List from: `awareness` `reach` `traffic` `engagement` `video_views` `lead_generation` `app_installs` `conversions` `catalog_sales` `store_visits` |
| `primary_kpis` | Yes | Free-text metric names — Claude uses these when reviewing performance |
| `account_ids` | Yes | Must match IDs in `accounts.json` |
| `member_ids` | Yes | Must match IDs in `team-members.json` |
| `lead_id` | Yes | Team lead — must be in `member_ids` |
| `reporting_cadence` | Yes | `daily` `weekly` `biweekly` `monthly` |
| `notes` | No | Put key context here: targets, processes, constraints |
**Tip:** The `notes` and `description` fields are the most valuable for Claude. Include:
- ROAS/CPA/CPL targets
- Key rules or constraints (e.g. "brand safe only")
- Important processes (e.g. "budget reviews every Monday")
- Links or references to external docs
---
### `team-members.json`
One entry per person. Members can belong to multiple teams.
```json
{
"team_members": [
{
"id": "user_mike",
"name": "Mike Rodriguez",
"email": "mike@yourcompany.com",
"role": "director",
"team_ids": ["team_performance"],
"platform_specialties": ["google_ads", "meta"],
"responsibilities": [
"Performance team leadership",
"ROAS and CPA target setting",
"Budget allocation across channels"
],
"notes": "Primary stakeholder for attribution model decisions."
}
]
}
```
| Field | Required | Notes |
|---|---|---|
| `id` | Yes | Must match `member_ids` in teams.json |
| `role` | Yes | `media_buyer` `media_planner` `analyst` `strategist` `manager` `director` `other` |
| `team_ids` | Yes | Array — analysts or shared staff can be on multiple teams |
| `platform_specialties` | Yes | Which platforms they work in day-to-day |
| `responsibilities` | Yes | Free-text list — Claude uses this to route questions to the right person |
| `notes` | No | Useful for capturing context like certifications, agency relationships, or ownership areas |
---
### `campaigns.json`
One entry per campaign. This is the largest and most important data file.
```json
{
"campaigns": [
{
"id": "camp_perf_search_001",
"name": "Performance Search — Always On",
"platform": "google_ads",
"account_id": "acc_perf_gads",
"team_id": "team_performance",
"status": "active",
"objective": "conversions",
"budget": {
"type": "daily",
"amount": 2000,
"currency": "USD",
"pacing": "standard"
},
"start_date": "2026-01-01",
"end_date": null,
"targeting": {
"geo": ["US"],
"devices": ["desktop", "mobile"],
"keyword_themes": ["branded", "competitor", "category"]
},
"funnel_stage": "lower",
"tags": ["always-on", "search", "performance"],
"notes": "Target ROAS: 5.0x. Smart Bidding tROAS strategy."
}
]
}
```
**Budget types:** `daily` · `lifetime` · `monthly`
**Objective values:** `awareness` · `reach` · `traffic` · `engagement` · `video_views` · `lead_generation` · `app_installs` · `conversions` · `catalog_sales` · `store_visits`
**Funnel stages:** `upper` · `mid` · `lower`
**Status values:** `active` · `paused` · `ended` · `draft` · `archived`
**Targeting fields** (all optional):
| Field | Example |
|---|---|
| `geo` | `["US", "CA", "GB"]` |
| `audience_segments` | `["lookalike_1pct_purchasers", "in-market_home_goods"]` |
| `age_range` | `{ "min": 25, "max": 54 }` |
| `gender` | `"all"` · `"male"` · `"female"` |
| `devices` | `["desktop", "mobile", "tablet", "connected_tv"]` |
| `keyword_themes` | `["branded", "competitor", "generic"]` |
| `custom_audiences` | `["cart_abandoners_14d", "crm_suppression"]` |
**Tags tip:** Tags are searchable. Use them consistently for filtering — e.g. `q2-2026`, `always-on`, `brand`, `retargeting`, `test`.
---
### `historical-performance.json`
Contains two sections: daily records and benchmarks.
#### Records
One entry per campaign per day. Include whatever metrics you have — rate metrics are re-calculated automatically when aggregating.
```json
{
"records": [
{
"campaign_id": "camp_perf_search_001",
"date": "2026-05-01",
"metrics": {
"impressions": 125000,
"clicks": 4200,
"spend": 1850.00,
"conversions": 310,
"conversion_value": 12400.00
}
}
]
}
```
**Available metric fields:**
| Metric | Description |
|---|---|
| `impressions` | Total ad impressions |
| `clicks` | Total clicks |
| `spend` | Total spend in account currency |
| `reach` | Unique users reached |
| `frequency` | Average impressions per user |
| `ctr` | Click-through rate (%) |
| `cpc` | Cost per click |
| `cpm` | Cost per 1,000 impressions |
| `cpa` | Cost per acquisition/conversion |
| `roas` | Return on ad spend |
| `conversions` | Total conversion events |
| `conversion_value` | Revenue value of conversions |
| `video_views` | Video view count |
| `video_view_rate` | Percentage who watched |
| `view_through_conversions` | View-assisted conversions |
| `custom_metrics` | Any additional metrics as key-value pairs |
**Tip:** You don't need to pre-calculate rate metrics (CTR, CPC, ROAS). The server calculates them when aggregating. Just include the raw counts.
**How to export data:** Most platforms let you download daily campaign performance as CSV. Use a tool like Google Sheets or Python to convert to this JSON format. See [data/historical-performance.json](data/historical-performance.json) for the full structure.
#### Benchmarks
Industry reference points for comparison. Optional but makes performance analysis much richer.
```json
{
"benchmarks": [
{
"platform": "google_ads",
"objective": "conversions",
"industry": "e-commerce",
"avg_ctr": 2.69,
"avg_cpc": 1.33,
"avg_cpa": 33.52,
"avg_roas": 3.5
}
]
}
```
Use published industry benchmarks from WordStream, Meta, Google, or your agency. Update annually.
---
### `attribution-models.json`
Documents how you measure conversions — not connected to live platforms, purely descriptive. Claude uses this to explain your measurement setup and make recommendations.
```json
{
"attribution_configurations": [
{
"id": "attr_last_click_30d",
"name": "Last Click — 30-Day",
"model": "last_click",
"window": {
"click": 30,
"view": 0,
"unit": "days"
},
"platforms_applied": ["google_ads", "meta"],
"conversion_events": ["purchase", "lead_form_submit"],
"cross_device": false,
"view_through_enabled": false,
"description": "100% credit to the last clicked ad within 30 days.",
"use_cases": [
"Bottom-funnel campaign optimization",
"Simple baseline for cross-channel comparison"
],
"notes": "Over-credits search/retargeting; undervalues prospecting."
}
]
}
```
**Model values:** `last_click` · `first_click` · `linear` · `time_decay` · `position_based` · `data_driven` · `custom`
**Tip:** Add one entry per meaningful configuration you use — e.g. one for Google Ads, one for Meta, one for cross-channel analysis. The `use_cases` and `notes` fields are especially valuable for Claude's analysis.
---
### `reporting-templates.json`
Defines the structure of your reports and dashboards. Claude uses these when generating reports to follow the right format for the right audience.
```json
{
"reporting_templates": [
{
"id": "tmpl_weekly_team",
"name": "Weekly Performance Report",
"type": "performance_summary",
"audience": "media_team",
"cadence": "weekly",
"metrics_included": ["spend", "conversions", "roas", "cpa"],
"dimensions": ["campaign", "platform", "date"],
"visualizations": ["spend_by_campaign_bar", "roas_trend_line"],
"delivery_format": ["google_sheets", "slack"],
"sections": [
{
"title": "Week Summary",
"description": "Overall performance vs. prior week and vs. targets.",
"metrics": ["spend", "conversions", "roas"]
},
{
"title": "Campaign Scorecards",
"description": "One row per active campaign with pacing status.",
"metrics": ["spend", "conversions", "cpa", "roas"]
},
{
"title": "Action Items",
"description": "Specific actions to take next week.",
"metrics": []
}
]
}
]
}
```
**Audience values:** `executive` · `media_team` · `client` · `internal`
**Type values:** `performance_summary` · `pacing` · `budget_flight` · `audience_insights` · `creative_analysis` · `channel_mix` · `attribution_path` · `executive_summary` · `custom`
**Tip:** The `sections` array is the most important part — it's the outline Claude follows when writing a report. Make section descriptions as specific as possible.
---
### `assets.json`
Documents your creative asset library and per-platform specs. Claude uses this to answer asset questions, check spec compliance, and guide campaign trafficking.
```json
{
"asset_library": {
"dam_system": "Bynder",
"dam_url": "https://yourcompany.bynder.com",
"access_instructions": "Request access via IT helpdesk. Login with SSO.",
"brand_guidelines_url": "https://yourcompany.bynder.com/brand-guidelines",
"copy_guidelines_url": "https://yourcompany.bynder.com/copy-guidelines",
"categories": [
{
"id": "cat_social_video",
"name": "Social Video",
"type": "video",
"location_url": "https://yourcompany.bynder.com/collections/social-video",
"naming_convention": "{brand}_{campaign}_{duration}s_{platform}_{version}",
"specs": [
{
"platform": "meta",
"format": "MP4 or MOV",
"dimensions": "1080x1080, 1080x1920, 1920x1080",
"max_file_size": "4GB",
"duration_max": "60s (Reels), 15s (Stories)",
"notes": "Include captions — 85% watch without sound"
}
]
}
]
}
}
```
**Asset type values:** `image` · `video` · `copy` · `audio` · `html5` · `document` · `other`
**Tip:** The `specs` array per category is especially valuable — Claude can answer "what do I need to traffic this campaign on TikTok?" directly from this data.
---
### `testing.json`
Documents your entire test-and-learn program: methodology, tools, and every test (active, planned, completed). This gives Claude a searchable institutional memory of what your team has tested and learned.
```json
{
"testing_program": {
"methodology": {
"confidence_threshold": 95,
"require_stat_sig": true,
"minimum_sample_size": 1000,
"minimum_test_duration_days": 14,
"minimum_detectable_effect_pct": 10,
"winner_criteria": "≥10% lift at 95% confidence, minimum 14 days runtime. If stat sig not achieved, test is inconclusive — retain prior best practice."
},
"tools": [
{
"id": "tool_meta_ab",
"name": "Meta A/B Testing (native)",
"type": "platform_native",
"platform": "meta",
"used_for": ["Creative A/B tests", "Audience split tests"]
}
],
"tests": [
{
"id": "test_001",
"name": "UGC vs Brand Creative",
"hypothesis": "UGC content will drive lower CPA on Meta prospecting due to higher thumb-stop rate.",
"status": "completed",
"type": "creative",
"platform": "meta",
"variants": [
{ "id": "v_control", "name": "Brand Creative", "description": "Polished brand video", "is_control": true },
{ "id": "v_ugc", "name": "UGC Video", "description": "Creator-style mobile video", "is_control": false }
],
"results": {
"winner_variant_id": "v_ugc",
"stat_sig_achieved": true,
"confidence_level": 97,
"primary_metric": "CPA",
"primary_metric_lift_pct": -23,
"conclusion": "UGC drove 23% lower CPA.",
"action_taken": "Scaled UGC — producing 2 new variants monthly."
}
}
]
}
}
```
| Field | Required | Notes |
|---|---|---|
| `methodology.confidence_threshold` | Yes | 90 or 95 are most common |
| `methodology.winner_criteria` | Yes | Plain-English rule — Claude quotes this when analyzing tests |
| `tests[].hypothesis` | Yes | Claude uses this to evaluate whether the test was well-designed |
| `tests[].results.primary_metric_lift_pct` | No | Negative = improvement for cost metrics (CPA, CPC) |
**Test type values:** `creative` · `audience` · `bidding` · `landing_page` · `copy` · `format` · `offer` · `other`
**Test status values:** `planned` · `active` · `completed` · `paused` · `abandoned`
**Tip:** Historical tests are the most valuable part — the more completed tests you document, the better Claude can summarize learnings and recommend next experiments.
---
### `audiences.json`
Documents your full audience infrastructure: first-party segments, contracted data providers, data onboarding platforms, lookalike strategy, and third-party overlay layers.
```json
{
"audience_library": {
"business_unit": "Consumer",
"first_party_audiences": [
{
"id": "aud_purchasers_180d",
"name": "Past Purchasers — 180 Days",
"type": "pixel_based",
"description": "All purchasers in the last 180 days.",
"size_estimate": 45000,
"platforms_available": ["meta", "google_ads"],
"refresh_cadence": "daily",
"tags": ["purchasers", "lookalike-seed"]
}
],
"data_providers": [
{
"id": "dp_oracle",
"name": "Oracle Data Cloud",
"contract_status": "active",
"segments_available": ["In-Market: Home & Garden"],
"platforms_available": ["dv360", "google_ads"],
"contract_end_date": "2026-12-31"
}
],
"onboarding_platforms": [
{
"id": "ob_liveramp",
"name": "LiveRamp",
"type": "data_onboarding",
"platforms_connected": ["meta", "google_ads", "dv360"],
"use_cases": ["CRM list onboarding", "Identity resolution"]
}
],
"lookalike_strategy": {
"default_expansion_pct": 1,
"entries": [
{
"seed_audience_id": "aud_purchasers_180d",
"seed_audience_name": "Past Purchasers — 180 Days",
"platform": "meta",
"expansion_percentages": [1, 2, 5],
"best_performing_expansion": 1
}
]
},
"third_party_layers": [
{
"id": "3p_in_market",
"name": "In-Market: Your Category",
"provider": "Google",
"category": "in-market",
"platforms_available": ["google_ads", "dv360"],
"is_default": true,
"is_best_performer": true,
"cpm_premium_estimate": 0.50
}
]
}
}
```
**First-party audience types:** `crm_list` · `pixel_based` · `customer_match` · `email_list` · `app_users` · `lookalike_seed` · `suppression` · `other`
**Onboarding platform types:** `clean_room` · `data_onboarding` · `identity_resolution` · `cdp`
**Tip:** Set `is_default: true` on audience layers you apply to every campaign, and `is_best_performer: true` on layers with proven efficiency gains — Claude uses both flags to make targeting recommendations.
---
### `measurement.json`
Documents your full tracking and measurement infrastructure: tag management, pixels, Conversion APIs, CM360/Floodlight setup, website data layer, and measurement partners.
```json
{
"measurement_setup": {
"tag_management": {
"system": "google_tag_manager",
"container_id": "GTM-XXXXXXX",
"implementation_type": "hybrid",
"server_side_endpoint": "https://sst.yourcompany.com"
},
"pixels_and_tags": [
{
"id": "pixel_meta",
"name": "Meta Pixel",
"platform": "meta",
"pixel_id": "XXXXXXXXXXXXXXXX",
"implementation": "both",
"events_tracked": ["PageView", "AddToCart", "Purchase"],
"custom_parameters": ["value", "currency", "order_id"]
}
],
"conversion_apis": [
{
"id": "capi_meta",
"platform": "meta",
"api_name": "Meta Conversions API (CAPI)",
"implementation": "both",
"events_sent": ["Purchase", "Lead"],
"match_rate_estimate_pct": 87,
"deduplication_method": "event_id matched client-side and server-side"
}
],
"cm360": {
"account_id": "XXXXXXX",
"floodlight_configuration_id": "FL-XXXXXXXX",
"u_variables": [
{ "variable": "u1", "name": "order_id", "type": "string", "description": "Unique order ID for deduplication" },
{ "variable": "u2", "name": "order_value", "type": "number", "description": "Order revenue in USD" }
]
},
"website_data_capture": {
"data_layer_implemented": true,
"data_layer_spec_url": "https://docs.yourcompany.com/datalayer",
"data_layer_variables": ["pageType", "transactionId", "transactionRevenue", "userId"],
"analytics_platform": "Google Analytics 4",
"analytics_property_id": "G-XXXXXXXXXX",
"first_party_cookies_implemented": true,
"cookie_domain": ".yourcompany.com",
"cookie_session_duration": "13 months",
"cookie_data_captured": ["_ga", "_gcl_aw (GCLID)", "_fbc (Meta click ID)"]
},
"measurement_partners": [
{
"id": "mp_mmm",
"name": "Your MMM Provider",
"type": "mmm",
"status": "active",
"platforms_covered": ["google_ads", "meta", "dv360"],
"cadence": "quarterly"
}
]
}
}
```
**Tag management system values:** `google_tag_manager` · `tealium` · `adobe_launch` · `segment` · `mparticle` · `manual` · `other`
**Implementation type values:** `client_side` · `server_side` · `hybrid`
**Measurement partner types:** `mmm` · `incrementality` · `brand_lift` · `attribution` · `analytics` · `identity` · `other`
**Tip:** The `cm360.u_variables` section is especially useful — Claude can explain what each u-variable captures and help troubleshoot Floodlight discrepancies when you reference specific variable names.
---
## What Claude can do
### Tools
Tools are actions Claude takes to retrieve your data.
#### Campaign tools
| Tool | What it does |
|---|---|
| `list_campaigns` | Filter campaigns by team, platform, status, objective, funnel stage, or tag |
| `get_campaign` | Full details for one campaign by ID |
| `list_accounts` | All accounts, optionally filtered by team |
| `get_account` | Full account details by ID |
#### Team tools
| Tool | What it does |
|---|---|
| `list_teams` | All teams with objectives, KPIs, platforms |
| `get_team` | Team details + its members + its accounts |
| `get_team_for_account` | Which team owns a given account |
| `list_team_members` | Members, optionally filtered by team |
| `get_team_member` | Full member details |
#### Performance tools
| Tool | What it does |
|---|---|
| `get_campaign_performance` | Per-day records + aggregated totals for a campaign |
| `get_team_performance` | Aggregated totals by team, broken down per campaign |
| `get_benchmarks` | Industry benchmarks by platform and objective |
#### Attribution tools
| Tool | What it does |
|---|---|
| `list_attribution_models` | All configured attribution setups |
| `get_attribution_model` | Full details for one model |
| `compare_attribution_models` | Side-by-side diff of two models |
#### Reporting tools
| Tool | What it does |
|---|---|
| `list_reporting_templates` | Templates filtered by audience |
| `get_reporting_template` | Full template with all sections |
| `build_performance_report` | Assembles raw data + template for Claude to narrate |
#### Asset tools
| Tool | What it does |
|---|---|
| `get_asset_library` | DAM system info, access instructions, guidelines links, category summary |
| `list_asset_categories` | All asset categories, optionally filtered by type (image, video, copy, etc.) |
| `get_asset_category` | Full details for one category: location, naming convention, specs |
| `get_asset_specs` | Platform-specific specs (dimensions, file size, format) for a given asset type and platform |
#### Testing tools
| Tool | What it does |
|---|---|
| `get_testing_methodology` | Confidence threshold, stat sig rules, winner criteria, and testing tools in use |
| `list_tests` | All tests filtered by status, type, team, or platform |
| `get_test` | Full details for one test: hypothesis, all variants, results |
| `get_test_learnings` | Summarized learnings from all completed tests |
#### Audience tools
| Tool | What it does |
|---|---|
| `get_audience_library_overview` | High-level summary: 1P count, data providers, onboarding platforms, LAL strategy |
| `list_first_party_audiences` | All 1P segments filtered by business unit or platform |
| `list_data_providers` | Contracted data providers filtered by contract status |
| `get_lookalike_strategy` | Full LAL strategy: seed audiences, expansion sizes, best performers |
| `list_third_party_audience_layers` | Overlay segments filtered by platform, default use, or best-performer flag |
| `get_onboarding_platforms` | Data onboarding and clean room platforms in use |
#### Measurement tools
| Tool | What it does |
|---|---|
| `get_measurement_overview` | High-level tracking stack: TMS, pixel count, CAPI count, measurement partners |
| `get_tag_management` | TMS details: platform, container ID, implementation type, server-side endpoint |
| `list_pixels_and_tags` | All platform pixels filtered by platform: events tracked, implementation |
| `list_conversion_apis` | All Conversion API implementations: events, match rate, deduplication method |
| `get_cm360_setup` | CM360 account, Floodlight config ID, and all u-variables with descriptions |
| `get_website_data_capture` | Data layer status/variables, analytics platform, first-party cookie setup |
| `list_measurement_partners` | MMM, incrementality, brand lift, attribution partners filtered by type |
---
### Resources
Resources are documents Claude can read as context (similar to attaching a file).
| Resource URI | What it contains |
|---|---|
| `paid-media://overview` | Company metadata + all teams + all accounts |
| `paid-media://campaigns` | All campaigns |
| `paid-media://team-structure` | Teams enriched with their members |
| `paid-media://attribution-models` | All attribution configurations |
| `paid-media://reporting-templates` | All reporting templates |
| `paid-media://asset-library` | Full asset library: DAM info, categories, and specs |
| `paid-media://testing-program` | Full testing program: methodology, tools, and all tests |
| `paid-media://audience-library` | Full audience library: 1P, providers, LAL strategy, 3P layers |
| `paid-media://measurement-setup` | Full tracking stack: TMS, pixels, APIs, CM360, data capture |
---
### Prompts
Pre-built prompt templates that guide Claude through multi-step analysis tasks. Access them from Claude's prompt picker (the `/` command in supported clients).
| Prompt | Arguments | What it does |
|---|---|---|
| `campaign_performance_review` | `campaign_id`, `date_from`, `date_to` | Full performance review with pacing and benchmark comparison |
| `team_weekly_report` | `team_id`, `week_start` | Weekly scorecard using your team's reporting template |
| `attribution_analysis` | `campaign_id` | Explains model options and recommends the right one for the campaign objective |
| `budget_pacing_check` | `team_id` (optional), `check_date` | Flags over/under-pacing campaigns with specific actions |
| `channel_mix_analysis` | `team_id`, `date_from`, `date_to` | Channel efficiency ranking and reallocation recommendations |
| `test_and_learn_review` | `team_id` (optional), `platform` (optional) | Summarizes test history, active tests, gaps, and recommends next experiments |
| `audience_strategy_review` | `platform` | Full audience strategy audit: 1P usage, LAL quality, 3P layer gaps, recommendations |
| `measurement_audit` | _(none)_ | End-to-end tracking audit: signal gaps, deduplication risks, attribution reliability |
| `asset_readiness_check` | `campaign_id` | Checks whether required assets exist for a campaign's platform and generates a trafficking checklist |
---
## Example conversations
Once connected, you can ask Claude things like:
**Campaign lookup**
> "What active Meta campaigns does the performance team have running right now?"
> "Show me all upper-funnel campaigns tagged q2-2026."
**Performance analysis**
> "How did the search always-on campaign perform last week? Compare it to our benchmarks."
> "Which of our campaigns had the best ROAS in May?"
**Pacing**
> "Is our Q2 Meta prospecting campaign on pace to deliver its budget?"
> "Check pacing across all active campaigns as of today."
**Team and ownership**
> "Who manages the LinkedIn account and what are their KPIs?"
> "I need to talk to someone about our Meta creative strategy — who should I contact?"
**Attribution**
> "We're seeing a big discrepancy between Meta reported conversions and GA4. Can you explain why that might be based on our attribution setup?"
> "Should we use last-click or data-driven attribution for our Google Shopping campaigns?"
**Reporting**
> "Write a weekly performance report for the performance team for the week of May 26."
> "Generate an executive summary of our Q2 paid media results."
**Assets**
> "What video specs do I need for TikTok? What about YouTube?"
> "Where do I find the Q2 brand campaign assets and what's the naming convention?"
> "Are we ready to launch the Meta prospecting campaign? Do we have all the required creative sizes?"
**Testing**
> "What have we learned from our Meta creative tests this year?"
> "We want to test bid strategies on Google Ads — has anyone tested tROAS vs tCPA before? What happened?"
> "What should we test next on LinkedIn? We haven't run any tests there in 6 months."
> "Is the TikTok creator test statistically significant yet?"
**Audiences**
> "What first-party audiences do we have available on Meta right now?"
> "Explain our lookalike strategy — what seed audiences are we using and what expansion size performs best?"
> "We have an Experian contract — are we using all the segments we're paying for?"
> "What third-party audience layers should we apply to a new DV360 campaign targeting homeowners?"
**Measurement**
> "Do we have server-side tracking on Meta? What's our Conversions API match rate?"
> "What are our CM360 u-variables and what does u3 capture?"
> "We're seeing a discrepancy between Meta CAPI and GA4 purchase counts — why might that happen based on our setup?"
> "Is our data layer capturing order value correctly for all conversion events?"
> "What measurement partners do we use and when is our next MMM run?"
---
## Connecting to live APIs
The default `FileAdapter` reads from local JSON files. To connect to a live platform API:
**Step 1** — Create a new adapter file, e.g. `src/adapters/google-ads-adapter.ts`
**Step 2** — Implement the `PaidMediaAdapter` interface:
```typescript
import type { PaidMediaAdapter } from "./base.js";
// ... import Google Ads API client
export class GoogleAdsAdapter implements PaidMediaAdapter {
constructor(private customerId: string) {}
async getCampaigns(filters = {}) {
// call Google Ads API
}
// implement all other methods...
}
```
**Step 3** — Swap it in `src/index.ts`:
```typescript
// Before:
const adapter = new FileAdapter(DATA_DIR);
// After:
const adapter = new GoogleAdsAdapter({
customerId: process.env.GOOGLE_ADS_CUSTOMER_ID!,
developerToken: process.env.GOOGLE_ADS_DEVELOPER_TOKEN!,
});
```
All tools, resources, and prompts work unchanged — they only call the adapter interface.
**Hybrid approach:** You can also create a `HybridAdapter` that pulls campaigns from the API but falls back to file data for teams, attribution, and reporting templates (which rarely change and aren't in platform APIs).
---
## Troubleshooting
### Claude Desktop doesn't show the paid-media tools
1. Check the config path: `~/Library/Application Support/Claude/claude_desktop_config.json` (Mac) or `%APPDATA%\Claude\claude_desktop_config.json` (Windows)
2. Make sure paths in the config are absolute, not relative
3. Check that `npm run build` ran without errors (`dist/index.js` must exist)
4. Fully quit and reopen Claude Desktop (Cmd+Q on Mac, not just closing the window)
5. Check Claude Desktop's MCP logs: **Settings → Developer → Logs**
### Server starts but returns no data
The server logs warnings (to stderr) for each data file it can't load. Run the server directly to see them:
```bash
node dist/index.js
```
You'll see lines like:
```
[FileAdapter] Warning: Data file not found: /path/to/data/campaigns.json
```
### Data changes aren't reflected
The server loads data files at startup. After editing any file in `data/`, restart the MCP server:
- In Claude Desktop: **Settings → Developer** → restart the paid-media server
- Or fully restart Claude Desktop
### JSON syntax errors
If a data file has a syntax error, the server silently skips it. Validate your JSON at [jsonlint.com](https://jsonlint.com) or run:
```bash
node -e "JSON.parse(require('fs').readFileSync('data/campaigns.json', 'utf8'))"
```
### Performance data not aggregating correctly
Rate metrics (CTR, CPC, ROAS) are re-computed from raw totals during aggregation. If you include both raw counts and pre-calculated rates in your records, the server will sum both, which will double-count rates. **Best practice:** include only raw count metrics in records (`impressions`, `clicks`, `spend`, `conversions`, `conversion_value`) and let the server compute rates.
---
## Project structure
```
paidmedia-mcp/
├── src/
│ ├── index.ts # MCP server entry point
│ ├── types.ts # TypeScript interfaces for all data models
│ ├── adapters/
│ │ ├── base.ts # PaidMediaAdapter interface — implement to connect live APIs
│ │ └── file-adapter.ts # Default: reads from data/*.json at startup
│ ├── tools/
│ │ ├── campaigns.ts # list_campaigns, get_campaign, list_accounts, get_account
│ │ ├── teams.ts # list_teams, get_team, get_team_for_account, list_team_members, get_team_member
│ │ ├── performance.ts # get_campaign_performance, get_team_performance, get_benchmarks
│ │ ├── attribution.ts # list_attribution_models, get_attribution_model, compare_attribution_models
│ │ ├── reporting.ts # list_reporting_templates, get_reporting_template, build_performance_report
│ │ ├── assets.ts # get_asset_library, list_asset_categories, get_asset_category, get_asset_specs
│ │ ├── testing.ts # get_testing_methodology, list_tests, get_test, get_test_learnings
│ │ ├── audiences.ts # get_audience_library_overview, list_first_party_audiences, list_data_providers,
│ │ │ # get_lookalike_strategy, list_third_party_audience_layers, get_onboarding_platforms
│ │ └── measurement.ts # get_measurement_overview, get_tag_management, list_pixels_and_tags,
│ │ # list_conversion_apis, get_cm360_setup, get_website_data_capture, list_measurement_partners
│ ├── resources/
│ │ └── index.ts # 9 readable MCP resources
│ └── prompts/
│ └── index.ts # 9 pre-built prompt templates
├── data/
│ ├── metadata.json # Company info
│ ├── accounts.json # Ad accounts by platform
│ ├── teams.json # Media teams, objectives, KPIs
│ ├── team-members.json # Team members, roles, responsibilities
│ ├── campaigns.json # All campaigns
│ ├── historical-performance.json # Daily metrics + benchmarks
│ ├── attribution-models.json # Attribution configurations
│ ├── reporting-templates.json # Report structures by audience
│ ├── assets.json # DAM info, asset categories, per-platform specs
│ ├── testing.json # Testing methodology, tools, and test history
│ ├── audiences.json # 1P audiences, data providers, LAL strategy, 3P layers
│ └── measurement.json # TMS, pixels, Conversion APIs, CM360, data layer, partners
├── claude_desktop_config.example.json # Config snippet for Claude Desktop
├── package.json
├── tsconfig.json
└── README.md
```
---
## Contributing
Issues and pull requests welcome. If you build an adapter for a specific platform (Google Ads API, Meta Marketing API, etc.), consider contributing it back.
## License
MIT