Meta广告管理MCP服务器

Meta广告管理MCP服务器是一个面向广告运营的MCP服务,提供99个工具,让用户通过自然语言查询、管理和优化Meta广告账户,并支持投放诊断、受众定位、创意管理和竞争研究等场景。

  • by jeffreywlai
  • Python
  • 本地部署
  • 更新于
在 GitHub 查看 jeffreywlai/meta-ads-mcp

使用说明

Meta Ads MCP Server

An optimization-first MCP server that bridges LLMs with the Meta Marketing API — tools for querying, managing, and optimizing your ad accounts through natural language.

Ask Claude or Gemini to "show me which creatives are fatiguing" or "give me an optimization snapshot for this account" — and it just works.

This is not an officially supported Meta product.

✨ Features

  • 📊 99 Tools — Discovery, reporting, activity history, diagnostics, social feedback, targeting, research, auth helpers, and controlled writes
  • 🔍 Optimization-First — Not just CRUD: pacing, fatigue, audience, and snapshot diagnostics built in
  • 📖 Built-in Docs — Object model, metrics, optimization playbook, current v26 notes, and historical v25 notes available as tools and MCP resources
  • 🎯 Full Targeting Suite — Interest, behavior, demographic, and geo search with audience size estimation
  • 🔑 Auth Helpers — Generate tokens, exchange codes, refresh tokens, and validate scopes
  • 🖼️ Creative Ops — Preview ads, upload assets, and set up A/B tests
  • 🔎 Tool Search — FastMCP 3.4.7 tool search lets the LLM discover tools on demand instead of loading the full catalog up front
  • 🖥️ Works Everywhere — Claude Code, Claude Desktop, Gemini CLI, or any MCP client

📋 Available Tools (99)

🔍 Discovery

Tool Description
list_ad_accounts List all accessible ad accounts
get_ad_account Get details for a specific ad account
get_account_pages Get Pages linked to an ad account
list_instagram_accounts List Instagram accounts linked to an ad account
list_campaigns List campaigns in an ad account, optionally filtered by name
get_campaign Get details for a specific campaign
list_adsets List ad sets in a campaign or account, optionally filtered by name
get_adset Get details for a specific ad set
list_ads List ads in an ad set or account, optionally filtered by name
get_ad Get details for a specific ad
list_audiences List custom and lookalike audiences with lightweight summary fields by default
get_audience Read one custom or lookalike audience by ID
list_creatives List ad creatives in an account
get_creative Read one ad creative by ID, including url_tags and full creative-spec fields

📊 Analysis

Tool Description
get_insights Backward-compatible alias for older insights calls
get_entity_insights Get performance insights with optional scalar action columns
get_performance_breakdown Break down performance by dimension
summarize_actions Count selected actions without returning full action arrays
compare_time_ranges Compare metrics across two time ranges
compare_performance Compare metrics across multiple entities
export_insights Export insights as CSV or structured data
create_async_insights_report Create a large async report with lean defaults or an explicit full preset
create_async_insights_report_batch Submit up to 10 independent breakdown reports sequentially
get_async_insights_report Poll or bounded-wait for an async report and retrieve compact rows

⚡ Optimization

Tool Description
get_account_optimization_snapshot Full account health and optimization summary
get_campaign_optimization_snapshot Campaign-level optimization summary
get_native_optimization_signals v26-native campaign, ad-set, or ad delivery and issue signals
get_account_health_snapshot Account totals with previous-window and YoY comparisons
detect_auction_overlap Directional cannibalization screen across campaigns
get_ad_feedback_signals Feedback availability and quality-ranking signals
get_budget_pacing_report Budget pacing and spend trajectory
get_creative_performance_report Creative performance analysis
get_creative_fatigue_report Detect creative fatigue signals
get_audience_performance_report Audience segment performance analysis
get_delivery_risk_report Delivery risks and issues
get_learning_phase_report Learning phase status for ad sets
get_recommendations Broad Meta-native opportunity scan
get_budget_opportunities Budget and scaling opportunities
get_creative_opportunities Creative asset and format opportunities
get_audience_opportunities Audience and targeting opportunities
get_delivery_opportunities Delivery and reach opportunities
get_bidding_opportunities Bid strategy opportunities

💬 Social Feedback

Tool Description
get_ad_social_context Resolve Facebook post and Instagram media ids behind an ad
list_ad_comments Read compact raw Facebook or Instagram comments for an ad or social object
list_comment_replies Continue paginated replies for one Facebook or Instagram comment
list_page_recommendations Read compact Facebook Page recommendations, reviews, or testimonials

🧾 Activity History

Tool Description
list_change_history Read account, campaign, ad set, or ad activity; object-scoped calls derive the owning account when account_id is omitted

🎯 Planning & Targeting

Tool Description
search_interests Search interest targeting options
get_interest_suggestions Get related interest suggestions
validate_interests Validate interest targeting IDs
search_geo_locations Search geographic targeting options
get_targeting_categories Get available targeting categories
search_behaviors Search behavior targeting options
search_demographics Search demographic targeting options
estimate_audience_size Estimate audience size for a targeting spec
get_reach_frequency_predictions Get reach and frequency predictions

✏️ Writes

Tool Description
create_campaign Create a new campaign
update_campaign Update campaign settings
delete_campaign Delete a campaign
create_ad_set Create or validate an ad set, including bid strategy and constraints
create_ad Create or validate an ad using a top-level or nested creative ID
delete_adset Explicitly delete an ad set
delete_ad Explicitly delete an ad
set_campaign_status Pause or enable a campaign
set_adset_status Pause or enable an ad set
set_ad_status Pause or enable an ad
update_campaign_budget Update a campaign's budget
update_adset_budget Update an ad set's budget
update_adset_bid_amount Update an ad set's bid amount
update_campaign_bid_strategy Update a campaign's bidding strategy
update_adset_bid_strategy Update an ad set's bidding strategy and constraints
create_custom_audience Create a custom audience
create_lookalike_audience Create a lookalike audience
update_custom_audience Update a custom audience
delete_audience Delete an audience
create_ad_creative Create a new ad creative
update_creative Update an ad creative
delete_creative Delete an ad creative

🖼️ Creative Ops

Tool Description
get_ad_image Get ad image details
preview_ad Preview an ad in various formats
upload_creative_asset Upload an image or video asset
setup_ab_test Set up an A/B test

🔬 Public Research

Tool Description
search_ads_archive Search the Meta Ad Library for competitor creatives

🔑 Auth Helpers

Tool Description
generate_auth_url Generate an OAuth authorization URL
exchange_code_for_token Exchange an auth code for an access token
refresh_to_long_lived_token Refresh a short-lived token to a long-lived one
generate_system_user_token Generate a system user access token
get_token_info Get info about the current token
validate_token Validate token scopes and expiry

📖 Docs & Utility

Tool Description
get_meta_object_model Meta Ads object model reference
get_metrics_reference Insights metrics reference
get_v26_notes Current Marketing API v26.0 capabilities and migration notes
get_v25_notes Historical Marketing API v25.0 release notes
get_optimization_playbook Optimization best practices playbook
health_check Server health check
get_capabilities List server capabilities
list_mutation_tools List write tools and safety notes
read_overflow_artifact Retrieve one bounded JSON chunk from an oversized response
delete_overflow_artifact Delete an oversized response artifact after retrieval

FastMCP 3.4.7 also exposes dynamic search tools at runtime:

Tool Description
search_tools Search for tools by keyword
call_tool Call a discovered tool by name

These let the LLM discover the right tool on demand instead of loading the full catalog into context up front. call_tool accepts name or the common tool_name alias, and arguments may be a JSON object or an object-valued JSON string. Familiar list_ad_sets, get_ad_set, and delete_ad_set spellings resolve to the canonical adset tool names without duplicating search results. Public string-list parameters, including fields, breakdowns, statuses, countries, scopes, and action types, accept either JSON string lists or comma-separated strings.

Budget and bid inputs use human-readable account-currency units. The server resolves currency from the owning Ad Account, converts values to Meta minor units exactly, and rejects precision the currency cannot represent (for example, fractional JPY). Campaign bidding strategy and Ad Set bid amounts are separate operations because Meta does not expose a campaign-level bid_amount.

📚 MCP Resources

Resource Description
meta://docs/object-model Meta Ads object hierarchy
meta://docs/insights-metrics Available insights metrics
meta://docs/v25-notes v25.0 API release notes
meta://docs/v26-notes Current v26.0 API capabilities and migration notes
meta://docs/optimization-playbook Optimization best practices
meta://docs/tool-routing Tool routing guide

🚀 Quick Start

Prerequisites

  • Python 3.12+
  • uv (recommended) or pipx
  • A Meta access token with the scopes needed for the tools you want to use
  • Social feedback tools also need Page or Instagram permissions, such as pages_read_user_content for Page comments/recommendations and the relevant Instagram comment permissions for IG media comments

1. Get Your Credentials

Set your access token:

export META_ACCESS_TOKEN='YOUR_META_ACCESS_TOKEN'

Optional settings:

export META_DEFAULT_ACCOUNT_ID='act_1234567890'
export META_API_VERSION='v26.0'
export META_APP_ID='YOUR_APP_ID'
export META_APP_SECRET='YOUR_APP_SECRET'
export META_REDIRECT_URI='https://example.com/callback'
export META_EXPORT_DIR='/path/to/meta-ads-exports'
export META_EXPORT_TTL_SECONDS='86400'
export META_EXPORT_MAX_FILES='100'
export META_EXPORT_MAX_BYTES='1000000000'

You can also place these in a .env file at the repo root.

When META_APP_SECRET is set, authenticated Graph API requests using the configured META_ACCESS_TOKEN automatically include Meta's HMAC-SHA256 appsecret_proof. A different token supplied as a request override is left unproved because it may belong to another app. The secret and generated proof are never included in public error payloads.

Marketing API v26 audit

The repository includes an SDK-backed compatibility audit that compares local default field projections with Meta's generated Python Business SDK schemas:

uv run audit-meta-sdk-schema \
  --sdk-repo /path/to/facebook-python-business-sdk \
  --base-ref 25.0.3 \
  --target-ref 26.0.2

The default API is v26.0; the audit target is SDK 26.0.2. These are different version numbers. See the v26 compatibility audit for schema findings and the read-only live validation gate.

With META_API_VERSION=v26.0 or newer, use get_native_optimization_signals for entity-native delivery, learning, issue, automation, and recommendation payloads. get_entity_insights can opt into the v26 instagram_profile_follow metric with include_instagram_profile_follow=true. Both options fail early if an explicit environment override selects v25. Restart the MCP to pick up a version change.

get_recommendations and the five typed opportunity tools accept Meta-native recommendation_names and recommendation_stages filters, as lists or CSV. For example, recommendation_stages=["PCR"] limits Meta's results before any local category filtering. Omitting the filters keeps the existing broad scan. Stage codes (MFR, PCR, PFR) are passed through without invented meanings. Providing either filter requires API v26 or newer and fails before a request under an explicit v25 override; unfiltered recommendation scans remain available.

New SDK fields and breakdowns use existing generic inputs: for example, get_entity_insights(..., fields=["shop_clicks"]) or get_entity_insights(..., breakdowns=["placement_path"]). Campaign reads now also accept custom fields. These examples show input paths, not guaranteed account eligibility or valid combinations. The live v26 account rejects the SDK-listed campaign bid_constraints field, so it is not a default projection. The ad persona field also requires permissions unavailable to the tested token. Use get_v26_notes for the full relevant additions and compatibility caveats.

Overflow settings are optional. Oversized MCP responses are saved as complete, owner-only JSON artifacts and replaced inline by an opaque export_id. Use the visible call_tool proxy with name="read_overflow_artifact" and the returned export_id, repeating with next_offset to retrieve the complete response from local or remote MCP transports. Then use call_tool with name="delete_overflow_artifact". When META_EXPORT_DIR is omitted, the server uses the operating system's temporary meta-ads-mcp-exports directory. The 64 KB threshold applies only to the inline MCP response: Meta's complete result is retained in the artifact and is not truncated or discarded. Archive schema v2 uses compact JSON and stores identical JSON compatibility text only once, under tool_result.structured_content. Distinct or annotated text remains intact. Overflow notices include archive size and retention. Artifacts expire after 24 hours by default, and the store retains at most 100 response artifacts totaling 1 GB of JSON payload data; small private integrity manifests are stored alongside those payloads. The three retention variables above override those defaults. If the host lacks secure directory-relative file operations and process locks, archival fails closed and the tool returns guidance to narrow the request.

Synchronous get_entity_insights (and its get_insights alias) omits duplicate raw action arrays by default, keeping numeric action maps, derived metrics, and requested flatten_actions columns. Custom action counts and values remain available without an extra opt-in. Set include_raw_actions=true to retain raw arrays, including named attribution-window values needed for click/view comparisons; generic maps are not window-specific totals. summarize_actions and JSON/CSV exports retain their existing action output. Existing callers that read raw action arrays must now opt in. Dimensional action_breakdowns (anything beyond action_type, such as action_device) require include_raw_actions=true; read the raw records for those dimensions, not the scalar maps or derived totals. Compact calls fail before making a request instead of discarding the dimensions.

For placement reporting across copies of an ad, use level="ad" with the parent object_id="act_ACCOUNT_ID" (or a campaign/ad set ID), breakdowns=["publisher_platform","platform_position"], and native filtering=[{"field":"ad.name","operator":"CONTAIN","value":"NAME_PREFIX"}]. level already selects row granularity; no separate row_level is needed. Filters also work with exports and async report creation. Synchronous summaries cover the returned page only: check summary.complete and continue with paging.after before treating the result as exhaustive. Alternatively, set fetch_all=true to collect up to 1,000 rows from the first page onward in one call (also supported by get_insights and export_insights). The server combines metrics after pagination, or fails explicitly if the scan cannot finish. Narrow the query or use async reports for larger results.

For an account-wide fatigue sweep, call get_creative_fatigue_report with account_id or level="account", object_id="act_ACCOUNT_ID". It reads both windows at ad granularity, follows pagination, and includes ad/campaign/ad set names. Findings use a transparent ordering: minimum impressions across both windows, CTR decline, frequency increase, current spend, then ad ID. This is a rule-based priority order, not statistical significance. Each window defaults to a 1,000-ad bound; use max_ads=5000 for a larger account (maximum 10,000). Scans beyond the selected bound or unusable pagination fail explicitly; no partial diagnosis is returned. Flagged ads receive current creative IDs via up to 100 extra metadata reads (max_creative_lookups, 0–1,000; zero disables enrichment). Missing IDs, failed reads, rate limits, and the lookup cap remain explicit without discarding findings. An exhausted transient error stops further optional reads for that call; unread identities are marked skipped_transient_error. Exact creative-ID groups cover flagged ads only; current IDs do not prove historical creative identity and are not inferred from names. creative_identity_complete is separate from the complete Insights scan. Confidence remains null/uncalibrated. Medium severity requires at least 20% CTR decline and 20% frequency rise; high requires at least 50% of both. These thresholds are a prioritization policy, not probabilities.

Use list_ads(name_contains_any=["Ada","Grace"], whole_term_match=true, effective_status=["ACTIVE"], fields=["id","name"]) to search several names in one bounded inventory scan. Matching is case-insensitive; whole-term mode treats punctuation and underscores as separators and avoids matching Ada in Adam. Each ad includes matched_terms. The scan follows pagination up to 1,000 ads and fails explicitly if it cannot finish; completeness still reflects the selected scope and status filters, not all historical ads.

get_ad_image joins asset labels to configured_image_rules, retaining crop coordinates, explicit default flags, rule constraints, and unresolved labels. It includes reporting-position hints (Instagram stream becomes feed; unknown values pass through). These are configured eligibility rules, not proof that a specific image served. Placement Insights show delivery totals, but do not establish image-level delivery when several assets are eligible. Pass ad_ids=["AD_1","AD_2"] instead of ad_id for a collection of up to 100 distinct ads. Creative reads and image-hash lookups are reused within that call, with image caching scoped to the owning account. Unresolved image hashes remain explicit. This uses the existing per-object Graph reads, not a new batch job or persistent cache.

For an analysis-only server, set META_READ_ONLY=true in its launch environment and restart it. This opt-in mode hides mutation tools from search and rejects advertising mutations, asset uploads, A/B-test setup, and token mutations before execution—even through call_tool or compatibility aliases. Unknown tools fail closed. Reporting jobs and local overflow-artifact cleanup remain available. Use an ads_read token as an additional permission boundary where possible. Analysis agents using tool search need access to search_tools, call_tool, and get_capabilities; allowing only underlying tool names is not sufficient. The default remains writable; no existing server or dbt agent configuration is changed automatically.

For click/view attribution comparisons, use get_entity_insights with explicit dates, fields=["actions","action_values"], use_unified_attribution_setting=false, action_attribution_windows=["7d_click","1d_view"], and include_raw_actions=true. Read the named window keys from the raw purchase action entries. Meta's generic value can differ from them even for a single requested window; core metrics, action maps, and flatten_actions use that generic value, not window-specific totals. Do not assume the window values or overlapping action aliases are additive. Historical ad set setting changes still require retained activity or warehouse history.

Async insights use a lean scalar field set by default; pass field_preset="full" or explicit fields when the wider Meta response is required. Pass flatten_actions=["purchase","purchase_value"] when creating and retrieving a report to request only the required action dependencies and promote those values into scalar row columns. Async retrieval omits verbose action arrays and maps unless include_raw_actions=true, while preserving requested scalar fields such as spend, impressions, and clicks. Use wait=true for a bounded server-side poll, or inspect the returned job.ready, job.terminal, and job.poll_after_seconds fields yourself.

Graph API failures are returned as allowlisted structured error JSON with Meta codes, subcodes, user guidance, retry timing, and usage diagnostics when available. Reads may retry transient failures; create, update, and delete calls are not automatically retried after ambiguous failures. If mutation_outcome_unknown=true, retryable is false and callers must verify current object state before deciding whether to retry.

META_DEFAULT_ACCOUNT_ID is an optional convenience, not a requirement for object-scoped activity history. When a campaign, ad set, or ad ID is supplied, the server looks up its owning account and validates any explicit or default account against that ownership.

Don't have a token? Use the built-in auth helper tools (generate_auth_url → exchange_code_for_token → refresh_to_long_lived_token) to create one interactively.

2. Install & Run

Option A: Claude Code (recommended)

# Install from repo
claude mcp add --transport stdio MetaAds \
  --env META_ACCESS_TOKEN=YOUR_META_ACCESS_TOKEN \
  --env META_DEFAULT_ACCOUNT_ID=act_1234567890 \
  -- pipx run --spec git+https://github.com/jeffreywlai/meta-ads-mcp.git run-meta-ads-mcp

Or from a local clone:

claude mcp add --transport stdio MetaAds \
  --env META_ACCESS_TOKEN=YOUR_META_ACCESS_TOKEN \
  --env META_DEFAULT_ACCOUNT_ID=act_1234567890 \
  -- uv run --directory /path/to/meta-ads-mcp -m meta_ads_mcp.stdio

Type /mcp in Claude Code to verify the server is connected.

Option B: Gemini CLI

Add to your Gemini MCP configuration:

{
  "mcpServers": {
    "MetaAds": {
      "command": "pipx",
      "args": [
        "run", "--spec",
        "git+https://github.com/jeffreywlai/meta-ads-mcp.git",
        "run-meta-ads-mcp"
      ],
      "env": {
        "META_ACCESS_TOKEN": "YOUR_META_ACCESS_TOKEN",
        "META_DEFAULT_ACCOUNT_ID": "act_1234567890"
      },
      "timeout": 30000
    }
  }
}

Option C: Direct Launch

uv sync
uv run -m meta_ads_mcp.stdio

For HTTP mode:

uv run -m meta_ads_mcp.server

💬 Usage Examples

Once connected, just talk naturally:

Discovery

"List my accessible ad accounts"
"Show me the campaigns in act_1234567890"
"What Instagram accounts are linked to this ad account?"
"Find the Pages I can use for creative setup"

Reporting & Analysis

"Show me account-level insights for the last 7 days"
"Compare these two campaigns on ROAS, CPA, and CTR"
"Break down campaign performance by country"
"Export ad-level insights for the last 30 days as CSV"
"Create async reports for country and device breakdowns, then wait for each result"
"Return purchase and purchase_value as flat columns without raw action arrays"

Optimization

"Give me an optimization snapshot for this account"
"Which creatives are fatiguing in this campaign?"
"What are the biggest delivery risks right now?"
"Which audience segments are underperforming?"

Planning & Research

"Estimate audience size for this targeting spec"
"Find interest suggestions related to running and fitness"
"Search demographic targeting categories for new parents"
"Search the Meta ads archive for competitor creatives"

Writes

"Create a paused campaign for this account"
"Pause this campaign"
"Update this ad set budget to 75 dollars daily"
"Validate a target-ROAS ad set with a 30000 ROAS floor without creating it"
"Create an ad in this ad set using creative 123"

🏗️ Project Structure

meta-ads-mcp/
├── meta_ads_mcp/
│   ├── coordinator.py         # Shared FastMCP instance & tool search config
│   ├── stdio.py               # Server entry point (Claude Code / stdio)
│   ├── server.py              # Server entry point (Gemini / SSE)
│   ├── config.py              # Configuration and env loading
│   ├── auth.py                # Auth utilities
│   ├── diagnostics.py         # Derived metrics & optimization heuristics
│   ├── errors.py              # Error handling
│   ├── graph_api.py           # Meta Graph API client
│   ├── money.py               # Account-currency resolution & exact conversion
│   ├── normalize.py           # Response normalization
│   ├── pagination.py          # Graph API pagination helpers
│   ├── schemas.py             # Pydantic schemas
│   ├── tools/
│   │   ├── ads.py             # Ad management
│   │   ├── activity.py        # Activity and change-history reads
│   │   ├── audiences.py       # Audience management
│   │   ├── auth_tools.py      # Auth helper tools
│   │   ├── campaigns.py       # Campaign & ad set management
│   │   ├── creatives.py       # Creative management
│   │   ├── diagnostics.py     # Optimization & diagnostics
│   │   ├── discovery.py       # Account & entity discovery
│   │   ├── docs.py            # Built-in documentation tools
│   │   ├── execution.py       # Write operations
│   │   ├── insights.py        # Reporting & analysis
│   │   ├── recommendations.py # AI recommendations
│   │   ├── research.py        # Ad Library research
│   │   ├── social_feedback.py # Comments & Page recommendations
│   │   ├── targeting.py       # Targeting & planning
│   │   └── utility.py         # Health check & capabilities
│   └── context/               # Embedded docs & playbooks
├── tests/                     # Mirrors source structure
├── CLAUDE.md
├── GEMINI.md
├── SPEC.md
├── pyproject.toml
└── README.md

🛠️ Development

uv sync --extra dev              # Install runtime and test dependencies
uv run --extra dev pytest        # Run tests

Project Notes

  • Keep Graph API calls isolated in meta_ads_mcp/graph_api.py
  • Prefer optimization and diagnostics tools before mutations
  • Return dicts and lists rather than serialized JSON strings
  • Treat all account IDs and object IDs as strings
  • Keep the implementation aligned with Marketing API v26.0

📄 License

Licensed under the MIT License.

📬 Contact

Questions, suggestions, or feedback? Open an issue.


Built with FastMCP 3.4.7 and Meta Marketing API v26.0