adloop 0.19.1__tar.gz → 0.19.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {adloop-0.19.1 → adloop-0.19.3}/PKG-INFO +1 -1
- {adloop-0.19.1 → adloop-0.19.3}/pyproject.toml +1 -1
- {adloop-0.19.1 → adloop-0.19.3}/pyproject.toml.orig +1 -1
- {adloop-0.19.1 → adloop-0.19.3}/src/adloop/ads/write.py +21 -1
- {adloop-0.19.1 → adloop-0.19.3}/src/adloop/server.py +138 -119
- {adloop-0.19.1 → adloop-0.19.3}/README.md +0 -0
- {adloop-0.19.1 → adloop-0.19.3}/src/adloop/__init__.py +0 -0
- {adloop-0.19.1 → adloop-0.19.3}/src/adloop/__main__.py +0 -0
- {adloop-0.19.1 → adloop-0.19.3}/src/adloop/_mcp_patches.py +0 -0
- {adloop-0.19.1 → adloop-0.19.3}/src/adloop/ads/__init__.py +0 -0
- {adloop-0.19.1 → adloop-0.19.3}/src/adloop/ads/ai_max.py +0 -0
- {adloop-0.19.1 → adloop-0.19.3}/src/adloop/ads/brands.py +0 -0
- {adloop-0.19.1 → adloop-0.19.3}/src/adloop/ads/client.py +0 -0
- {adloop-0.19.1 → adloop-0.19.3}/src/adloop/ads/conversion_actions.py +0 -0
- {adloop-0.19.1 → adloop-0.19.3}/src/adloop/ads/currency.py +0 -0
- {adloop-0.19.1 → adloop-0.19.3}/src/adloop/ads/custom_conversion_goals.py +0 -0
- {adloop-0.19.1 → adloop-0.19.3}/src/adloop/ads/enums.py +0 -0
- {adloop-0.19.1 → adloop-0.19.3}/src/adloop/ads/forecast.py +0 -0
- {adloop-0.19.1 → adloop-0.19.3}/src/adloop/ads/gaql.py +0 -0
- {adloop-0.19.1 → adloop-0.19.3}/src/adloop/ads/image_fetch.py +0 -0
- {adloop-0.19.1 → adloop-0.19.3}/src/adloop/ads/pmax.py +0 -0
- {adloop-0.19.1 → adloop-0.19.3}/src/adloop/ads/read.py +0 -0
- {adloop-0.19.1 → adloop-0.19.3}/src/adloop/ads/validate_only.py +0 -0
- {adloop-0.19.1 → adloop-0.19.3}/src/adloop/auth.py +0 -0
- {adloop-0.19.1 → adloop-0.19.3}/src/adloop/cli.py +0 -0
- {adloop-0.19.1 → adloop-0.19.3}/src/adloop/config.py +0 -0
- {adloop-0.19.1 → adloop-0.19.3}/src/adloop/crossref.py +0 -0
- {adloop-0.19.1 → adloop-0.19.3}/src/adloop/diagnostics.py +0 -0
- {adloop-0.19.1 → adloop-0.19.3}/src/adloop/ga4/__init__.py +0 -0
- {adloop-0.19.1 → adloop-0.19.3}/src/adloop/ga4/client.py +0 -0
- {adloop-0.19.1 → adloop-0.19.3}/src/adloop/ga4/reports.py +0 -0
- {adloop-0.19.1 → adloop-0.19.3}/src/adloop/ga4/tracking.py +0 -0
- {adloop-0.19.1 → adloop-0.19.3}/src/adloop/ga4/write.py +0 -0
- {adloop-0.19.1 → adloop-0.19.3}/src/adloop/gsc/__init__.py +0 -0
- {adloop-0.19.1 → adloop-0.19.3}/src/adloop/gsc/client.py +0 -0
- {adloop-0.19.1 → adloop-0.19.3}/src/adloop/gsc/reports.py +0 -0
- {adloop-0.19.1 → adloop-0.19.3}/src/adloop/gtm/__init__.py +0 -0
- {adloop-0.19.1 → adloop-0.19.3}/src/adloop/gtm/client.py +0 -0
- {adloop-0.19.1 → adloop-0.19.3}/src/adloop/gtm/read.py +0 -0
- {adloop-0.19.1 → adloop-0.19.3}/src/adloop/merchant/__init__.py +0 -0
- {adloop-0.19.1 → adloop-0.19.3}/src/adloop/merchant/client.py +0 -0
- {adloop-0.19.1 → adloop-0.19.3}/src/adloop/merchant/read.py +0 -0
- {adloop-0.19.1 → adloop-0.19.3}/src/adloop/pagespeed.py +0 -0
- {adloop-0.19.1 → adloop-0.19.3}/src/adloop/reddit/__init__.py +0 -0
- {adloop-0.19.1 → adloop-0.19.3}/src/adloop/reddit/auth.py +0 -0
- {adloop-0.19.1 → adloop-0.19.3}/src/adloop/reddit/client.py +0 -0
- {adloop-0.19.1 → adloop-0.19.3}/src/adloop/reddit/read.py +0 -0
- {adloop-0.19.1 → adloop-0.19.3}/src/adloop/reddit/schedule.py +0 -0
- {adloop-0.19.1 → adloop-0.19.3}/src/adloop/reddit/write.py +0 -0
- {adloop-0.19.1 → adloop-0.19.3}/src/adloop/rules/__init__.py +0 -0
- {adloop-0.19.1 → adloop-0.19.3}/src/adloop/rules/adloop.md +0 -0
- {adloop-0.19.1 → adloop-0.19.3}/src/adloop/rules/commands/analyze-performance.md +0 -0
- {adloop-0.19.1 → adloop-0.19.3}/src/adloop/rules/commands/budget-plan.md +0 -0
- {adloop-0.19.1 → adloop-0.19.3}/src/adloop/rules/commands/create-ad.md +0 -0
- {adloop-0.19.1 → adloop-0.19.3}/src/adloop/rules/commands/create-campaign.md +0 -0
- {adloop-0.19.1 → adloop-0.19.3}/src/adloop/rules/commands/diagnose-tracking.md +0 -0
- {adloop-0.19.1 → adloop-0.19.3}/src/adloop/rules/commands/optimize-campaign.md +0 -0
- {adloop-0.19.1 → adloop-0.19.3}/src/adloop/rules_install.py +0 -0
- {adloop-0.19.1 → adloop-0.19.3}/src/adloop/runtime.py +0 -0
- {adloop-0.19.1 → adloop-0.19.3}/src/adloop/safety/__init__.py +0 -0
- {adloop-0.19.1 → adloop-0.19.3}/src/adloop/safety/audit.py +0 -0
- {adloop-0.19.1 → adloop-0.19.3}/src/adloop/safety/guards.py +0 -0
- {adloop-0.19.1 → adloop-0.19.3}/src/adloop/safety/preview.py +0 -0
- {adloop-0.19.1 → adloop-0.19.3}/src/adloop/tracking.py +0 -0
|
@@ -2780,7 +2780,27 @@ def confirm_and_apply(
|
|
|
2780
2780
|
"objects an earlier step would create, so Google could "
|
|
2781
2781
|
"only validate the step(s) before them."
|
|
2782
2782
|
)
|
|
2783
|
-
|
|
2783
|
+
from adloop.runtime import deployment_mode as _deployment_mode
|
|
2784
|
+
|
|
2785
|
+
if forced_by_config and _deployment_mode() == "server":
|
|
2786
|
+
# Hosted: the flag is the workspace's live-changes setting,
|
|
2787
|
+
# switched in the dashboard. There is no config file to edit
|
|
2788
|
+
# and no server for the user to restart.
|
|
2789
|
+
response["dry_run_forced_by"] = "config.safety.require_dry_run"
|
|
2790
|
+
response["remediation"] = (
|
|
2791
|
+
"Live changes are switched off for this workspace (or for "
|
|
2792
|
+
"this client). The workspace owner can switch them on in "
|
|
2793
|
+
"the AdLoop Cloud dashboard under Settings → Safety. Passing "
|
|
2794
|
+
"dry_run=false on this tool will keep being overridden until "
|
|
2795
|
+
"then."
|
|
2796
|
+
)
|
|
2797
|
+
response["message"] = (
|
|
2798
|
+
"dry_run=false was IGNORED because live changes are switched "
|
|
2799
|
+
"off for this workspace. No changes were made. Retrying this "
|
|
2800
|
+
"tool with dry_run=false will not succeed until live changes "
|
|
2801
|
+
"are switched on in the dashboard."
|
|
2802
|
+
)
|
|
2803
|
+
elif forced_by_config:
|
|
2784
2804
|
# The caller passed dry_run=false but safety.require_dry_run
|
|
2785
2805
|
# forced it back on. Tell them exactly why and how to unlock
|
|
2786
2806
|
# real writes — without this, agents (e.g. Claude Code) retry
|
|
@@ -166,6 +166,20 @@ mcp = FastMCP(
|
|
|
166
166
|
)
|
|
167
167
|
|
|
168
168
|
|
|
169
|
+
def _tool(*, title: str, annotations: ToolAnnotations, **kwargs):
|
|
170
|
+
"""Register a tool with its title in both places MCP defines one.
|
|
171
|
+
|
|
172
|
+
The tool's own ``title`` is what clients display; ``annotations.title``
|
|
173
|
+
is what directory reviews (Claude's connector portal) check. One title,
|
|
174
|
+
copied into the shared annotation preset, keeps them from drifting.
|
|
175
|
+
"""
|
|
176
|
+
return mcp.tool(
|
|
177
|
+
title=title,
|
|
178
|
+
annotations=annotations.model_copy(update={"title": title}),
|
|
179
|
+
**kwargs,
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
|
|
169
183
|
def _reddit_structured_error(exc: Exception) -> dict | None:
|
|
170
184
|
"""Reddit-specific translations; keyed on exception type so Reddit's
|
|
171
185
|
``invalid_grant`` never gets the "Reconnect Google" hint below."""
|
|
@@ -310,13 +324,20 @@ def _structured_error(fn_name: str, exc: Exception) -> dict:
|
|
|
310
324
|
}
|
|
311
325
|
|
|
312
326
|
if "deleted_client" in err_lower or "invalid_client" in err_lower:
|
|
327
|
+
from adloop.runtime import deployment_mode
|
|
328
|
+
|
|
313
329
|
return {
|
|
314
330
|
"error": (
|
|
315
331
|
"Authentication failed — the OAuth client behind your stored "
|
|
316
332
|
"credentials no longer exists or is invalid."
|
|
317
333
|
),
|
|
334
|
+
# On a hosted server the user never sees an OAuth client: the
|
|
335
|
+
# fix is reconnecting, and pointing at a product would be an ad.
|
|
318
336
|
"hint": (
|
|
319
|
-
"
|
|
337
|
+
"Reconnect Google in your AdLoop Cloud dashboard "
|
|
338
|
+
"(Settings → Google), then retry."
|
|
339
|
+
if deployment_mode() == "server"
|
|
340
|
+
else "If you set up AdLoop before v0.10 with its bundled "
|
|
320
341
|
"credentials: that shared Google Cloud project has been "
|
|
321
342
|
"retired. Fastest fix: AdLoop Cloud (https://getadloop.com) — "
|
|
322
343
|
"connect Google in two clicks, no Google Cloud project "
|
|
@@ -393,7 +414,7 @@ def _safe(fn: Callable) -> Callable:
|
|
|
393
414
|
# ---------------------------------------------------------------------------
|
|
394
415
|
|
|
395
416
|
|
|
396
|
-
@
|
|
417
|
+
@_tool(title="Connection health check", annotations=_READONLY, tags={"core"})
|
|
397
418
|
@_safe
|
|
398
419
|
def health_check() -> dict:
|
|
399
420
|
"""Test AdLoop connectivity — checks OAuth token, GA4 API, Google Ads API,
|
|
@@ -524,7 +545,7 @@ def health_check() -> dict:
|
|
|
524
545
|
# ---------------------------------------------------------------------------
|
|
525
546
|
|
|
526
547
|
|
|
527
|
-
@
|
|
548
|
+
@_tool(title="List Analytics properties", annotations=_READONLY, tags={"ga4"})
|
|
528
549
|
@_safe
|
|
529
550
|
def get_account_summaries() -> dict:
|
|
530
551
|
"""List all GA4 accounts and properties accessible by the authenticated user.
|
|
@@ -537,7 +558,7 @@ def get_account_summaries() -> dict:
|
|
|
537
558
|
return _impl(current_config())
|
|
538
559
|
|
|
539
560
|
|
|
540
|
-
@
|
|
561
|
+
@_tool(title="Analytics report", annotations=_READONLY, tags={"ga4"})
|
|
541
562
|
@_safe
|
|
542
563
|
def run_ga4_report(
|
|
543
564
|
dimensions: _StrListOpt = None,
|
|
@@ -570,7 +591,7 @@ def run_ga4_report(
|
|
|
570
591
|
)
|
|
571
592
|
|
|
572
593
|
|
|
573
|
-
@
|
|
594
|
+
@_tool(title="Analytics realtime report", annotations=_READONLY, tags={"ga4"})
|
|
574
595
|
@_safe
|
|
575
596
|
def run_realtime_report(
|
|
576
597
|
dimensions: _StrListOpt = None,
|
|
@@ -593,7 +614,7 @@ def run_realtime_report(
|
|
|
593
614
|
)
|
|
594
615
|
|
|
595
616
|
|
|
596
|
-
@
|
|
617
|
+
@_tool(title="List Analytics events", annotations=_READONLY, tags={"ga4"})
|
|
597
618
|
@_safe
|
|
598
619
|
def get_tracking_events(
|
|
599
620
|
date_range_start: str = "28daysAgo",
|
|
@@ -620,7 +641,7 @@ def get_tracking_events(
|
|
|
620
641
|
# ---------------------------------------------------------------------------
|
|
621
642
|
|
|
622
643
|
|
|
623
|
-
@
|
|
644
|
+
@_tool(title="List Search Console properties", annotations=_READONLY, tags={"gsc"})
|
|
624
645
|
@_safe
|
|
625
646
|
def list_gsc_sites() -> dict:
|
|
626
647
|
"""List all Google Search Console properties the authenticated user can access.
|
|
@@ -634,7 +655,7 @@ def list_gsc_sites() -> dict:
|
|
|
634
655
|
return _impl(current_config())
|
|
635
656
|
|
|
636
657
|
|
|
637
|
-
@
|
|
658
|
+
@_tool(title="Search Console report", annotations=_READONLY, tags={"gsc"})
|
|
638
659
|
@_safe
|
|
639
660
|
def run_gsc_report(
|
|
640
661
|
site_url: str = "",
|
|
@@ -652,7 +673,7 @@ def run_gsc_report(
|
|
|
652
673
|
finding keyword opportunities, and cross-referencing with GA4 and Ads data.
|
|
653
674
|
|
|
654
675
|
site_url: the GSC property URL (e.g. "https://example.com/" or
|
|
655
|
-
"sc-domain:example.com"). Defaults to
|
|
676
|
+
"sc-domain:example.com"). Defaults to the configured Search Console site.
|
|
656
677
|
dimensions: one or more of ["query", "page", "country", "device", "date"].
|
|
657
678
|
Defaults to ["query"].
|
|
658
679
|
date_range_start / date_range_end: ISO dates (YYYY-MM-DD) or relative
|
|
@@ -686,7 +707,7 @@ def run_gsc_report(
|
|
|
686
707
|
# ---------------------------------------------------------------------------
|
|
687
708
|
|
|
688
709
|
|
|
689
|
-
@
|
|
710
|
+
@_tool(title="PageSpeed analysis", annotations=_READONLY, tags={"web"})
|
|
690
711
|
@_safe
|
|
691
712
|
def analyze_page_speed(url: str, strategy: str = "mobile") -> dict:
|
|
692
713
|
"""Run PageSpeed Insights for a landing page — Lighthouse + real-user data.
|
|
@@ -705,7 +726,7 @@ def analyze_page_speed(url: str, strategy: str = "mobile") -> dict:
|
|
|
705
726
|
return _impl(current_config(), url=url, strategy=strategy)
|
|
706
727
|
|
|
707
728
|
|
|
708
|
-
@
|
|
729
|
+
@_tool(
|
|
709
730
|
title="List Merchant Center accounts",
|
|
710
731
|
annotations=_READONLY,
|
|
711
732
|
tags={"merchant"},
|
|
@@ -723,7 +744,7 @@ def list_merchant_accounts() -> dict:
|
|
|
723
744
|
return _impl(current_config())
|
|
724
745
|
|
|
725
746
|
|
|
726
|
-
@
|
|
747
|
+
@_tool(title="Merchant Center feed health", annotations=_READONLY, tags={"merchant"})
|
|
727
748
|
@_safe
|
|
728
749
|
def get_merchant_feed_health(account_id: str = "") -> dict:
|
|
729
750
|
"""Merchant Center feed health — disapproved products + account issues.
|
|
@@ -743,7 +764,7 @@ def get_merchant_feed_health(account_id: str = "") -> dict:
|
|
|
743
764
|
return _impl(current_config(), account_id=account_id)
|
|
744
765
|
|
|
745
766
|
|
|
746
|
-
@
|
|
767
|
+
@_tool(title="List Google Ads accounts", annotations=_READONLY, tags={"ads"})
|
|
747
768
|
@_safe
|
|
748
769
|
def list_accounts(limit: int = 200) -> dict:
|
|
749
770
|
"""List accessible Google Ads accounts.
|
|
@@ -762,7 +783,7 @@ def list_accounts(limit: int = 200) -> dict:
|
|
|
762
783
|
return _impl(current_config(), limit=limit)
|
|
763
784
|
|
|
764
785
|
|
|
765
|
-
@
|
|
786
|
+
@_tool(title="Campaign performance", annotations=_READONLY, tags={"ads"})
|
|
766
787
|
@_safe
|
|
767
788
|
def get_campaign_performance(
|
|
768
789
|
customer_id: str = "",
|
|
@@ -791,7 +812,7 @@ def get_campaign_performance(
|
|
|
791
812
|
)
|
|
792
813
|
|
|
793
814
|
|
|
794
|
-
@
|
|
815
|
+
@_tool(title="Ad performance", annotations=_READONLY, tags={"ads"})
|
|
795
816
|
@_safe
|
|
796
817
|
def get_ad_performance(
|
|
797
818
|
customer_id: str = "",
|
|
@@ -819,7 +840,7 @@ def get_ad_performance(
|
|
|
819
840
|
)
|
|
820
841
|
|
|
821
842
|
|
|
822
|
-
@
|
|
843
|
+
@_tool(title="Keyword performance", annotations=_READONLY, tags={"ads"})
|
|
823
844
|
@_safe
|
|
824
845
|
def get_keyword_performance(
|
|
825
846
|
customer_id: str = "",
|
|
@@ -847,7 +868,7 @@ def get_keyword_performance(
|
|
|
847
868
|
)
|
|
848
869
|
|
|
849
870
|
|
|
850
|
-
@
|
|
871
|
+
@_tool(title="Search terms report", annotations=_READONLY, tags={"ads"})
|
|
851
872
|
@_safe
|
|
852
873
|
def get_search_terms(
|
|
853
874
|
customer_id: str = "",
|
|
@@ -875,7 +896,7 @@ def get_search_terms(
|
|
|
875
896
|
)
|
|
876
897
|
|
|
877
898
|
|
|
878
|
-
@
|
|
899
|
+
@_tool(title="List negative keywords", annotations=_READONLY, tags={"ads"})
|
|
879
900
|
@_safe
|
|
880
901
|
def get_negative_keywords(
|
|
881
902
|
customer_id: str = "",
|
|
@@ -895,7 +916,7 @@ def get_negative_keywords(
|
|
|
895
916
|
)
|
|
896
917
|
|
|
897
918
|
|
|
898
|
-
@
|
|
919
|
+
@_tool(
|
|
899
920
|
title="List shared negative keyword lists",
|
|
900
921
|
annotations=_READONLY,
|
|
901
922
|
tags={"ads"},
|
|
@@ -915,7 +936,7 @@ def get_negative_keyword_lists(
|
|
|
915
936
|
return _impl(current_config(), customer_id=customer_id or current_config().ads.customer_id)
|
|
916
937
|
|
|
917
938
|
|
|
918
|
-
@
|
|
939
|
+
@_tool(
|
|
919
940
|
title="Keywords in a negative keyword list",
|
|
920
941
|
annotations=_READONLY,
|
|
921
942
|
tags={"ads"},
|
|
@@ -938,7 +959,7 @@ def get_negative_keyword_list_keywords(
|
|
|
938
959
|
)
|
|
939
960
|
|
|
940
961
|
|
|
941
|
-
@
|
|
962
|
+
@_tool(
|
|
942
963
|
title="Campaigns using a negative keyword list",
|
|
943
964
|
annotations=_READONLY,
|
|
944
965
|
tags={"ads"},
|
|
@@ -967,7 +988,7 @@ def get_negative_keyword_list_campaigns(
|
|
|
967
988
|
# ---------------------------------------------------------------------------
|
|
968
989
|
|
|
969
990
|
|
|
970
|
-
@
|
|
991
|
+
@_tool(title="Google Ads recommendations", annotations=_READONLY, tags={"ads"})
|
|
971
992
|
@_safe
|
|
972
993
|
def get_recommendations(
|
|
973
994
|
customer_id: str = "",
|
|
@@ -996,7 +1017,7 @@ def get_recommendations(
|
|
|
996
1017
|
)
|
|
997
1018
|
|
|
998
1019
|
|
|
999
|
-
@
|
|
1020
|
+
@_tool(title="Performance Max performance", annotations=_READONLY, tags={"ads"})
|
|
1000
1021
|
@_safe
|
|
1001
1022
|
def get_pmax_performance(
|
|
1002
1023
|
customer_id: str = "",
|
|
@@ -1027,7 +1048,7 @@ def get_pmax_performance(
|
|
|
1027
1048
|
)
|
|
1028
1049
|
|
|
1029
1050
|
|
|
1030
|
-
@
|
|
1051
|
+
@_tool(
|
|
1031
1052
|
title="Performance Max asset performance",
|
|
1032
1053
|
annotations=_READONLY,
|
|
1033
1054
|
tags={"ads"},
|
|
@@ -1060,7 +1081,7 @@ def get_asset_performance(
|
|
|
1060
1081
|
)
|
|
1061
1082
|
|
|
1062
1083
|
|
|
1063
|
-
@
|
|
1084
|
+
@_tool(
|
|
1064
1085
|
title="Performance Max asset combinations",
|
|
1065
1086
|
annotations=_READONLY,
|
|
1066
1087
|
tags={"ads"},
|
|
@@ -1087,7 +1108,7 @@ def get_detailed_asset_performance(
|
|
|
1087
1108
|
)
|
|
1088
1109
|
|
|
1089
1110
|
|
|
1090
|
-
@
|
|
1111
|
+
@_tool(title="Audience performance", annotations=_READONLY, tags={"ads"})
|
|
1091
1112
|
@_safe
|
|
1092
1113
|
def get_audience_performance(
|
|
1093
1114
|
customer_id: str = "",
|
|
@@ -1118,7 +1139,7 @@ def get_audience_performance(
|
|
|
1118
1139
|
)
|
|
1119
1140
|
|
|
1120
1141
|
|
|
1121
|
-
@
|
|
1142
|
+
@_tool(title="Demographic targeting", annotations=_READONLY, tags={"ads"})
|
|
1122
1143
|
@_safe
|
|
1123
1144
|
def get_demographic_targeting(
|
|
1124
1145
|
ad_group_id: str = "",
|
|
@@ -1151,7 +1172,7 @@ def get_demographic_targeting(
|
|
|
1151
1172
|
# ---------------------------------------------------------------------------
|
|
1152
1173
|
|
|
1153
1174
|
|
|
1154
|
-
@
|
|
1175
|
+
@_tool(
|
|
1155
1176
|
title="Campaign conversions against Analytics",
|
|
1156
1177
|
annotations=_READONLY,
|
|
1157
1178
|
tags={"tracking"},
|
|
@@ -1185,7 +1206,7 @@ def analyze_campaign_conversions(
|
|
|
1185
1206
|
)
|
|
1186
1207
|
|
|
1187
1208
|
|
|
1188
|
-
@
|
|
1209
|
+
@_tool(title="Landing page analysis", annotations=_READONLY, tags={"tracking"})
|
|
1189
1210
|
@_safe
|
|
1190
1211
|
def landing_page_analysis(
|
|
1191
1212
|
date_range_start: str = "",
|
|
@@ -1211,7 +1232,7 @@ def landing_page_analysis(
|
|
|
1211
1232
|
)
|
|
1212
1233
|
|
|
1213
1234
|
|
|
1214
|
-
@
|
|
1235
|
+
@_tool(title="Attribution check", annotations=_READONLY, tags={"tracking"})
|
|
1215
1236
|
@_safe
|
|
1216
1237
|
def attribution_check(
|
|
1217
1238
|
date_range_start: str = "",
|
|
@@ -1242,7 +1263,7 @@ def attribution_check(
|
|
|
1242
1263
|
)
|
|
1243
1264
|
|
|
1244
1265
|
|
|
1245
|
-
@
|
|
1266
|
+
@_tool(title="Tracking coverage audit", annotations=_READONLY, tags={"gtm"})
|
|
1246
1267
|
@_safe
|
|
1247
1268
|
def audit_event_coverage(
|
|
1248
1269
|
expected_events: list[str],
|
|
@@ -1295,7 +1316,7 @@ def audit_event_coverage(
|
|
|
1295
1316
|
)
|
|
1296
1317
|
|
|
1297
1318
|
|
|
1298
|
-
@
|
|
1319
|
+
@_tool(title="List Tag Manager accounts", annotations=_READONLY, tags={"gtm"})
|
|
1299
1320
|
@_safe
|
|
1300
1321
|
def list_gtm_accounts() -> dict:
|
|
1301
1322
|
"""List all GTM accounts the AdLoop service account / OAuth user can read.
|
|
@@ -1310,7 +1331,7 @@ def list_gtm_accounts() -> dict:
|
|
|
1310
1331
|
return _impl(current_config())
|
|
1311
1332
|
|
|
1312
1333
|
|
|
1313
|
-
@
|
|
1334
|
+
@_tool(title="List Tag Manager containers", annotations=_READONLY, tags={"gtm"})
|
|
1314
1335
|
@_safe
|
|
1315
1336
|
def list_gtm_containers(gtm_account_id: str = "") -> dict:
|
|
1316
1337
|
"""List all containers under a GTM account.
|
|
@@ -1330,7 +1351,7 @@ def list_gtm_containers(gtm_account_id: str = "") -> dict:
|
|
|
1330
1351
|
return _impl(current_config(), account_id=gtm_account_id)
|
|
1331
1352
|
|
|
1332
1353
|
|
|
1333
|
-
@
|
|
1354
|
+
@_tool(title="List Tag Manager tags", annotations=_READONLY, tags={"gtm"})
|
|
1334
1355
|
@_safe
|
|
1335
1356
|
def list_gtm_tags(gtm_account_id: str = "", gtm_container_id: str = "") -> dict:
|
|
1336
1357
|
"""List every tag in the LIVE GTM container.
|
|
@@ -1350,7 +1371,7 @@ def list_gtm_tags(gtm_account_id: str = "", gtm_container_id: str = "") -> dict:
|
|
|
1350
1371
|
)
|
|
1351
1372
|
|
|
1352
1373
|
|
|
1353
|
-
@
|
|
1374
|
+
@_tool(title="Tag Manager tag details", annotations=_READONLY, tags={"gtm"})
|
|
1354
1375
|
@_safe
|
|
1355
1376
|
def get_gtm_tag(
|
|
1356
1377
|
tag_id: str, gtm_account_id: str = "", gtm_container_id: str = ""
|
|
@@ -1375,7 +1396,7 @@ def get_gtm_tag(
|
|
|
1375
1396
|
)
|
|
1376
1397
|
|
|
1377
1398
|
|
|
1378
|
-
@
|
|
1399
|
+
@_tool(title="List Tag Manager triggers", annotations=_READONLY, tags={"gtm"})
|
|
1379
1400
|
@_safe
|
|
1380
1401
|
def list_gtm_triggers(gtm_account_id: str = "", gtm_container_id: str = "") -> dict:
|
|
1381
1402
|
"""List every trigger in the LIVE GTM container.
|
|
@@ -1395,7 +1416,7 @@ def list_gtm_triggers(gtm_account_id: str = "", gtm_container_id: str = "") -> d
|
|
|
1395
1416
|
)
|
|
1396
1417
|
|
|
1397
1418
|
|
|
1398
|
-
@
|
|
1419
|
+
@_tool(title="Tag Manager trigger details", annotations=_READONLY, tags={"gtm"})
|
|
1399
1420
|
@_safe
|
|
1400
1421
|
def get_gtm_trigger(
|
|
1401
1422
|
trigger_id: str, gtm_account_id: str = "", gtm_container_id: str = ""
|
|
@@ -1420,7 +1441,7 @@ def get_gtm_trigger(
|
|
|
1420
1441
|
)
|
|
1421
1442
|
|
|
1422
1443
|
|
|
1423
|
-
@
|
|
1444
|
+
@_tool(title="List Tag Manager variables", annotations=_READONLY, tags={"gtm"})
|
|
1424
1445
|
@_safe
|
|
1425
1446
|
def list_gtm_variables(gtm_account_id: str = "", gtm_container_id: str = "") -> dict:
|
|
1426
1447
|
"""List GTM variables — both custom and enabled built-in.
|
|
@@ -1442,7 +1463,7 @@ def list_gtm_variables(gtm_account_id: str = "", gtm_container_id: str = "") ->
|
|
|
1442
1463
|
)
|
|
1443
1464
|
|
|
1444
1465
|
|
|
1445
|
-
@
|
|
1466
|
+
@_tool(title="List Tag Manager workspaces", annotations=_READONLY, tags={"gtm"})
|
|
1446
1467
|
@_safe
|
|
1447
1468
|
def list_gtm_workspaces(gtm_account_id: str = "", gtm_container_id: str = "") -> dict:
|
|
1448
1469
|
"""List workspaces (drafts) under a GTM container.
|
|
@@ -1462,7 +1483,7 @@ def list_gtm_workspaces(gtm_account_id: str = "", gtm_container_id: str = "") ->
|
|
|
1462
1483
|
)
|
|
1463
1484
|
|
|
1464
1485
|
|
|
1465
|
-
@
|
|
1486
|
+
@_tool(title="Tag Manager workspace changes", annotations=_READONLY, tags={"gtm"})
|
|
1466
1487
|
@_safe
|
|
1467
1488
|
def get_gtm_workspace_diff(
|
|
1468
1489
|
workspace_id: str, gtm_account_id: str = "", gtm_container_id: str = ""
|
|
@@ -1489,7 +1510,7 @@ def get_gtm_workspace_diff(
|
|
|
1489
1510
|
)
|
|
1490
1511
|
|
|
1491
1512
|
|
|
1492
|
-
@
|
|
1513
|
+
@_tool(title="Tag Manager version history", annotations=_READONLY, tags={"gtm"})
|
|
1493
1514
|
@_safe
|
|
1494
1515
|
def list_gtm_versions(
|
|
1495
1516
|
gtm_account_id: str = "", gtm_container_id: str = "", page_size: int = 50
|
|
@@ -1515,7 +1536,7 @@ def list_gtm_versions(
|
|
|
1515
1536
|
)
|
|
1516
1537
|
|
|
1517
1538
|
|
|
1518
|
-
@
|
|
1539
|
+
@_tool(title="Tag Manager version details", annotations=_READONLY, tags={"gtm"})
|
|
1519
1540
|
@_safe
|
|
1520
1541
|
def get_gtm_version(
|
|
1521
1542
|
container_version_id: str, gtm_account_id: str = "", gtm_container_id: str = ""
|
|
@@ -1540,7 +1561,7 @@ def get_gtm_version(
|
|
|
1540
1561
|
)
|
|
1541
1562
|
|
|
1542
1563
|
|
|
1543
|
-
@
|
|
1564
|
+
@_tool(title="Custom Google Ads query", annotations=_READONLY, tags={"ads"})
|
|
1544
1565
|
@_safe
|
|
1545
1566
|
def run_gaql(
|
|
1546
1567
|
query: str,
|
|
@@ -1570,7 +1591,7 @@ def run_gaql(
|
|
|
1570
1591
|
# ---------------------------------------------------------------------------
|
|
1571
1592
|
|
|
1572
1593
|
|
|
1573
|
-
@
|
|
1594
|
+
@_tool(title="Draft a campaign", annotations=_WRITE, tags={"ads"})
|
|
1574
1595
|
@_safe
|
|
1575
1596
|
def draft_campaign(
|
|
1576
1597
|
campaign_name: str,
|
|
@@ -1637,7 +1658,7 @@ def draft_campaign(
|
|
|
1637
1658
|
)
|
|
1638
1659
|
|
|
1639
1660
|
|
|
1640
|
-
@
|
|
1661
|
+
@_tool(title="Draft an ad group", annotations=_WRITE, tags={"ads"})
|
|
1641
1662
|
@_safe
|
|
1642
1663
|
def draft_ad_group(
|
|
1643
1664
|
campaign_id: str,
|
|
@@ -1670,7 +1691,7 @@ def draft_ad_group(
|
|
|
1670
1691
|
)
|
|
1671
1692
|
|
|
1672
1693
|
|
|
1673
|
-
@
|
|
1694
|
+
@_tool(title="Draft campaign changes", annotations=_WRITE, tags={"ads"})
|
|
1674
1695
|
@_safe
|
|
1675
1696
|
def update_campaign(
|
|
1676
1697
|
campaign_id: str,
|
|
@@ -1727,7 +1748,7 @@ def update_campaign(
|
|
|
1727
1748
|
)
|
|
1728
1749
|
|
|
1729
1750
|
|
|
1730
|
-
@
|
|
1751
|
+
@_tool(title="Draft a responsive search ad", annotations=_WRITE, tags={"ads"})
|
|
1731
1752
|
@_safe
|
|
1732
1753
|
def draft_responsive_search_ad(
|
|
1733
1754
|
ad_group_id: str,
|
|
@@ -1770,7 +1791,7 @@ def draft_responsive_search_ad(
|
|
|
1770
1791
|
)
|
|
1771
1792
|
|
|
1772
1793
|
|
|
1773
|
-
@
|
|
1794
|
+
@_tool(title="Update a responsive search ad", annotations=_WRITE, tags={"ads"})
|
|
1774
1795
|
@_safe
|
|
1775
1796
|
def update_responsive_search_ad(
|
|
1776
1797
|
ad_id: str,
|
|
@@ -1829,7 +1850,7 @@ def update_responsive_search_ad(
|
|
|
1829
1850
|
)
|
|
1830
1851
|
|
|
1831
1852
|
|
|
1832
|
-
@
|
|
1853
|
+
@_tool(title="Draft keywords", annotations=_WRITE, tags={"ads"})
|
|
1833
1854
|
@_safe
|
|
1834
1855
|
def draft_keywords(
|
|
1835
1856
|
ad_group_id: str,
|
|
@@ -1851,7 +1872,7 @@ def draft_keywords(
|
|
|
1851
1872
|
)
|
|
1852
1873
|
|
|
1853
1874
|
|
|
1854
|
-
@
|
|
1875
|
+
@_tool(title="Custom conversion goals", annotations=_READONLY, tags={"ads"})
|
|
1855
1876
|
@_safe
|
|
1856
1877
|
def get_custom_conversion_goals(
|
|
1857
1878
|
campaign_id: str = "",
|
|
@@ -1880,7 +1901,7 @@ def get_custom_conversion_goals(
|
|
|
1880
1901
|
)
|
|
1881
1902
|
|
|
1882
1903
|
|
|
1883
|
-
@
|
|
1904
|
+
@_tool(
|
|
1884
1905
|
title="Draft a custom conversion goal",
|
|
1885
1906
|
annotations=_WRITE,
|
|
1886
1907
|
tags={"ads"},
|
|
@@ -1924,7 +1945,7 @@ def draft_custom_conversion_goal(
|
|
|
1924
1945
|
)
|
|
1925
1946
|
|
|
1926
1947
|
|
|
1927
|
-
@
|
|
1948
|
+
@_tool(
|
|
1928
1949
|
title="Draft changes to a custom conversion goal",
|
|
1929
1950
|
annotations=_WRITE,
|
|
1930
1951
|
tags={"ads"},
|
|
@@ -1962,7 +1983,7 @@ def draft_update_custom_conversion_goal(
|
|
|
1962
1983
|
)
|
|
1963
1984
|
|
|
1964
1985
|
|
|
1965
|
-
@
|
|
1986
|
+
@_tool(
|
|
1966
1987
|
title="Draft assigning a custom conversion goal",
|
|
1967
1988
|
annotations=_WRITE,
|
|
1968
1989
|
tags={"ads"},
|
|
@@ -2005,7 +2026,7 @@ def draft_assign_custom_conversion_goal(
|
|
|
2005
2026
|
)
|
|
2006
2027
|
|
|
2007
2028
|
|
|
2008
|
-
@
|
|
2029
|
+
@_tool(
|
|
2009
2030
|
title="Draft clearing a custom conversion goal",
|
|
2010
2031
|
annotations=_WRITE,
|
|
2011
2032
|
tags={"ads"},
|
|
@@ -2036,7 +2057,7 @@ def draft_clear_custom_conversion_goal(
|
|
|
2036
2057
|
)
|
|
2037
2058
|
|
|
2038
2059
|
|
|
2039
|
-
@
|
|
2060
|
+
@_tool(title="Draft negative keywords", annotations=_WRITE, tags={"ads"})
|
|
2040
2061
|
@_safe
|
|
2041
2062
|
def add_negative_keywords(
|
|
2042
2063
|
campaign_id: str,
|
|
@@ -2061,7 +2082,7 @@ def add_negative_keywords(
|
|
|
2061
2082
|
)
|
|
2062
2083
|
|
|
2063
2084
|
|
|
2064
|
-
@
|
|
2085
|
+
@_tool(title="Draft negative locations", annotations=_WRITE, tags={"ads"})
|
|
2065
2086
|
@_safe
|
|
2066
2087
|
def add_negative_locations(
|
|
2067
2088
|
campaign_id: str,
|
|
@@ -2085,7 +2106,7 @@ def add_negative_locations(
|
|
|
2085
2106
|
)
|
|
2086
2107
|
|
|
2087
2108
|
|
|
2088
|
-
@
|
|
2109
|
+
@_tool(
|
|
2089
2110
|
title="Draft a shared negative keyword list",
|
|
2090
2111
|
annotations=_WRITE,
|
|
2091
2112
|
tags={"ads"},
|
|
@@ -2117,7 +2138,7 @@ def propose_negative_keyword_list(
|
|
|
2117
2138
|
)
|
|
2118
2139
|
|
|
2119
2140
|
|
|
2120
|
-
@
|
|
2141
|
+
@_tool(
|
|
2121
2142
|
title="Draft additions to a negative keyword list",
|
|
2122
2143
|
annotations=_WRITE,
|
|
2123
2144
|
tags={"ads"},
|
|
@@ -2154,7 +2175,7 @@ def add_to_negative_keyword_list(
|
|
|
2154
2175
|
)
|
|
2155
2176
|
|
|
2156
2177
|
|
|
2157
|
-
@
|
|
2178
|
+
@_tool(title="Draft attaching a shared set", annotations=_WRITE, tags={"ads"})
|
|
2158
2179
|
@_safe
|
|
2159
2180
|
def attach_shared_set_to_campaigns(
|
|
2160
2181
|
shared_set_id: str,
|
|
@@ -2185,7 +2206,7 @@ def attach_shared_set_to_campaigns(
|
|
|
2185
2206
|
)
|
|
2186
2207
|
|
|
2187
2208
|
|
|
2188
|
-
@
|
|
2209
|
+
@_tool(title="Draft detaching a shared set", annotations=_WRITE, tags={"ads"})
|
|
2189
2210
|
@_safe
|
|
2190
2211
|
def detach_shared_set_from_campaigns(
|
|
2191
2212
|
shared_set_id: str,
|
|
@@ -2216,7 +2237,7 @@ def detach_shared_set_from_campaigns(
|
|
|
2216
2237
|
)
|
|
2217
2238
|
|
|
2218
2239
|
|
|
2219
|
-
@
|
|
2240
|
+
@_tool(title="AI Max settings", annotations=_READONLY, tags={"ads"})
|
|
2220
2241
|
@_safe
|
|
2221
2242
|
def get_ai_max_settings(
|
|
2222
2243
|
campaign_id: str = "",
|
|
@@ -2246,7 +2267,7 @@ def get_ai_max_settings(
|
|
|
2246
2267
|
campaign_id=campaign_id,
|
|
2247
2268
|
)
|
|
2248
2269
|
|
|
2249
|
-
@
|
|
2270
|
+
@_tool(title="Draft AI Max settings", annotations=_WRITE, tags={"ads"})
|
|
2250
2271
|
@_safe
|
|
2251
2272
|
def draft_ai_max_settings(
|
|
2252
2273
|
campaign_id: str,
|
|
@@ -2311,7 +2332,7 @@ def draft_ai_max_settings(
|
|
|
2311
2332
|
)
|
|
2312
2333
|
|
|
2313
2334
|
|
|
2314
|
-
@
|
|
2335
|
+
@_tool(
|
|
2315
2336
|
title="Prepare a campaign for brand exclusions",
|
|
2316
2337
|
annotations=_WRITE,
|
|
2317
2338
|
tags={"ads"},
|
|
@@ -2354,7 +2375,7 @@ def draft_prepare_brand_exclusions(
|
|
|
2354
2375
|
include_paused_ad_groups=include_paused_ad_groups,
|
|
2355
2376
|
)
|
|
2356
2377
|
|
|
2357
|
-
@
|
|
2378
|
+
@_tool(title="Draft demographic targeting", annotations=_WRITE, tags={"ads"})
|
|
2358
2379
|
@_safe
|
|
2359
2380
|
def draft_demographic_targeting(
|
|
2360
2381
|
customer_id: str = "",
|
|
@@ -2406,7 +2427,7 @@ def draft_demographic_targeting(
|
|
|
2406
2427
|
)
|
|
2407
2428
|
|
|
2408
2429
|
|
|
2409
|
-
@
|
|
2430
|
+
@_tool(title="Draft ad group changes", annotations=_WRITE, tags={"ads"})
|
|
2410
2431
|
@_safe
|
|
2411
2432
|
def update_ad_group(
|
|
2412
2433
|
ad_group_id: str,
|
|
@@ -2426,7 +2447,7 @@ def update_ad_group(
|
|
|
2426
2447
|
)
|
|
2427
2448
|
|
|
2428
2449
|
|
|
2429
|
-
@
|
|
2450
|
+
@_tool(title="Draft callouts", annotations=_WRITE, tags={"ads"})
|
|
2430
2451
|
@_safe
|
|
2431
2452
|
def draft_callouts(
|
|
2432
2453
|
campaign_id: str,
|
|
@@ -2444,7 +2465,7 @@ def draft_callouts(
|
|
|
2444
2465
|
)
|
|
2445
2466
|
|
|
2446
2467
|
|
|
2447
|
-
@
|
|
2468
|
+
@_tool(title="Draft structured snippets", annotations=_WRITE, tags={"ads"})
|
|
2448
2469
|
@_safe
|
|
2449
2470
|
def draft_structured_snippets(
|
|
2450
2471
|
campaign_id: str,
|
|
@@ -2462,7 +2483,7 @@ def draft_structured_snippets(
|
|
|
2462
2483
|
)
|
|
2463
2484
|
|
|
2464
2485
|
|
|
2465
|
-
@
|
|
2486
|
+
@_tool(title="Draft image assets", annotations=_WRITE, tags={"ads"})
|
|
2466
2487
|
@_safe
|
|
2467
2488
|
def draft_image_assets(
|
|
2468
2489
|
campaign_id: str,
|
|
@@ -2496,7 +2517,7 @@ def draft_image_assets(
|
|
|
2496
2517
|
)
|
|
2497
2518
|
|
|
2498
2519
|
|
|
2499
|
-
@
|
|
2520
|
+
@_tool(title="Draft pausing an entity", annotations=_WRITE, tags={"ads"})
|
|
2500
2521
|
@_safe
|
|
2501
2522
|
def pause_entity(
|
|
2502
2523
|
entity_type: str,
|
|
@@ -2524,7 +2545,7 @@ def pause_entity(
|
|
|
2524
2545
|
)
|
|
2525
2546
|
|
|
2526
2547
|
|
|
2527
|
-
@
|
|
2548
|
+
@_tool(title="Draft enabling an entity", annotations=_WRITE, tags={"ads"})
|
|
2528
2549
|
@_safe
|
|
2529
2550
|
def enable_entity(
|
|
2530
2551
|
entity_type: str,
|
|
@@ -2552,7 +2573,7 @@ def enable_entity(
|
|
|
2552
2573
|
)
|
|
2553
2574
|
|
|
2554
2575
|
|
|
2555
|
-
@
|
|
2576
|
+
@_tool(title="Draft removing an entity", annotations=_DESTRUCTIVE, tags={"ads"})
|
|
2556
2577
|
@_safe
|
|
2557
2578
|
def remove_entity(
|
|
2558
2579
|
entity_type: str,
|
|
@@ -2588,7 +2609,7 @@ def remove_entity(
|
|
|
2588
2609
|
)
|
|
2589
2610
|
|
|
2590
2611
|
|
|
2591
|
-
@
|
|
2612
|
+
@_tool(title="Draft sitelinks", annotations=_WRITE, tags={"ads"})
|
|
2592
2613
|
@_safe
|
|
2593
2614
|
def draft_sitelinks(
|
|
2594
2615
|
campaign_id: str,
|
|
@@ -2621,7 +2642,7 @@ def draft_sitelinks(
|
|
|
2621
2642
|
)
|
|
2622
2643
|
|
|
2623
2644
|
|
|
2624
|
-
@
|
|
2645
|
+
@_tool(title="Apply a previewed change", annotations=_DESTRUCTIVE, tags={"core"})
|
|
2625
2646
|
@_safe
|
|
2626
2647
|
def confirm_and_apply(
|
|
2627
2648
|
plan_id: str,
|
|
@@ -2633,14 +2654,12 @@ def confirm_and_apply(
|
|
|
2633
2654
|
to make real changes to the ad account (Google Ads or Reddit Ads — the
|
|
2634
2655
|
plan knows which platform it targets).
|
|
2635
2656
|
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
user edits the config file, sets 'require_dry_run: false', and restarts
|
|
2643
|
-
the AdLoop MCP server.
|
|
2657
|
+
Forced dry runs: when real changes are switched off (live changes off
|
|
2658
|
+
for the workspace in AdLoop Cloud, or safety.require_dry_run in a
|
|
2659
|
+
self-hosted config), dry_run=false is IGNORED and the result is still
|
|
2660
|
+
DRY_RUN_SUCCESS, with 'dry_run_forced_by' and 'remediation' fields.
|
|
2661
|
+
Pass the remediation on to the user and stop retrying: calling again
|
|
2662
|
+
with dry_run=false changes nothing until that setting is changed.
|
|
2644
2663
|
|
|
2645
2664
|
Two-phase apply: if 'safety.two_phase_apply: true' is set (always on
|
|
2646
2665
|
for AdLoop Cloud tenants), dry_run=false is REFUSED with status
|
|
@@ -2676,7 +2695,7 @@ def _reddit_account(ad_account_id: str) -> str:
|
|
|
2676
2695
|
return ad_account_id or current_config().reddit.ad_account_id
|
|
2677
2696
|
|
|
2678
2697
|
|
|
2679
|
-
@
|
|
2698
|
+
@_tool(title="List Reddit ad accounts", annotations=_READONLY, tags={"reddit"})
|
|
2680
2699
|
@_safe
|
|
2681
2700
|
def list_reddit_accounts() -> dict:
|
|
2682
2701
|
"""List Reddit businesses and ad accounts the connected Reddit user can access.
|
|
@@ -2690,7 +2709,7 @@ def list_reddit_accounts() -> dict:
|
|
|
2690
2709
|
return _impl(current_config())
|
|
2691
2710
|
|
|
2692
2711
|
|
|
2693
|
-
@
|
|
2712
|
+
@_tool(
|
|
2694
2713
|
title="Reddit billing + posting profiles", annotations=_READONLY, tags={"reddit"}
|
|
2695
2714
|
)
|
|
2696
2715
|
@_safe
|
|
@@ -2705,7 +2724,7 @@ def list_reddit_funding_instruments(ad_account_id: str = "") -> dict:
|
|
|
2705
2724
|
return _impl(current_config(), ad_account_id=_reddit_account(ad_account_id))
|
|
2706
2725
|
|
|
2707
2726
|
|
|
2708
|
-
@
|
|
2727
|
+
@_tool(title="Reddit campaigns", annotations=_READONLY, tags={"reddit"})
|
|
2709
2728
|
@_safe
|
|
2710
2729
|
def get_reddit_campaigns(ad_account_id: str = "", include_archived: bool = False) -> dict:
|
|
2711
2730
|
"""List Reddit campaigns with status, objective, budget mode and bids.
|
|
@@ -2724,7 +2743,7 @@ def get_reddit_campaigns(ad_account_id: str = "", include_archived: bool = False
|
|
|
2724
2743
|
)
|
|
2725
2744
|
|
|
2726
2745
|
|
|
2727
|
-
@
|
|
2746
|
+
@_tool(title="Reddit ad groups", annotations=_READONLY, tags={"reddit"})
|
|
2728
2747
|
@_safe
|
|
2729
2748
|
def get_reddit_ad_groups(ad_account_id: str = "", campaign_id: str = "") -> dict:
|
|
2730
2749
|
"""List Reddit ad groups (budget, bid, pixel, weekly schedule, targeting summary), optionally per campaign.
|
|
@@ -2741,7 +2760,7 @@ def get_reddit_ad_groups(ad_account_id: str = "", campaign_id: str = "") -> dict
|
|
|
2741
2760
|
)
|
|
2742
2761
|
|
|
2743
2762
|
|
|
2744
|
-
@
|
|
2763
|
+
@_tool(title="Reddit ads", annotations=_READONLY, tags={"reddit"})
|
|
2745
2764
|
@_safe
|
|
2746
2765
|
def get_reddit_ads(
|
|
2747
2766
|
ad_account_id: str = "",
|
|
@@ -2767,7 +2786,7 @@ def get_reddit_ads(
|
|
|
2767
2786
|
)
|
|
2768
2787
|
|
|
2769
2788
|
|
|
2770
|
-
@
|
|
2789
|
+
@_tool(title="Reddit performance", annotations=_READONLY, tags={"reddit"})
|
|
2771
2790
|
@_safe
|
|
2772
2791
|
def get_reddit_performance(
|
|
2773
2792
|
ad_account_id: str = "",
|
|
@@ -2803,7 +2822,7 @@ def get_reddit_performance(
|
|
|
2803
2822
|
)
|
|
2804
2823
|
|
|
2805
2824
|
|
|
2806
|
-
@
|
|
2825
|
+
@_tool(title="Raw Reddit report", annotations=_READONLY, tags={"reddit"})
|
|
2807
2826
|
@_safe
|
|
2808
2827
|
def run_reddit_report(
|
|
2809
2828
|
fields: _StrList,
|
|
@@ -2839,7 +2858,7 @@ def run_reddit_report(
|
|
|
2839
2858
|
)
|
|
2840
2859
|
|
|
2841
2860
|
|
|
2842
|
-
@
|
|
2861
|
+
@_tool(title="Reddit pixels", annotations=_READONLY, tags={"reddit"})
|
|
2843
2862
|
@_safe
|
|
2844
2863
|
def get_reddit_pixels(ad_account_id: str = "") -> dict:
|
|
2845
2864
|
"""Reddit pixels of the account and when each event (purchase, sign_up, lead, ...) last fired.
|
|
@@ -2853,7 +2872,7 @@ def get_reddit_pixels(ad_account_id: str = "") -> dict:
|
|
|
2853
2872
|
return _impl(current_config(), ad_account_id=_reddit_account(ad_account_id))
|
|
2854
2873
|
|
|
2855
2874
|
|
|
2856
|
-
@
|
|
2875
|
+
@_tool(title="Search Reddit targeting", annotations=_READONLY, tags={"reddit"})
|
|
2857
2876
|
@_safe
|
|
2858
2877
|
def search_reddit_targeting(
|
|
2859
2878
|
kind: str, query: str = "", country: str = "", website_url: str = "", limit: int = 25
|
|
@@ -2875,7 +2894,7 @@ def search_reddit_targeting(
|
|
|
2875
2894
|
)
|
|
2876
2895
|
|
|
2877
2896
|
|
|
2878
|
-
@
|
|
2897
|
+
@_tool(title="Reddit account change history", annotations=_READONLY, tags={"reddit"})
|
|
2879
2898
|
@_safe
|
|
2880
2899
|
def get_reddit_account_history(
|
|
2881
2900
|
ad_account_id: str = "",
|
|
@@ -2906,7 +2925,7 @@ def get_reddit_account_history(
|
|
|
2906
2925
|
)
|
|
2907
2926
|
|
|
2908
2927
|
|
|
2909
|
-
@
|
|
2928
|
+
@_tool(title="Estimate a Reddit ad group", annotations=_READONLY, tags={"reddit"})
|
|
2910
2929
|
@_safe
|
|
2911
2930
|
def estimate_reddit_ad_group(
|
|
2912
2931
|
daily_budget: float | None = None,
|
|
@@ -2966,7 +2985,7 @@ def estimate_reddit_ad_group(
|
|
|
2966
2985
|
)
|
|
2967
2986
|
|
|
2968
2987
|
|
|
2969
|
-
@
|
|
2988
|
+
@_tool(title="Draft pausing a Reddit entity", annotations=_WRITE, tags={"reddit"})
|
|
2970
2989
|
@_safe
|
|
2971
2990
|
def pause_reddit_entity(
|
|
2972
2991
|
entity_type: str, entity_id: str, ad_account_id: str = ""
|
|
@@ -2986,7 +3005,7 @@ def pause_reddit_entity(
|
|
|
2986
3005
|
)
|
|
2987
3006
|
|
|
2988
3007
|
|
|
2989
|
-
@
|
|
3008
|
+
@_tool(title="Draft enabling a Reddit entity", annotations=_WRITE, tags={"reddit"})
|
|
2990
3009
|
@_safe
|
|
2991
3010
|
def enable_reddit_entity(
|
|
2992
3011
|
entity_type: str, entity_id: str, ad_account_id: str = ""
|
|
@@ -3006,7 +3025,7 @@ def enable_reddit_entity(
|
|
|
3006
3025
|
)
|
|
3007
3026
|
|
|
3008
3027
|
|
|
3009
|
-
@
|
|
3028
|
+
@_tool(title="Draft archiving a Reddit entity", annotations=_DESTRUCTIVE, tags={"reddit"})
|
|
3010
3029
|
@_safe
|
|
3011
3030
|
def remove_reddit_entity(
|
|
3012
3031
|
entity_type: str, entity_id: str, ad_account_id: str = ""
|
|
@@ -3027,7 +3046,7 @@ def remove_reddit_entity(
|
|
|
3027
3046
|
)
|
|
3028
3047
|
|
|
3029
3048
|
|
|
3030
|
-
@
|
|
3049
|
+
@_tool(title="Draft Reddit campaign changes", annotations=_WRITE, tags={"reddit"})
|
|
3031
3050
|
@_safe
|
|
3032
3051
|
def update_reddit_campaign(
|
|
3033
3052
|
campaign_id: str,
|
|
@@ -3075,7 +3094,7 @@ def update_reddit_campaign(
|
|
|
3075
3094
|
)
|
|
3076
3095
|
|
|
3077
3096
|
|
|
3078
|
-
@
|
|
3097
|
+
@_tool(title="Draft Reddit ad group changes", annotations=_WRITE, tags={"reddit"})
|
|
3079
3098
|
@_safe
|
|
3080
3099
|
def update_reddit_ad_group(
|
|
3081
3100
|
ad_group_id: str,
|
|
@@ -3146,7 +3165,7 @@ def update_reddit_ad_group(
|
|
|
3146
3165
|
)
|
|
3147
3166
|
|
|
3148
3167
|
|
|
3149
|
-
@
|
|
3168
|
+
@_tool(title="Draft Reddit ad changes", annotations=_WRITE, tags={"reddit"})
|
|
3150
3169
|
@_safe
|
|
3151
3170
|
def update_reddit_ad(
|
|
3152
3171
|
ad_id: str,
|
|
@@ -3173,7 +3192,7 @@ def update_reddit_ad(
|
|
|
3173
3192
|
)
|
|
3174
3193
|
|
|
3175
3194
|
|
|
3176
|
-
@
|
|
3195
|
+
@_tool(title="Draft a Reddit campaign", annotations=_WRITE, tags={"reddit"})
|
|
3177
3196
|
@_safe
|
|
3178
3197
|
def draft_reddit_campaign(
|
|
3179
3198
|
campaign_name: str,
|
|
@@ -3232,7 +3251,7 @@ def draft_reddit_campaign(
|
|
|
3232
3251
|
)
|
|
3233
3252
|
|
|
3234
3253
|
|
|
3235
|
-
@
|
|
3254
|
+
@_tool(title="Draft a Reddit ad group", annotations=_WRITE, tags={"reddit"})
|
|
3236
3255
|
@_safe
|
|
3237
3256
|
def draft_reddit_ad_group(
|
|
3238
3257
|
campaign_id: str,
|
|
@@ -3313,7 +3332,7 @@ def draft_reddit_ad_group(
|
|
|
3313
3332
|
)
|
|
3314
3333
|
|
|
3315
3334
|
|
|
3316
|
-
@
|
|
3335
|
+
@_tool(title="Draft a Reddit ad", annotations=_WRITE, tags={"reddit"})
|
|
3317
3336
|
@_safe
|
|
3318
3337
|
def draft_reddit_ad(
|
|
3319
3338
|
ad_group_id: str,
|
|
@@ -3369,7 +3388,7 @@ def draft_reddit_ad(
|
|
|
3369
3388
|
# ---------------------------------------------------------------------------
|
|
3370
3389
|
|
|
3371
3390
|
|
|
3372
|
-
@
|
|
3391
|
+
@_tool(title="Draft an Analytics key event", annotations=_WRITE, tags={"ga4"})
|
|
3373
3392
|
@_safe
|
|
3374
3393
|
def draft_key_event(
|
|
3375
3394
|
event_name: str,
|
|
@@ -3394,7 +3413,7 @@ def draft_key_event(
|
|
|
3394
3413
|
)
|
|
3395
3414
|
|
|
3396
3415
|
|
|
3397
|
-
@
|
|
3416
|
+
@_tool(title="Draft a conversion action", annotations=_WRITE, tags={"ads"})
|
|
3398
3417
|
@_safe
|
|
3399
3418
|
def draft_create_conversion_action(
|
|
3400
3419
|
name: str,
|
|
@@ -3447,7 +3466,7 @@ def draft_create_conversion_action(
|
|
|
3447
3466
|
)
|
|
3448
3467
|
|
|
3449
3468
|
|
|
3450
|
-
@
|
|
3469
|
+
@_tool(title="Draft conversion action changes", annotations=_WRITE, tags={"ads"})
|
|
3451
3470
|
@_safe
|
|
3452
3471
|
def draft_update_conversion_action(
|
|
3453
3472
|
conversion_action_id: str,
|
|
@@ -3494,7 +3513,7 @@ def draft_update_conversion_action(
|
|
|
3494
3513
|
)
|
|
3495
3514
|
|
|
3496
3515
|
|
|
3497
|
-
@
|
|
3516
|
+
@_tool(title="Draft removing a conversion action", annotations=_WRITE, tags={"ads"})
|
|
3498
3517
|
@_safe
|
|
3499
3518
|
def draft_remove_conversion_action(
|
|
3500
3519
|
conversion_action_id: str,
|
|
@@ -3518,7 +3537,7 @@ def draft_remove_conversion_action(
|
|
|
3518
3537
|
)
|
|
3519
3538
|
|
|
3520
3539
|
|
|
3521
|
-
@
|
|
3540
|
+
@_tool(title="Validate tracking", annotations=_READONLY, tags={"tracking"})
|
|
3522
3541
|
@_safe
|
|
3523
3542
|
def validate_tracking(
|
|
3524
3543
|
expected_events: _StrList,
|
|
@@ -3546,7 +3565,7 @@ def validate_tracking(
|
|
|
3546
3565
|
)
|
|
3547
3566
|
|
|
3548
3567
|
|
|
3549
|
-
@
|
|
3568
|
+
@_tool(title="Generate tracking code", annotations=_READONLY, tags={"tracking"})
|
|
3550
3569
|
@_safe
|
|
3551
3570
|
def generate_tracking_code(
|
|
3552
3571
|
event_name: str,
|
|
@@ -3581,7 +3600,7 @@ def generate_tracking_code(
|
|
|
3581
3600
|
# ---------------------------------------------------------------------------
|
|
3582
3601
|
|
|
3583
3602
|
|
|
3584
|
-
@
|
|
3603
|
+
@_tool(title="Budget forecast", annotations=_READONLY, tags={"ads"})
|
|
3585
3604
|
@_safe
|
|
3586
3605
|
def estimate_budget(
|
|
3587
3606
|
keywords: _DictList,
|
|
@@ -3618,7 +3637,7 @@ def estimate_budget(
|
|
|
3618
3637
|
)
|
|
3619
3638
|
|
|
3620
3639
|
|
|
3621
|
-
@
|
|
3640
|
+
@_tool(title="Keyword ideas", annotations=_READONLY, tags={"ads"})
|
|
3622
3641
|
@_safe
|
|
3623
3642
|
def discover_keywords(
|
|
3624
3643
|
seed_keywords: _StrList = [], # noqa: B006 — mutable default required for MCP JSON schema
|
|
@@ -3666,7 +3685,7 @@ def discover_keywords(
|
|
|
3666
3685
|
# ---------------------------------------------------------------------------
|
|
3667
3686
|
|
|
3668
3687
|
|
|
3669
|
-
@
|
|
3688
|
+
@_tool(title="Suggest brands", annotations=_READONLY, tags={"ads"})
|
|
3670
3689
|
@_safe
|
|
3671
3690
|
def suggest_brands(
|
|
3672
3691
|
brand_prefix: str,
|
|
@@ -3703,7 +3722,7 @@ def suggest_brands(
|
|
|
3703
3722
|
)
|
|
3704
3723
|
|
|
3705
3724
|
|
|
3706
|
-
@
|
|
3725
|
+
@_tool(title="Check brand names", annotations=_READONLY, tags={"ads"})
|
|
3707
3726
|
@_safe
|
|
3708
3727
|
def check_brand_names(
|
|
3709
3728
|
brand_names: _StrList,
|
|
@@ -3736,7 +3755,7 @@ def check_brand_names(
|
|
|
3736
3755
|
customer_id=customer_id or current_config().ads.customer_id,
|
|
3737
3756
|
)
|
|
3738
3757
|
|
|
3739
|
-
@
|
|
3758
|
+
@_tool(title="List brand lists", annotations=_READONLY, tags={"ads"})
|
|
3740
3759
|
@_safe
|
|
3741
3760
|
def get_brand_lists(
|
|
3742
3761
|
customer_id: str = "",
|
|
@@ -3756,7 +3775,7 @@ def get_brand_lists(
|
|
|
3756
3775
|
customer_id=customer_id or current_config().ads.customer_id,
|
|
3757
3776
|
)
|
|
3758
3777
|
|
|
3759
|
-
@
|
|
3778
|
+
@_tool(title="Brands in a brand list", annotations=_READONLY, tags={"ads"})
|
|
3760
3779
|
@_safe
|
|
3761
3780
|
def get_brand_list_brands(
|
|
3762
3781
|
shared_set_id: str,
|
|
@@ -3780,7 +3799,7 @@ def get_brand_list_brands(
|
|
|
3780
3799
|
shared_set_id=shared_set_id,
|
|
3781
3800
|
)
|
|
3782
3801
|
|
|
3783
|
-
@
|
|
3802
|
+
@_tool(title="Campaigns using a brand list", annotations=_READONLY, tags={"ads"})
|
|
3784
3803
|
@_safe
|
|
3785
3804
|
def get_brand_list_campaigns(
|
|
3786
3805
|
shared_set_id: str = "",
|
|
@@ -3806,7 +3825,7 @@ def get_brand_list_campaigns(
|
|
|
3806
3825
|
shared_set_id=shared_set_id,
|
|
3807
3826
|
)
|
|
3808
3827
|
|
|
3809
|
-
@
|
|
3828
|
+
@_tool(title="Draft a brand list", annotations=_WRITE, tags={"ads"})
|
|
3810
3829
|
@_safe
|
|
3811
3830
|
def propose_brand_list(
|
|
3812
3831
|
list_name: str,
|
|
@@ -3844,7 +3863,7 @@ def propose_brand_list(
|
|
|
3844
3863
|
negative=negative,
|
|
3845
3864
|
)
|
|
3846
3865
|
|
|
3847
|
-
@
|
|
3866
|
+
@_tool(title="Draft additions to a brand list", annotations=_WRITE, tags={"ads"})
|
|
3848
3867
|
@_safe
|
|
3849
3868
|
def add_to_brand_list(
|
|
3850
3869
|
shared_set_id: str,
|
|
@@ -3874,7 +3893,7 @@ def add_to_brand_list(
|
|
|
3874
3893
|
brand_ids=brand_ids,
|
|
3875
3894
|
)
|
|
3876
3895
|
|
|
3877
|
-
@
|
|
3896
|
+
@_tool(title="Draft removing brands from a list", annotations=_DESTRUCTIVE, tags={"ads"})
|
|
3878
3897
|
@_safe
|
|
3879
3898
|
def remove_from_brand_list(
|
|
3880
3899
|
shared_set_id: str,
|
|
@@ -3904,7 +3923,7 @@ def remove_from_brand_list(
|
|
|
3904
3923
|
criterion_ids=criterion_ids,
|
|
3905
3924
|
)
|
|
3906
3925
|
|
|
3907
|
-
@
|
|
3926
|
+
@_tool(title="Draft attaching a brand list", annotations=_WRITE, tags={"ads"})
|
|
3908
3927
|
@_safe
|
|
3909
3928
|
def attach_brand_list_to_campaigns(
|
|
3910
3929
|
shared_set_id: str,
|
|
@@ -3941,7 +3960,7 @@ def attach_brand_list_to_campaigns(
|
|
|
3941
3960
|
negative=negative,
|
|
3942
3961
|
)
|
|
3943
3962
|
|
|
3944
|
-
@
|
|
3963
|
+
@_tool(title="Draft detaching a brand list", annotations=_DESTRUCTIVE, tags={"ads"})
|
|
3945
3964
|
@_safe
|
|
3946
3965
|
def detach_brand_list_from_campaigns(
|
|
3947
3966
|
shared_set_id: str,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|