creative-tagger-mcp
Creative Tagger MCP server lets AI agents classify ad creatives, manage brand taxonomy and memory, and run performance/strategy analyses via MCP tools.
Analyze images, videos, carousels, landing pages, and emails across 21 creative dimensions; auto-save results and generate naming.
Retrieve taxonomy v2 and customize brand-specific values, aliases, and entities (founders, products, offers, segments, etc.).
Browse, search, and inspect the saved analysis library; surface cross-library patterns and concentration gaps.
Store and retrieve per-brand context (voice, audience, top performers, anti-patterns, notes) for grounded strategist help.
Ask the Creative Strategist for recommendations or gap-analysis briefs.
Manage naming variables/templates: list, save, preview, delete, and generate naming strings.
Check/sync read-only Meta performance and read performance summaries, tag-level performance, and taxonomy coverage.
Build strategy reports, prebuilt reports, custom reports, saved custom reports, leaderboards, batch readouts, and period comparisons.
Predict creative performance observationally (not causal) and form controlled-test hypotheses.
Read/export Brand Brain learnings and performance time-series fatigue/trajectory context.
Read demographics performance and export audience context.
Generate brand taxonomy from the analyzed creative library.
Scan competitors' Meta Ad Library, view saved scan history, and inspect scan details.
Generate V1-compatible naming conventions from classified attributes.
Integrates with Meta's advertising platform to sync read-only performance memory (spend, impressions, video metrics, etc.), scan competitor ads from the Meta Ad Library, and import Meta ad performance data via MCP, enabling AI agents to analyze winners, demographic opportunities, and taxonomy gaps.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@creative-tagger-mcp analyze the ad creative at ./new_ad.mp4 for Acme brand"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Creative Tagger MCP Server
The MCP layer for Creative Tagger — plug structured creative intelligence into any AI agent (Claude Desktop, Cursor, Windsurf, ChatGPT with MCP, etc.).
Release note (2026-08-30): this source tree and its packaged metadata are
version 0.2.5. The hosted and stdio surfaces are separate clients of the same
API and may expose different tool counts. The companion API must be deployed
and live before this stdio release is tagged and published.
Your AI of choice gets:
Taxonomy — 21 standardized dimensions for any ad creative (video, image, carousel, landing page, long video, email)
Memory — every analysis is saved to the user's library; the agent can search it, recall patterns, and pull individual results
Brand-custom taxonomy — extend the standard taxonomy with each brand's founders, products, segments, aliases, and naming variables
Meta performance memory — read-only Meta sync/status/tools so agents can reason over objective-aware results, unproven tags, observational demographic delivery, and taxonomy gaps
Brain learnings — auto-written account learnings in plain language, with agent-ready context for the next brief
Strategist — recommendation + gap-analysis tools that reason over the user's library plus saved brand context (voice, audience, anti-patterns)
Competitive intelligence — scan a competitor's Meta Ad Library through Creative Tagger's native Market access
Quick Start
The hosted server speaks standard MCP OAuth (dynamic client registration,
PKCE) at https://api.creativetagger.ai/mcp/. Point your client at that URL
and sign in when prompted:
Claude Code —
claude mcp add --transport http creative-tagger https://api.creativetagger.ai/mcp/thenclaude mcp login creative-tagger(or run/mcpinside a session).Codex CLI / IDE —
codex mcp add creative-tagger --url https://api.creativetagger.ai/mcp/thencodex mcp login creative-tagger.claude.ai (web/desktop/mobile) — Settings → Connectors → Add custom connector → paste
https://api.creativetagger.ai/mcp/→ Connect.ChatGPT — Settings → Connectors → Advanced → Developer mode → add
https://api.creativetagger.ai/mcp/.Other MCP clients (Cursor, VS Code, Gemini CLI, Windsurf, Hermes, etc.) — add the URL to the client's MCP config; the client's own OAuth prompt fires on first use.
Manage or revoke connected assistants any time under Settings → Connections.
For clients that don't do OAuth discovery (e.g. Grok's custom-connector integration), fall back to a bearer API key:
URL: https://api.creativetagger.ai/mcp/
Authorization: Bearer ct_your_keyThe repository package is the stdio path for clients that require a local
command. 0.2.5 is unreleased; install 0.2.4, the latest version on PyPI.
Tools and options listed under 0.2.5 in CHANGELOG.md are not in
0.2.4:
# Install the latest published release (0.2.5 is not on PyPI yet)
pip install creative-tagger-mcp==0.2.4
# Run against production (default)
CREATIVE_TAGGER_API_KEY=ct_your_key creative-tagger-mcp
# Or against a local API
CREATIVE_TAGGER_URL=http://localhost:8000 \
CREATIVE_TAGGER_API_KEY=ct_your_key \
creative-tagger-mcpGet an API key at app.creativetagger.ai.
Related MCP server: muze-mcp
Release Verification
Before publishing a new MCP version, build the artifacts and smoke-test the wheel that will be uploaded to PyPI:
python -m build
python scripts/smoke_release.py
python -m twine check \
dist/creative_tagger_mcp-0.2.5-py3-none-any.whl \
dist/creative_tagger_mcp-0.2.5.tar.gzThe smoke test installs the wheel into a temporary virtualenv, verifies the
creative-tagger-mcp console entry point, checks the package version, and
confirms the V1 tool surface is present from the installed artifact.
Publishing to PyPI
The release workflow publishes from GitHub Actions after it builds the package,
runs scripts/smoke_release.py, and passes twine check.
After the 0.2.5 review and API-dependency gates pass, tag the exact current
main commit:
git tag -a v0.2.5 -m "Creative Tagger MCP v0.2.5"
git push origin refs/tags/v0.2.5The workflow supports PyPI trusted publishing with GitHub OIDC. Configure the
PyPI publisher for repository stephenlavender/creative-tagger-mcp, workflow
.github/workflows/publish.yml, environment pypi, then push the version tag.
Exact PyPI trusted publisher values:
PyPI project:
creative-tagger-mcpPublisher: GitHub
Owner:
stephenlavenderRepository:
creative-tagger-mcpWorkflow filename:
publish.ymlEnvironment name:
pypi
If the workflow fails with invalid-publisher, PyPI does not have a trusted
publisher matching those claims yet. Add the publisher above, then rerun the
failed workflow or push the version tag again.
Fallback path: add a GitHub Actions repository secret named PYPI_API_TOKEN
containing a PyPI project token. The same workflow will use that token when it
is present.
Local fallback:
python -m build
python scripts/smoke_release.py
python -m twine check \
dist/creative_tagger_mcp-0.2.5-py3-none-any.whl \
dist/creative_tagger_mcp-0.2.5.tar.gz
python -m twine upload \
dist/creative_tagger_mcp-0.2.5-py3-none-any.whl \
dist/creative_tagger_mcp-0.2.5.tar.gzAlways select the exact release artifacts for a local upload. A reused checkout
may contain older valid distributions in dist/; never publish with
twine upload dist/*.
Add to Claude Desktop
~/Library/Application Support/Claude/claude_desktop_config.json:
{
"mcpServers": {
"creative-tagger": {
"command": "creative-tagger-mcp",
"env": {
"CREATIVE_TAGGER_URL": "https://api.creativetagger.ai",
"CREATIVE_TAGGER_API_KEY": "ct_your_key_here"
}
}
}
}Restart Claude Desktop. The tools appear in the MCP picker.
Tools
analyze_creative
Analyze any ad creative and get structured classification across 21 dimensions.
{ "file_path": "./ad.mp4", "brand_name": "Brand" }
{ "url": "https://example.com/landing-page", "brand_name": "Brand" }
{ "html_content": "<html>...</html>", "brand_name": "Brand" }Results auto-save to the user's library.
get_taxonomy
Read taxonomy v2's versioned vocabulary or one dimension. The package returns
15 controlled dimensions, one derived/open aspect_ratio dimension, and two
intentionally dynamic, brand-specific dimensions. Aspect ratio includes common
canonical examples but sets allow_other_values: true: the API may derive any
reduced WxH ratio (such as 3x2 or 300x157) or preserve a W:H ratio for
long video. The package does not infer enums from OpenAPI: several valid
classification fields are strings in that schema, so schema discovery would
silently return an incomplete taxonomy.
{} # all controlled + derived/open + dynamic dimensions
{ "dimension": "hook_type" } # one dimension
{ "dimension": "aspect_ratio" } # examples; other derived values remain validTaxonomy v2 splits three dimensions the old model mixed together: media type
(the auto-detected format — static image, video, carousel; never AI-classified),
asset type (production class: UGC, Studio, High Production, …), and
visual format (execution style: Talking Head, Demo, Testimonial, …).
Static Image and Carousel are media types and are no longer valid
visual_format values. messaging_angle is the canonical angle dimension.
list_workspaces
List the authenticated user's available workspaces. Start every connected
account workflow here, select one returned brand_name, and pass that exact
value to every library, Meta status, report, and strategist call. Do not blend
observations across workspaces unless the user explicitly requests a comparison.
{}list_library
Browse saved analyses. Search by filename or hook, filter by format, messaging
angle, emotion, CTA, talent, offer, audio type, or seasonality, and sort by
joined performance. limit is clamped to 1–100 and offset to zero or higher
before the request leaves the local stdio server.
{
"brand_name": "Acme",
"limit": 50,
"search": "BFCM",
"format": "video",
"angle": "Social Proof",
"talent": "Founder",
"sort": "roas"
}get_library_patterns
Cross-library pattern insights — concentration and diversity per dimension, plus rule-based diversification flags.
Pass the exact workspace brand_name returned by list_workspaces.
get_analysis
Pull the full 21-dimension result for one library item.
{ "brand_name": "Acme", "analysis_id": 42 }recommend ⭐
Ask the Creative Strategist a question grounded in the user's library + brand context.
{ "brand_name": "Acme", "question": "What kind of UGC should I test for Q4?" }Returns concrete recommendations using taxonomy values + library observations.
analyze_gaps ⭐
Identify concentration risk in the library and propose next creatives that diversify it.
{ "brand_name": "Acme" }get_brand_context / set_brand_context
Long-term memory per brand. Voice, target audience, top performers, anti-patterns, notes.
set_brand_context is a partial update: omitted fields stay unchanged, while an
explicit empty string or list clears only that field.
set_brand_context: {
"brand_name": "Acme",
"voice": "clinical, precise, no personality",
"target_audience": "new moms 28-40, postpartum recovery",
"top_performers": ["UGC TalkHead", "BeforeAfter visuals"],
"anti_patterns": ["loud humor", "celebrity endorsement"],
"notes": "Q4 focus: gift-shoppers + retention"
}Strategist tools auto-include this context.
get_brand_taxonomy / set_brand_taxonomy_value / delete_brand_taxonomy_value / set_brand_entity / delete_brand_entity
Customize the standard taxonomy for one brand without breaking cross-brand reporting.
set_brand_taxonomy_value: {
"brand_name": "Acme",
"dimension": "talent",
"value": "Stephen Lavender / Founder",
"aliases": ["Stephen", "founder"],
"description": "Use when Stephen appears or is referenced"
}
set_brand_entity: {
"brand_name": "Acme",
"entity_type": "product",
"name": "Creative Tagger",
"aliases": ["CT", "tagger"]
}
delete_brand_taxonomy_value: {
"brand_name": "Acme",
"dimension": "talent",
"value": "Old Founder Label"
}
delete_brand_entity: {
"brand_name": "Acme",
"entity_type": "product",
"name": "Retired Product"
}get_naming_variables / list_naming_templates / save_naming_template
Manage saved naming templates from your agent. Templates support standard taxonomy
fields plus brand-custom variables like founder, product, offer, customer_segment,
icp, and campaign_label. Saved templates auto-apply to future analyze_creative
results.
save_naming_template: {
"name": "default",
"template": "{brand}_{founder}_{customer_segment}_{hook_type}_{cta}_{ratio}_{version}"
}Use preview_naming_template to test a template before saving, and
delete_naming_template to remove one.
get_meta_status / sync_meta_performance
Check or trigger read-only Meta performance memory. No campaign creation, no budget edits.
Creative Tagger must have an approved native Meta OAuth connection before
customer accounts can sync Meta performance.
Pass attribution_windows when the buyer uses a non-default Meta lookback
window and Creative Tagger should match Ads Manager exactly.
{
"brand_name": "Acme",
"date_preset": "last_30d",
"attribution_windows": ["7d_click", "1d_view"]
}get_creative_strategy_report
Pull the same strategy matrix shown in Creative Tagger Reports. Defaults to
visual formats by messaging angles, with states for next tests, live learning,
winners, losers, fatigue, and gaps. Returns the decision queue and a bounded
matrix slice for agent strategy work. Detailed responses also include an
agent_context payload that can be handed directly to an LLM.
Supports creative-diagnostics metrics such as CTR, thumbstop, hook, hold, video
milestone rates, CPA, CVR, ROAS, revenue, spend, and funnel score. For
audience-mode reads, switch the axes to demographic dimensions such as
demographic_age and demographic_gender, or use the demographic-read or
audience-signals templates. Other built-in templates include
creative-winners, fatigue-watch, coverage-gaps, hook-performance, and
persona-read. Creative axes follow taxonomy v2: visual_format (execution
style), asset_type (production class), and media_type (auto-detected
format) are three separate dimensions, with ad_type kept as a deprecated
alias for visual_format. Demographics are account-level only, with no
per-ad key: pairing a creative tag axis with a demographic axis is
structurally not_applicable and returns an explicit cross_contract
instead of a populated grid. Audience-mode matrices need BOTH axes to be
demographic instead — e.g. demographic_age by demographic_gender (the
demographic-read template), or demographic_segment by
demographic_signal (the audience-signals template). Add
fatigue_minimum_calendar_days when fatigue should only count after a long
enough live window, not just after a few close-together synced points. For
fatigue-aware reads, pass the same embedded watch controls the app/API support:
watch_group_by, watch_metric, watch_signal_focus,
watch_trajectory_focus, watch_coverage_focus, watch_minimum_points,
watch_minimum_calendar_days, watch_maximum_gap_days, and watch_limit.
The decision-queue limit is clamped to 1–25, while watch_limit is clamped
to 1–10, before the API request.
Responses default to response_format: "concise" with at most 24 matrix cells
to keep the result bounded. Set response_format: "detailed" explicitly for
the richer report fields, including agent_context. Both formats respect
max_cells; raise it (up to 200) when a larger matrix slice is needed.
{
"brand_name": "Acme",
"report_template": "next-tests",
"rows": "visual_format",
"columns": "messaging_angle",
"metrics": "spend,ctr,thumbstop_rate,hook_rate,hold_rate,cpa",
"response_format": "concise",
"max_cells": 24
}{
"brand_name": "Acme",
"report_template": "demographic-read",
"rows": "demographic_age",
"columns": "demographic_gender",
"metrics": "spend,roas,ctr,cpa,conversions,revenue",
"roas_target": 2.5,
"fatigue_minimum_calendar_days": 7,
"watch_group_by": "hook_type",
"watch_metric": "cpa",
"watch_signal_focus": "fatigued",
"watch_trajectory_focus": "worsening",
"watch_coverage_focus": "windowed_history",
"watch_minimum_points": 2,
"watch_minimum_calendar_days": 7,
"watch_maximum_gap_days": 7,
"watch_limit": 5,
"start_date": "2026-05-01",
"end_date": "2026-05-31"
}{
"brand_name": "Acme",
"report_template": "audience-signals",
"rows": "demographic_signal",
"columns": "demographic_segment",
"metrics": "spend,roas,ctr,cpa,conversions,revenue",
"date_preset": "last_30_days"
}{
"brand_name": "Acme",
"report_template": "hook-performance",
"rows": "hook",
"columns": "ad_type",
"metrics": "spend,hook_rate,hold_rate,roas,ctr,cpa",
"fatigue_minimum_calendar_days": 7,
"date_preset": "last_30_days"
}get_brain_learnings
Read the auto-written Brand Brain learnings generated from performance memory,
strategy cells, taxonomy winners/watchouts, and audience signals. Returns a
hero learning, concise stories, and an agent_context payload for the next
brief or strategist prompt. Use kinds when an agent only wants a focused slice
such as conclusion, working,audience, or watch. Add
conclusion_statuses to narrow conclusion stories to winner, fatigued, or
loser outcomes only, and conclusion_recency_days to keep only the most
recent conclusion window. Use watch_group_by, watch_metric,
watch_signal_focus, watch_trajectory_focus, watch_coverage_focus,
watch_minimum_points, watch_minimum_calendar_days, watch_sources, and
fatigue_decay_threshold when the watchouts should be written from a different
fatigue lens such as fatigued-only CPA by ad type, weak taxonomy patterns only,
CTR by hook, or stable ROAS by demographic_segment.
When kinds includes audience, audience_signal_focus accepts the canonical
values all, higher_observed_efficiency, or
lower_observed_efficiency. The same vocabulary applies to get, save, and
export operations. Across all three operations, story limit is clamped to
1–12 and audience_limit is clamped to 1–10 before the API request.
{
"brand_name": "Acme",
"date_preset": "last_30_days",
"minimum_spend": 500,
"learning_spend": 1500,
"kinds": "conclusion,watch,audience",
"audience_signal_focus": "higher_observed_efficiency",
"conclusion_statuses": "winner,fatigued",
"conclusion_recency_days": 21,
"watch_group_by": "ad_type",
"watch_metric": "cpa",
"watch_signal_focus": "fatigued",
"watch_trajectory_focus": "worsening",
"watch_coverage_focus": "windowed_history",
"watch_minimum_points": 3,
"watch_minimum_calendar_days": 7,
"watch_sources": "timeseries,patterns",
"fatigue_decay_threshold": 0.25,
"limit": 6
}save_brain_learnings
Persist the current auto-written Brand Brain learnings into saved Brain notes
for a brand, using the same filtering controls as get_brain_learnings. Use
this after reviewing a conclusion/working/watch/audience/gap slice when the
user wants the best current learnings saved back into reusable strategist context.
{
"brand_name": "Acme",
"date_preset": "last_30_days",
"minimum_spend": 500,
"learning_spend": 1500,
"kinds": "conclusion,watch,audience",
"audience_signal_focus": "lower_observed_efficiency",
"conclusion_statuses": "winner,fatigued",
"conclusion_recency_days": 21,
"watch_group_by": "ad_type",
"watch_metric": "cpa",
"watch_signal_focus": "fatigued",
"watch_trajectory_focus": "worsening",
"watch_coverage_focus": "windowed_history",
"watch_minimum_points": 3,
"watch_minimum_calendar_days": 7,
"watch_sources": "timeseries,patterns",
"include_gaps_in_notes": false,
"limit": 6
}export_brain_learnings_context
Export the bounded agent_context from get_brain_learnings, including its
filtered learning stories and follow-up Strategy/time-series queries. It uses
the same controls and canonical audience_signal_focus values as the get and
save tools.
{
"brand_name": "Acme",
"kinds": "audience",
"audience_signal_focus": "higher_observed_efficiency",
"limit": 6
}get_performance_timeseries
Read saved performance curves for fatigue checks without opening the dashboard.
Returns dated points plus a fatigue signal for each grouped series, using the
same decay threshold as Creative Tagger's strategy matrix. Group by creative,
campaign, landing page, analysis_id, or audience slices like
demographic_age, demographic_gender, demographic_segment, and
demographic_signal, and inspect metrics like ROAS, CPA, CTR, CPM, thumbstop,
completion rate, or funnel score. Use signal_focus when an agent only wants
the current fatigue watchlist or only stable controls, and trajectory_focus
when the agent wants only worsening, improving, flat, or insufficient-data
series. Use coverage_focus to isolate call-ready, gappy, short-window, or
windowed-history curves. Add minimum_calendar_days when fatigue should only
count after a trend has been live long enough, not just after a few
close-together points. Both this tool and its context export clamp limit to
1–10 grouped series locally.
{
"brand_name": "Acme",
"date_preset": "last_30d",
"group_by": "ad_name",
"metric": "roas",
"signal_focus": "fatigued",
"trajectory_focus": "worsening",
"coverage_focus": "call_ready",
"minimum_spend": 500,
"minimum_points": 3,
"minimum_calendar_days": 7,
"fatigue_decay_threshold": 0.18,
"limit": 5
}Use date_preset for a standard lookback window, or pass explicit
start_date / end_date to override it.
export_performance_timeseries_context
Return the reusable agent_context payload from performance time series. Use
this when another agent needs the fatigue decision queue, summary text, action
mix, top groups, and prompt-ready export without carrying the full chart payload.
It accepts the same inputs as get_performance_timeseries.
{
"brand_name": "Acme",
"date_preset": "last_30d",
"group_by": "ad_name",
"metric": "roas",
"signal_focus": "fatigued",
"trajectory_focus": "worsening",
"coverage_focus": "call_ready",
"minimum_spend": 500,
"minimum_points": 3,
"minimum_calendar_days": 7,
"fatigue_decay_threshold": 0.18,
"limit": 5
}Internal migration/backfill tools are hidden from the default published MCP
surface. They require CREATIVE_TAGGER_INTERNAL_BACKFILL_TOOLS=1 and should not
be used in customer flows or to avoid Meta approval.
get_meta_performance_summary
Read saved Meta performance memory without triggering a sync.
{ "brand_name": "Acme" }Returns account totals plus performance by standard taxonomy and brand-custom taxonomy.
Each aggregate can include funnel_score and a funnel explanation object for
capture -> hold -> bring-to-site -> convert diagnosis.
get_taxonomy_performance
Find historical tag associations, under-observed tags, and standard taxonomy values that have not been tested. Rows include ROAS, CTR, thumbstop, and funnel scores when performance memory exists. These are observational comparisons; validate a promising tag with a one-variable controlled test.
{ "brand_name": "Acme", "dimension": "hook_type", "spend_threshold": 500 }get_prebuilt_reports
Return ready-made Motion-style reports: best hooks, landing pages, messaging angles,
audiences, offers, CTAs, visual formats, and brand-custom values. Add
start_date / end_date when the report should only cover a specific synced
window. limit is clamped to 1–50 rows per report before the API request.
{ "brand_name": "Acme", "report_id": "best_hooks", "limit": 8 }
{ "brand_name": "Acme", "report_id": "best_angles", "start_date": "2026-05-01", "end_date": "2026-05-31", "limit": 8 }create_custom_report
Build a custom report from selected standard or brand taxonomy dimensions and
rank the actual matched dimension combinations by ROAS, funnel score, spend,
CTR, or CPA. Use this for Motion-style views like best hook x landing page x
offer, founder x hook, audience x offer, or brand segment x product. Add
start_date and end_date when the report should isolate a specific test
window instead of the full synced history. limit is clamped to 1–50 rows
before the API request.
attribution accepts blended, 7d_click, 1d_view, or incremental.
Omitting it and passing blended return the byte-identical legacy response.
The selected basis recomputes only conversion-derived metrics (conversions,
revenue, CPA, ROAS, and CVR); delivery, rate, and video metrics stay
unchanged. Incremental results are labelled modelled, and an unmeasured
conversion value is never turned into zero.
{
"brand_name": "Acme",
"dimensions": ["hook_type", "landing_page", "offer_type"],
"layer": "all",
"metric": "roas",
"attribution": "7d_click",
"start_date": "2026-05-01",
"end_date": "2026-05-31"
}Rows can include parts and values, so the agent can explain a winning
combination instead of treating each tag independently.
Saved custom reports
Save reusable report definitions, list them for a brand, rerun them by id, or
delete them when they are no longer needed. Saved reports can also persist a
custom start_date / end_date window for a specific launch or test period,
plus dashboard-style preset state such as view_type, date_range,
group_by, metrics, filters, sort, and saved_metric_preset.
Current chart view types are table, bar, line, and pie.
save_custom_report clamps limit to 1–50 rows before the API request.
The API accepts attribution on a save request but does not persist it;
run_saved_custom_report always replays blended attribution.
{
"brand_name": "Acme",
"name": "Hook + LP + Offer",
"dimensions": ["hook_type", "landing_page", "offer_type"],
"view_type": "table",
"date_range": "custom",
"group_by": "dimension",
"metrics": ["spend", "roas", "cpa", "ctr"],
"filters": [{"field": "status", "value": "winner"}],
"sort": "desc",
"saved_metric_preset": "delivery",
"start_date": "2026-05-01",
"end_date": "2026-05-31"
}
{ "brand_name": "Acme" }
{ "report_id": 7 }Tools: save_custom_report, list_custom_reports, run_saved_custom_report,
delete_custom_report.
get_creative_leaderboard
One ranked list answering "which creatives should I scale or kill." One row per creative for the
window (default last_14_days), ranked by rank_by (roas | cpa | spend | ctr |
thumbstop, default roas), each with thumbnail/media, spend, spend_share, measurement
states, days_running, and a first/second-half trend_direction. A creative below min_spend
(default 500, the shared materiality floor) is flagged below_min_spend, excluded from the
ranks, and never crowned a winner on thin spend — but still returned and counted. direction
(winners | losers | all) slices the ranked half. When the workspace's performance evidence
is not decision-safe (stale sync, no Meta connection), rankings_withheld is true and every
row drops to observation-only with no rank. launched_after / launched_before (YYYY-MM-DD)
scope the ranked population to creatives first synced in that window; limit is clamped to 1–50.
{ "brand_name": "Acme", "window": "last_14_days", "rank_by": "roas", "direction": "winners", "min_spend": 500, "limit": 20 }get_batch_readout
Grades a launch cohort against the rest of the account. Given a launch window (launched_after /
launched_before, YYYY-MM-DD — at least one required), every creative first synced in that
window gets a three-way verdict — promising, underperforming, or insufficient_evidence —
against a same-window baseline built from every other creative (the baseline excludes the
batch, so a new cohort is judged like-for-like, never against its own numbers). verdict_counts
totals the three buckets. insufficient_evidence always carries a verdict_reason: most often
below_min_spend (expected for roughly half of most batches — that honesty is the point), or
metric_not_applicable when the creative's objective/format does not track rank_by (e.g.
roas on a leads creative), in which case it is also excluded from the baseline. rank_by is
roas | cpa | ctr | thumbstop. Verdicts are withheld when evidence is not decision-safe;
limit is clamped to 1–50.
{ "brand_name": "Acme", "launched_after": "2026-06-01", "launched_before": "2026-06-14", "window": "last_30_days", "rank_by": "roas" }compare_periods
Period-over-period: "is it the ads, the auction, or the site?" Compares period_a (baseline) to
period_b (the "after" window); each period is either a preset (this_week, last_week,
last_7_days, last_14_days, last_30_days, last_90_days, this_month, last_month) or an
explicit period_X_start / period_X_end (YYYY-MM-DD) pair — never both, and the two windows
must not overlap. Returns account-level deltas (spend, revenue, ROAS, CPA, CPM, CTR, thumbstop,
click-to-purchase rate, AOV) with measurement states honored, plus a multiplicative funnel
decomposition whose dominant_factor names why a ROAS/CPA change happened — auction (CPM),
creative_engagement (CTR), landing_conversion (CVR), order_value (AOV), or mixed. When
revenue reported a measured $0 in a period, the decomposition falls back to CPA and returns a
non-null revenue_caution — trust it when present: the revenue collapse itself is the likely
explanation, not the delivery reading. Optional group_by (creative or a taxonomy dimension)
adds per-value deltas and biggest_movers; limit is clamped to 1–25.
{
"brand_name": "Acme",
"period_a_preset": "last_week",
"period_b_preset": "this_week",
"metric": "roas",
"group_by": "hook_type"
}predict_creative
Despite the legacy tool name, this is not a forecast. It compares a saved
analysis or draft attributes with the brand's historical tag-level performance
and returns an explicit observational association score and controlled-test
hypotheses—never a forecast, lift estimate, or causal recommendation. Turn a
promising association into a falsifiable, one-variable controlled test with a
predeclared primary metric, minimum data, guardrails, and ship/stop criteria.
Since 0.2.3 the package sends the required predict_observational.v2 request
handshake and rejects legacy or mixed response shapes instead of decorating
them. A contract mismatch returns no prediction evidence.
{
"brand_name": "Acme",
"attributes": { "hook_type": "Question", "cta": "Shop Now" },
"objective_metric": "cpa",
"goal_direction": "lower_better"
}get_demographics_performance
Read age x gender delivery with account-relative higher and lower observed-
return-per-spend bands. These bands are descriptive associations, not audience
outcome or action verdicts. Use date_preset for a standard audience window,
or start_date / end_date to isolate a specific audience window.
{
"brand_name": "Acme",
"date_preset": "last_30_days",
"start_date": "2026-05-01",
"end_date": "2026-05-31"
}export_demographics_context
Return an agent-ready audience context payload from the saved demographics read.
Use this when another agent needs higher and lower observed-efficiency bands,
raw totals, per-segment account-wide tag reads and trend views, and a
prompt-ready descriptive summary without the full wrapper. Demographics are
account-level only, with no per-ad key — every follow-up query stays a
separate demographic-only or tag-only read, never a joined tag x demographic
cross. Outcome direction stays withheld until an objective metric and
direction are predeclared. limit is clamped to 1–100 segments per
observed-efficiency band.
{
"brand_name": "Acme",
"date_preset": "last_30_days",
"limit": 3
}generate_brand_taxonomy
Generate brand-specific messaging themes and intended audiences from the analyzed creative library, then optionally save them to Brand Taxonomy Studio.
{ "brand_name": "Acme", "persist": true }scan_competitor
Classify a competitor's Meta Ad Library ads and get strategy breakdown.
limit is clamped to 1–50 ads before the API request.
{ "brand_name": "Acme", "page_name": "Hims & Hers", "limit": 25 }Internal competitor-row backfill is also hidden from the default published MCP
surface. Customer-facing competitor intelligence should use scan_competitor
after native Meta Ad Library access is approved.
get_competitor_scan_history
Read the saved Market scans/imports for a workspace without re-running Meta Ad
Library access. Useful when the agent needs the latest saved competitor hooks,
styles, or scan metadata before drafting briefs. limit is clamped to 1–50
saved scans before the API request.
{ "brand_name": "Acme", "limit": 6 }get_competitor_scan_detail
Read one saved competitor scan/import in full, including the stored ads,
per-ad analyses, original query, and aggregate strategy breakdown. Use the
scan_id returned by get_competitor_scan_history to reopen a specific past
market read for grounded follow-up briefing without re-running Meta Ad Library
access.
{ "scan_id": 42 }generate_naming
Build naming strings from already-classified attributes (rarely needed — analyze_creative already includes naming).
Prompts
Beyond the tools above, this server exposes 10 MCP prompts (prompts/list, prompts/get) —
turnkey report recipes. Each one tells the calling agent exactly which tools to call, in what
order and with what arguments, and how to write up the result: a shared measurement-states
vocabulary (measured / not_applicable / not_reported — never a guessed number), spend
floors before calling winners or losers, explicit insufficient-evidence verdicts, and a
verdict-first, receipts-after output format. Any MCP client with prompt support can run these
directly; arguments arrive as strings and are validated the same way tool arguments are —
invalid enum values, malformed dates, and reversed date ranges (start after end) all raise a
protocol-level INVALID_PARAMS error instead of rendering a broken recipe. Default date windows
are UTC-anchored (datetime.now(timezone.utc)); date_preset never accepts custom on a
prompt that has no start_date/end_date argument of its own, since an unpaired custom window
is unsafe across these tools (some silently read all-time history, others reject it outright).
weekly_creative_report
The Monday artifact: freshness-stamped totals, tag-level winners/losers, top-spender fatigue
watch, and a decision queue. brand_name (required), date_preset (last_7_days |
last_30_days, default last_7_days), target_roas, target_cpa, spend_threshold
(default 500).
fatigue_check
Ranked fatigue watchlist for the top spenders before it shows up in ROAS. brand_name
(required), top_n (1-10, default 5), metric (roas | cpa | ctr | thumbstop_rate,
default roas), date_preset (last_30d | last_90d, default last_30d).
scale_kill_hold
Morning triage: every material creative bucketed into scale/kill/hold/insufficient-evidence
against a declared target. brand_name (required), objective_metric (roas | cpa,
required), target_value (required), minimum_spend (default 500), date_preset
(all_time | last_7_days | last_30_days | last_90_days, default last_30_days).
what_to_make_next_brief
Turns performance and coverage gaps into next sprint's production brief. brand_name
(required), production_slots (default 5), formats_available (optional), date_preset
(all_time | last_7_days | last_30_days | last_90_days, default last_30_days).
hook_report
Which hooks earn the view AND the purchase, which get skipped, and which are wearing out.
brand_name (required), date_preset (all_time | last_7_days | last_30_days |
last_90_days, default last_30_days), spend_threshold (default 500).
batch_readout
Grades a creative batch against the account baseline, with an explicit too-early-to-judge
bucket. brand_name (required), batch_start_date (required, YYYY-MM-DD), batch_end_date
(default today), baseline_preset (default last_90_days).
monday_money_check
The founder's one-glance verdict: above/below breakeven, better/worse than last week (Meta-
attributed only — blended MER is reported not_applicable). brand_name (required),
breakeven_roas (required unless target_cpa is given), target_cpa (optional),
date_preset (last_7_days | last_30_days, default last_7_days).
competitive_whitespace
Diffs a competitor's live ad strategy against your own library on the same taxonomy.
brand_name (required), competitor (optional page name — omit to reuse the latest saved
scan), country (default US), run_fresh_scan (default false), date_preset (all_time |
last_7_days | last_30_days | last_90_days, default last_90_days).
audience_read
Who your spend is reaching vs. who is efficiently converting, broken by age and gender,
reported alongside (never crossed with) messaging-angle and hook performance, as observed
associations with the controlled tests that would confirm them. brand_name
(required), objective_metric (roas | cpa | ctr, required), goal_direction
(maximize | minimize, required, must agree with objective_metric), date_preset
(all_time | last_7_days | last_30_days | last_90_days, default last_30_days).
client_review_pack
The monthly business-review skeleton: totals, winner pattern, testing slide, audience read,
competitor context, and next month's test proposal. brand_name (required),
period_start/period_end (required, YYYY-MM-DD), client_cpa_target (optional),
include_competitors (default true).
Architecture
Your AI agent ←—stdio—→ creative-tagger-mcp ←—HTTPS—→ api.creativetagger.ai
│
├── Gemini 3.5 Flash (default classifier)
├── Claude Sonnet 5 (configured fallback)
├── SQLite (library + brand memory)
└── Meta Ad LibraryYou bring the agent. We provide the taxonomy, the memory, and the strategist.
License
MIT
Available Tools
43 toolsanalyze_creativeA
Analyze any ad creative (image, video, carousel, landing page, email) and return structured classification across 21 dimensions: media type, asset type, visual format, visual style, talent and talent demographics, hook type, messaging angle, audience, CTA, emotion, audio type, voiceover tone, seasonality, offer type, aspect ratio, duration, and more. Also generates standardized naming conventions. Provide one of: file_path, url, or html_content.
Inputs: url, format, version, file_path, +5 more.
analyze_gapsA
Identify gaps in the user's creative library for a given brand and propose concrete next creatives that fill them. Surfaces concentration risk (e.g., 78% UGC TalkHead) and recommends under-represented hook types, messaging angles, creative types. Returns JSON with gap analysis + ready-to-produce briefs.
Inputs: brand_name (required).
create_custom_reportA
Create a custom performance report by selecting standard and/or brand taxonomy dimensions, then ranking the actual matched dimension combinations by ROAS, funnel_score, spend, CTR, or CPA. Use this when the user asks for a custom Motion-style view like hook x landing_page x offer_type, founder x hook, offer x audience, or custom segments. Optional start_date and end_date let an agent isolate a specific test window before explaining the winning combination. Rows can include parts and values so the agent can explain the winning combination.
Inputs: brand_name (required), dimensions (required), layer, limit, +5 more.
delete_brand_entityB
Delete one brand entity by brand, entity_type, and canonical name. Useful when a creator, product, offer, customer segment, ICP, or campaign label should no longer be recognized for the brand.
Inputs: name (required), brand_name (required), entity_type (required).
delete_brand_taxonomy_valueA
Delete one brand-specific taxonomy value by brand, dimension, and canonical value. Use this to prune stale founders, segments, offers, or internal labels from Brand Taxonomy Studio.
Inputs: value (required), dimension (required), brand_name (required).
delete_custom_reportC
Delete a saved custom report definition by id.
Inputs: report_id (required).
delete_naming_templateC
Delete a saved naming template by name.
Inputs: name.
export_brain_learnings_contextC
Export a bounded, prompt-ready context from get_brain_learnings, including follow-up Strategy and time-series queries and the same canonical audience filters.
Inputs: kinds, limit, end_date, brand_name, +20 more.
export_demographics_contextA
Return an agent-ready audience context payload from saved age x gender performance memory. Use this when another agent or workflow needs the higher and lower observed-efficiency bands, account totals, summary text, a prompt-ready descriptive review queue, and date-scoped mixed creative x audience strategy queries plus time-series follow-up queries without opening the dashboard.
Inputs: limit, end_date, brand_name, start_date, +1 more.
export_performance_timeseries_contextC
Export the bounded agent_context from get_performance_timeseries with its decision queue and data-quality warnings.
Inputs: limit, metric, end_date, group_by, +11 more.
generate_brand_taxonomyA
Auto-build a brand's ENTIRE custom taxonomy from trends in its analyzed creative library — messaging themes, intended audiences, AND entities (products, founders, creators, offers, customer segments, campaign labels). Lets a brand get the full brand-custom layer with zero manual setup. Optionally persists everything into Brand Taxonomy Studio so future analyses, predictions, and naming templates use them.
Inputs: brand_name (required), persist.
generate_namingA
Generate V1-compatible standard, full, compact, and reporting naming convention strings from creative attributes. Use when you already have classified attributes (for example from analyze_creative) and need the same naming structure the API returns.
Inputs: brand_name (required), cta, talent, emotion, +15 more.
get_analysisA
Get the full analysis result for a single saved library item by ID. Use after list_library when you need the complete 21-dimension classification (list_library returns a summary; this returns the full JSON).
Inputs: analysis_id (required), brand_name.
get_brain_learningsA
Read one workspace's current Brand Brain observations, conclusions, watchouts, audience signals, gaps, and agent_context. Validate associations with controlled tests before changing allocation. Audience filters use higher_observed_efficiency or lower_observed_efficiency.
Inputs: kinds, limit, end_date, brand_name, +20 more.
get_brand_contextA
Retrieve the saved brand context for a brand: voice, target audience, top performers, anti-patterns, and notes. Strategist tools auto-include this; this tool exposes the raw stored context.
Inputs: brand_name (required).
get_brand_taxonomyA
Retrieve the brand-custom taxonomy for a brand: custom values, aliases, and entities such as founder, recurring creators, products, offers, customer segments, ICPs, and campaign labels. Standard taxonomy still lives in attributes; this is the brand-specific extension layer.
Inputs: brand_name (required).
get_competitor_scan_historyA
Return saved competitor Market scans/imports for the current workspace without re-running Meta Ad Library access. Useful for re-briefing past market reads, checking the latest tagged competitor patterns, or building strategy prompts from previously saved scans.
Inputs: limit, brand_name.
get_creative_strategy_reportA
Read one workspace's observational Strategy matrix and decision queue. Defaults to a bounded concise response; use detailed only for an explicit deep dive. Treat cells as test hypotheses, not causal effects.
Inputs: rows, limit, columns, metrics, +23 more.
get_demographics_performanceA
Return saved age x gender delivery with account-relative higher and lower observed-return-per-spend bands. These are descriptive associations, not audience outcome or action verdicts. Supports report date presets like last_30_days or a custom start_date/end_date (YYYY-MM-DD) to scope the audience read to a specific performance window.
Inputs: end_date, brand_name, start_date, date_preset.
get_library_patternsA
Get pattern insights across the user's entire library: which hooks, angles, creative types, emotions they over- or under-index on. Returns top values per dimension with percentages plus rule-based diversification insights. Use this for portfolio analysis before recommending what to make next.
Inputs: brand_name.
get_meta_performance_summaryA
Read the saved Meta performance memory for a brand without triggering a sync. Returns totals plus winners/losers by standard taxonomy and brand-custom taxonomy values, including explainable funnel_score signals for capture, hold, bring-to-site, and convert stages. Supports all_time, last_7_days, last_30_days, last_90_days, or custom date windows.
Inputs: end_date, brand_name, start_date, date_preset.
get_meta_statusB
Check whether read-only Meta performance sync is connected for the authenticated user. Returns account id, scopes, read-only status, and latest sync metadata.
Inputs: brand_name.
get_naming_variablesA
List every variable available in saved naming templates, including standard taxonomy fields plus brand-custom variables like founder, product, offer, customer_segment, icp, and campaign_label.
Inputs: no named parameters.
get_performance_timeseriesB
Read one workspace's saved performance series for observational fatigue, trajectory, and data-coverage checks.
Inputs: limit, metric, end_date, group_by, +11 more.
get_prebuilt_reportsA
Return Motion-style prebuilt creative reports for a brand: best hooks, landing pages, messaging angles, audiences, offers, CTAs, visual formats, and brand-custom values. Rows include ROAS, spend, CTR, thumbstop, and funnel_score when performance memory exists. Optional start_date/end_date (YYYY-MM-DD) scope the report window.
Inputs: limit, end_date, report_id, brand_name, +2 more.
get_taxonomyA
Get Creative Tagger taxonomy v2's 15 controlled dimensions, one derived/open aspect-ratio dimension, and two dynamic, brand-specific dimensions. The package ships a versioned vocabulary because the API schema does not expose enums for every classification field. Use this before analyze_creative when you want to know the vocabulary the system understands. Taxonomy v2: media type (the auto-detected format — static image, video, carousel), asset type (production class), and visual format (execution style) are three separate dimensions; 'Static Image' and 'Carousel' are media types, not visual_format values.
Inputs: dimension.
get_taxonomy_performanceA
Return tag-level performance with significance gating and coverage gaps. Use this to find which taxonomy values are associated with stronger historical outcomes, which are under-observed, and which standard values have never been tried. Rows include ROAS, CTR, thumbstop, and funnel_score when performance memory exists. Supports the same date presets as the main performance summary.
Inputs: end_date, dimension, brand_name, start_date, +2 more.
list_custom_reportsC
List saved custom report definitions for a brand.
Inputs: brand_name.
list_libraryA
Browse the authenticated user's saved analysis library (memory). Every analyze_creative call is automatically saved. Use this to recall what has been analyzed before — search by filename, hook, angle, emotion, CTA, talent, offer, audio, season, or format, then sort by recency or joined performance (spend, reach, frequency, ROAS, CTR, CPM, CPA).
Inputs: cta, hook, sort, angle, +10 more.
list_naming_templatesA
List the authenticated user's saved naming templates. Templates are applied automatically to future analyze_creative results.
Inputs: no named parameters.
list_workspacesA
List the authenticated user's workspaces and their exact brand_name scope. Call this first, then reuse one returned brand_name on every library, status, report, and strategist request.
Inputs: no named parameters.
predict_creativeA
Legacy-named observational pre-flight. Compare a creative's tags with the brand's historical tag-level performance; this is not a forecast or causal estimate. Use the fit score and tag associations to form a one-variable controlled-test hypothesis with predeclared success and stop criteria. Pass an analysis_id or raw attributes.
Inputs: brand_name (required), attributes, analysis_id.
preview_naming_templateC
Preview a naming template with sample taxonomy values before saving it.
Inputs: template (required), name, separator.
recommendA
Ask the Creative Strategist a question, grounded in the user's library + brand context. The strategist auto-loads patterns from prior analyses and any saved brand voice/audience/anti-patterns for the brand, then answers with concrete creative recommendations using taxonomy values. Use this for open-ended strategic questions ('what should I test next', 'how should I approach Q4', 'what kind of UGC would work for this audience').
Inputs: question (required), brand_name (required).
run_saved_custom_reportC
Run a saved custom report definition by id.
Inputs: report_id (required).
save_brain_learningsB
Persist a reviewed get_brain_learnings slice as Brand Brain notes. Uses the same canonical audience filters; saving memory does not prove causality.
Inputs: brand_name (required), kinds, limit, end_date, +21 more.
save_custom_reportB
Save or update a reusable custom report definition for a brand. Use this when the user wants the same Motion-style combination view available later, such as hook_type x landing_page x offer_type, including custom report windows scoped to a specific test period or a richer dashboard preset with a saved view type, grouping, metric set, filters, sort, and metric preset.
Inputs: name (required), brand_name (required), dimensions (required), sort, +13 more.
save_naming_templateB
Create or update a saved naming template using {variable} placeholders. Supports standard taxonomy fields and brand-custom variables.
Inputs: template (required), name, separator.
scan_competitorA
Scan a competitor's ads from the Meta Ad Library and return classified results plus an aggregate strategy breakdown (top hook types, visual styles, CTAs, emotions, estimated spend). Provide page_id, page_name, or keyword. Returns ad metadata, full Creative Tagger analysis per ad, and strategy insights.
Inputs: limit, country, keyword, page_id, +3 more.
set_brand_contextA
Create or update brand context for a brand. Stored per-user. This is the brand's long-term memory — voice, audience, what works, what to avoid. Future strategist and brief calls automatically include this context. Upserts on (user, brand_name).
Inputs: brand_name (required), notes, voice, anti_patterns, +2 more.
set_brand_entityB
Create or update a prompt/entity-based brand entity to recognize in creative analysis: founder, creator, customer, spokesperson, product, offer, customer_segment, icp, or campaign_label.
Inputs: name (required), brand_name (required), entity_type (required), aliases, +1 more.
set_brand_taxonomy_valueB
Create or update one brand-specific allowed value for an existing Creative Tagger dimension, with aliases. Example: dimension=talent, value='Stephen Lavender / Founder', aliases=['Stephen','founder'].
Inputs: value (required), dimension (required), brand_name (required), aliases, +1 more.
sync_meta_performanceA
Trigger a read-only Meta ads performance sync for a brand. Syncs ad performance rows and reports summaries by standard and brand-custom taxonomy values. Supports explicit attribution/lookback windows so agents can match the buyer's Ads Manager view. Does not create campaigns or edit budgets.
Inputs: account_id, brand_name, date_preset, attribution_windows.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 43 tools
Each tool targets a distinct function: analyzing, retrieving, managing taxonomy, performance, reports, naming, strategy, etc. Descriptions clearly differentiate overlapping areas like analysis vs. prediction vs. library browsing. No ambiguity between tools.
All tools consistently use snake_case with a verb_noun pattern (e.g., analyze_creative, get_taxonomy, set_brand_context). Even longer names follow this pattern. No mixing of conventions.
43 tools is on the high side for a single server. While the domain is broad (analysis, taxonomy, performance, reports, strategy), the number could be streamlined. However, each tool serves a clear purpose, so it's not excessive.
The server covers the full lifecycle of creative analysis: uploading, classification, storage, taxonomy management, performance tracking, reporting, naming, competitor scanning, and strategic recommendations. No obvious gaps for the stated purpose.
Maintenance
Related MCP Connectors
Creative intelligence for Meta, TikTok, Google Ads and Amazon DSP, in Claude and other MCP clients.
Competitive ad intelligence for AI agents: portfolios, ad/content search, analytics, discovery.
Creative analytics for Meta ads: winning ads, AI tags, competitor ad intel and ad launching.
Marketing intelligence API for AI agents. Real campaign data, not LLM guesses.
Related MCP Servers
- AlicenseAqualityNot gradedmaintenanceEnables AI-powered analysis, management, and optimization of Meta advertising campaigns across Facebook and Instagram, including performance insights, budget optimization, and creative testing.33Business Source 1.1
- AlicenseAqualityDmaintenanceProvides Meta and Google Ads intelligence for AI assistants, enabling users to analyze performance, track competitors, and manage ad campaigns through natural language. It features 17 tools for generating creative concepts, scraping competitor ads, and performing deep account-level analysis.17MIT
- AlicenseNot gradedqualityBmaintenanceEnables AI assistants to create, analyze, and optimize ad campaigns across Google Ads, Meta Ads, TikTok Ads, LinkedIn Ads, Amazon Ads, and ChatGPT Ads through natural language using 400+ tools.107MIT

AdCrunch MCP Serverofficial
FlicenseNot gradedqualityCmaintenanceEnables querying ad campaign performance and setup across Meta, TikTok, and Google Ads using natural language through AI agents.1-