adloop 0.13.3__tar.gz → 0.14.0__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.13.3/README.md → adloop-0.14.0/PKG-INFO +61 -3
- adloop-0.13.3/PKG-INFO → adloop-0.14.0/README.md +34 -29
- {adloop-0.13.3 → adloop-0.14.0}/pyproject.toml +4 -2
- {adloop-0.13.3 → adloop-0.14.0}/pyproject.toml.orig +6 -3
- adloop-0.14.0/src/adloop/ads/conversion_actions.py +558 -0
- {adloop-0.13.3 → adloop-0.14.0}/src/adloop/ads/write.py +339 -20
- {adloop-0.13.3 → adloop-0.14.0}/src/adloop/auth.py +23 -0
- {adloop-0.13.3 → adloop-0.14.0}/src/adloop/cli.py +110 -0
- {adloop-0.13.3 → adloop-0.14.0}/src/adloop/config.py +27 -0
- adloop-0.14.0/src/adloop/reddit/__init__.py +9 -0
- adloop-0.14.0/src/adloop/reddit/auth.py +504 -0
- adloop-0.14.0/src/adloop/reddit/client.py +270 -0
- adloop-0.14.0/src/adloop/reddit/read.py +1344 -0
- adloop-0.14.0/src/adloop/reddit/schedule.py +200 -0
- adloop-0.14.0/src/adloop/reddit/write.py +1684 -0
- {adloop-0.13.3 → adloop-0.14.0}/src/adloop/rules/adloop.md +75 -7
- {adloop-0.13.3 → adloop-0.14.0}/src/adloop/safety/preview.py +4 -0
- {adloop-0.13.3 → adloop-0.14.0}/src/adloop/server.py +1006 -5
- {adloop-0.13.3 → adloop-0.14.0}/src/adloop/__init__.py +0 -0
- {adloop-0.13.3 → adloop-0.14.0}/src/adloop/__main__.py +0 -0
- {adloop-0.13.3 → adloop-0.14.0}/src/adloop/_mcp_patches.py +0 -0
- {adloop-0.13.3 → adloop-0.14.0}/src/adloop/ads/__init__.py +0 -0
- {adloop-0.13.3 → adloop-0.14.0}/src/adloop/ads/client.py +0 -0
- {adloop-0.13.3 → adloop-0.14.0}/src/adloop/ads/currency.py +0 -0
- {adloop-0.13.3 → adloop-0.14.0}/src/adloop/ads/enums.py +0 -0
- {adloop-0.13.3 → adloop-0.14.0}/src/adloop/ads/forecast.py +0 -0
- {adloop-0.13.3 → adloop-0.14.0}/src/adloop/ads/gaql.py +0 -0
- {adloop-0.13.3 → adloop-0.14.0}/src/adloop/ads/pmax.py +0 -0
- {adloop-0.13.3 → adloop-0.14.0}/src/adloop/ads/read.py +0 -0
- {adloop-0.13.3 → adloop-0.14.0}/src/adloop/crossref.py +0 -0
- {adloop-0.13.3 → adloop-0.14.0}/src/adloop/diagnostics.py +0 -0
- {adloop-0.13.3 → adloop-0.14.0}/src/adloop/ga4/__init__.py +0 -0
- {adloop-0.13.3 → adloop-0.14.0}/src/adloop/ga4/client.py +0 -0
- {adloop-0.13.3 → adloop-0.14.0}/src/adloop/ga4/reports.py +0 -0
- {adloop-0.13.3 → adloop-0.14.0}/src/adloop/ga4/tracking.py +0 -0
- {adloop-0.13.3 → adloop-0.14.0}/src/adloop/ga4/write.py +0 -0
- {adloop-0.13.3 → adloop-0.14.0}/src/adloop/gsc/__init__.py +0 -0
- {adloop-0.13.3 → adloop-0.14.0}/src/adloop/gsc/client.py +0 -0
- {adloop-0.13.3 → adloop-0.14.0}/src/adloop/gsc/reports.py +0 -0
- {adloop-0.13.3 → adloop-0.14.0}/src/adloop/gtm/__init__.py +0 -0
- {adloop-0.13.3 → adloop-0.14.0}/src/adloop/gtm/client.py +0 -0
- {adloop-0.13.3 → adloop-0.14.0}/src/adloop/gtm/read.py +0 -0
- {adloop-0.13.3 → adloop-0.14.0}/src/adloop/merchant/__init__.py +0 -0
- {adloop-0.13.3 → adloop-0.14.0}/src/adloop/merchant/client.py +0 -0
- {adloop-0.13.3 → adloop-0.14.0}/src/adloop/merchant/read.py +0 -0
- {adloop-0.13.3 → adloop-0.14.0}/src/adloop/pagespeed.py +0 -0
- {adloop-0.13.3 → adloop-0.14.0}/src/adloop/rules/__init__.py +0 -0
- {adloop-0.13.3 → adloop-0.14.0}/src/adloop/rules/commands/analyze-performance.md +0 -0
- {adloop-0.13.3 → adloop-0.14.0}/src/adloop/rules/commands/budget-plan.md +0 -0
- {adloop-0.13.3 → adloop-0.14.0}/src/adloop/rules/commands/create-ad.md +0 -0
- {adloop-0.13.3 → adloop-0.14.0}/src/adloop/rules/commands/create-campaign.md +0 -0
- {adloop-0.13.3 → adloop-0.14.0}/src/adloop/rules/commands/diagnose-tracking.md +0 -0
- {adloop-0.13.3 → adloop-0.14.0}/src/adloop/rules/commands/optimize-campaign.md +0 -0
- {adloop-0.13.3 → adloop-0.14.0}/src/adloop/rules_install.py +0 -0
- {adloop-0.13.3 → adloop-0.14.0}/src/adloop/runtime.py +0 -0
- {adloop-0.13.3 → adloop-0.14.0}/src/adloop/safety/__init__.py +0 -0
- {adloop-0.13.3 → adloop-0.14.0}/src/adloop/safety/audit.py +0 -0
- {adloop-0.13.3 → adloop-0.14.0}/src/adloop/safety/guards.py +0 -0
- {adloop-0.13.3 → adloop-0.14.0}/src/adloop/tracking.py +0 -0
|
@@ -1,10 +1,37 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: adloop
|
|
3
|
+
Version: 0.14.0
|
|
4
|
+
Summary: The AI command center for Google Ads, Reddit Ads, GA4, and tracking code.
|
|
5
|
+
Keywords: mcp,google-ads,reddit-ads,google-analytics,ga4,cursor,marketing
|
|
6
|
+
Author: Daniel Klose
|
|
7
|
+
Author-email: Daniel Klose <info@daniel-klose.com>
|
|
8
|
+
License: MIT
|
|
9
|
+
Requires-Dist: fastmcp>=3.0.0
|
|
10
|
+
Requires-Dist: google-ads>=31.1.0
|
|
11
|
+
Requires-Dist: google-analytics-data>=0.20.0
|
|
12
|
+
Requires-Dist: google-analytics-admin>=0.27.0
|
|
13
|
+
Requires-Dist: google-api-python-client>=2.100.0
|
|
14
|
+
Requires-Dist: google-auth-oauthlib>=1.0.0
|
|
15
|
+
Requires-Dist: google-api-python-client>=2.0.0
|
|
16
|
+
Requires-Dist: pyyaml>=6.0
|
|
17
|
+
Requires-Dist: requests>=2.31
|
|
18
|
+
Requires-Dist: pytest>=8.0 ; extra == 'dev'
|
|
19
|
+
Requires-Dist: pytest-asyncio>=0.23 ; extra == 'dev'
|
|
20
|
+
Requires-Python: >=3.11
|
|
21
|
+
Project-URL: Homepage, https://github.com/kLOsk/adloop
|
|
22
|
+
Project-URL: Repository, https://github.com/kLOsk/adloop
|
|
23
|
+
Project-URL: Issues, https://github.com/kLOsk/adloop/issues
|
|
24
|
+
Project-URL: Changelog, https://github.com/kLOsk/adloop/releases
|
|
25
|
+
Provides-Extra: dev
|
|
26
|
+
Description-Content-Type: text/markdown
|
|
27
|
+
|
|
1
28
|
<!-- mcp-name: com.getadloop/adloop -->
|
|
2
29
|
|
|
3
30
|
<div align="center">
|
|
4
31
|
|
|
5
32
|
# AdLoop
|
|
6
33
|
|
|
7
|
-
**The AI command center for Google Ads, GA4, and tracking code.**
|
|
34
|
+
**The AI command center for Google Ads, Reddit Ads, GA4, and tracking code.**
|
|
8
35
|
|
|
9
36
|
[](https://pypi.org/project/adloop/)
|
|
10
37
|
[](LICENSE)
|
|
@@ -14,7 +41,7 @@
|
|
|
14
41
|
[](https://developers.google.com/analytics/devguides/reporting/data/v1)
|
|
15
42
|
[](https://github.com/kLOsk/adloop)
|
|
16
43
|
|
|
17
|
-
An MCP server that gives your AI assistant read + write access to Google Ads and GA4 — with safety guardrails that prevent accidental spend.
|
|
44
|
+
An MCP server that gives your AI assistant read + write access to Google Ads, Reddit Ads and GA4 — with safety guardrails that prevent accidental spend.
|
|
18
45
|
|
|
19
46
|
**[☁️ Skip the setup — use AdLoop Cloud (free plan, no card)](https://getadloop.com)** · or self-host: `pip install adloop`
|
|
20
47
|
|
|
@@ -171,6 +198,27 @@ These tools read the live GTM container and join it with the codebase + GA4 to f
|
|
|
171
198
|
|
|
172
199
|
> **Setup for GSC tools** — Enable the **Search Console API** in your GCP project. Upgrading OAuth users must re-authorize once for the new scope (delete `~/.adloop/token.json`, run any tool). The killer combo: cross-reference organic queries with `get_keyword_performance` to find paid/organic cannibalization and untapped keyword opportunities.
|
|
173
200
|
|
|
201
|
+
### Reddit Ads Tools
|
|
202
|
+
|
|
203
|
+
A second ad platform, same safety model. Reddit is a separate connection: its own developer app, its own OAuth, no developer token and no approval process. Every tool takes `ad_account_id` (defaults to `reddit.ad_account_id`).
|
|
204
|
+
|
|
205
|
+
| Tool | What It Does |
|
|
206
|
+
|------|-------------|
|
|
207
|
+
| `list_reddit_accounts` | Discover businesses and ad accounts (currency, time zone, approval state) |
|
|
208
|
+
| `list_reddit_funding_instruments` | Billing instruments and posting profiles — prerequisites for creating campaigns and ads |
|
|
209
|
+
| `get_reddit_campaigns` / `get_reddit_ad_groups` / `get_reddit_ads` | Structure with configured vs effective status, budgets, bids, pixel, targeting, weekly schedule, rejection reasons; `include_copy` returns each ad's post (headline, body, destination, media) |
|
|
210
|
+
| `get_reddit_performance` | Spend, clicks, CTR, CPC, conversions, CPA, ROAS per account/campaign/ad group/ad, optional breakdown (date, country, community, keyword, placement, …), compact mode with insights |
|
|
211
|
+
| `run_reddit_report` | Raw reports endpoint for any metric (REACH, video, per-event conversions) |
|
|
212
|
+
| `get_reddit_pixels` | Pixels and when each event last fired — flags ad groups optimizing for events the pixel never sent |
|
|
213
|
+
| `search_reddit_targeting` | Communities, interests, geolocations, languages, keyword suggestions, and Reddit's related-community suggestions (by seed communities or website) |
|
|
214
|
+
| `get_reddit_account_history` | Who changed what and when: field, before/after, member |
|
|
215
|
+
| `estimate_reddit_ad_group` | Audience size, delivery estimate and suggested bid range for a planned ad group (Reddit's counterpart of `estimate_budget`) |
|
|
216
|
+
| `pause_reddit_entity` / `enable_reddit_entity` / `remove_reddit_entity` | Status changes through the preview gate (remove = ARCHIVE, irreversible, double-confirmed) |
|
|
217
|
+
| `update_reddit_campaign` / `update_reddit_ad_group` / `update_reddit_ad` | Budget, bid, run dates, weekly schedule (day names, viewer-local hours), targeting and placements (validated with Reddit at draft time), landing URL and comment changes with old → new previews, budget cap and bid-increase guards |
|
|
218
|
+
| `draft_reddit_campaign` / `draft_reddit_ad_group` / `draft_reddit_ad` | Create campaign → ad group (pixel + targeting required) → post + ad, or promote an existing post with `post_id`. Everything is created **PAUSED**. |
|
|
219
|
+
|
|
220
|
+
> **Setup for Reddit Ads tools** — In Reddit Ads Manager open **Business Manager → Developer Application → Create app** (business admins only; no approval wait). Register the redirect URL exactly as `http://localhost:8765/callback`, then run `adloop init` and complete the Reddit Ads step: it opens Reddit's consent page (scopes `adsread` + `adsedit`, permanent grant), stores the refresh token at `~/.adloop/reddit_token.json`, and lets you pick the default ad account. Reddit rate-limits per user (reporting: 60 requests/min) and requires a descriptive User-Agent, which AdLoop builds from your app id and Reddit username. Reddit has no validate-only mode, so `confirm_and_apply(dry_run=true)` re-reads the target and re-checks the safety caps instead.
|
|
221
|
+
|
|
174
222
|
### Planning Tools
|
|
175
223
|
|
|
176
224
|
| Tool | What It Does |
|
|
@@ -420,6 +468,10 @@ All configuration lives in `~/.adloop/config.yaml`. See [`config.yaml.example`](
|
|
|
420
468
|
| `ads` | `developer_token` | — | Your Google Ads API developer token |
|
|
421
469
|
| `ads` | `customer_id` | — | Default Google Ads customer ID (auto-discovered by `adloop init`) |
|
|
422
470
|
| `ads` | `login_customer_id` | — | Your MCC account ID |
|
|
471
|
+
| `reddit` | `client_id` / `client_secret` | *(empty)* | Your Reddit developer app (Business Manager → Developer Application) |
|
|
472
|
+
| `reddit` | `ad_account_id` | *(empty)* | Default Reddit ad account for every Reddit tool (picked by `adloop init`) |
|
|
473
|
+
| `reddit` | `username` | *(empty)* | Your Reddit username, used only in the User-Agent Reddit requires |
|
|
474
|
+
| `reddit` | `token_path` | `~/.adloop/reddit_token.json` | Where the Reddit refresh token is stored |
|
|
423
475
|
| `safety` | `max_daily_budget` | `50.00` | Maximum allowed daily budget per campaign |
|
|
424
476
|
| `safety` | `require_dry_run` | `true` | Force all writes to dry-run mode |
|
|
425
477
|
| `safety` | `two_phase_apply` | `false` | Refuse real applies until the plan had a dry-run pass |
|
|
@@ -442,6 +494,7 @@ Most MCP clients (claude.ai, ChatGPT, Cursor, …) load **every tool schema into
|
|
|
442
494
|
| `gsc` | Search Console reads |
|
|
443
495
|
| `web` | PageSpeed / Core Web Vitals |
|
|
444
496
|
| `merchant` | Merchant Center feed health |
|
|
497
|
+
| `reddit` | Reddit Ads reads, writes, and planning |
|
|
445
498
|
|
|
446
499
|
`health_check` and `confirm_and_apply` are always included, whatever you select. Unset = the full catalog; unknown names fail at startup with the valid list. The effect is real: `ads,ga4` drops the session cost to ~13k tokens, and a `ga4`-only client pays ~2k — nearly 90% less. Toolsets are per *client*, not per install: one AdLoop config can serve a trimmed Cursor and a full-catalog Claude Code side by side.
|
|
447
500
|
|
|
@@ -452,7 +505,7 @@ On [AdLoop Cloud](https://getadloop.com), the same feature is per API key: pick
|
|
|
452
505
|
```
|
|
453
506
|
src/adloop/
|
|
454
507
|
├── __init__.py # Entry point — routes 'adloop init' to wizard, otherwise starts MCP server
|
|
455
|
-
├── server.py # FastMCP server —
|
|
508
|
+
├── server.py # FastMCP server — every tool registration with safety annotations and toolset tags
|
|
456
509
|
├── config.py # Config loader (~/.adloop/config.yaml)
|
|
457
510
|
├── auth.py # OAuth 2.0 flow (user-supplied credentials, headless fallback) + service accounts; GA4 / Ads / GTM scopes
|
|
458
511
|
├── cli.py # Interactive 'adloop init' setup wizard
|
|
@@ -472,6 +525,11 @@ src/adloop/
|
|
|
472
525
|
├── gtm/
|
|
473
526
|
│ ├── client.py # Google Tag Manager API v2 client
|
|
474
527
|
│ └── read.py # Live container fetching, tag/trigger/variable parsing, workspace diff, version history
|
|
528
|
+
├── reddit/
|
|
529
|
+
│ ├── auth.py # Reddit OAuth2 (own app, permanent refresh token, loopback flow for adloop init)
|
|
530
|
+
│ ├── client.py # Reddit Ads API v3 REST client — bearer refresh, per-user rate limits, pagination
|
|
531
|
+
│ ├── read.py # Accounts, campaigns, ad groups, ads, performance reports, pixels, targeting lookups
|
|
532
|
+
│ └── write.py # Draft/preflight/apply for status, budget, bid, targeting, and PAUSED creation
|
|
475
533
|
└── safety/
|
|
476
534
|
├── guards.py # Budget caps, bid limits, blocked operations, Broad Match safety
|
|
477
535
|
├── preview.py # Change plans and previews
|
|
@@ -1,36 +1,10 @@
|
|
|
1
|
-
Metadata-Version: 2.3
|
|
2
|
-
Name: adloop
|
|
3
|
-
Version: 0.13.3
|
|
4
|
-
Summary: The AI command center for Google Ads, GA4, and tracking code.
|
|
5
|
-
Keywords: mcp,google-ads,google-analytics,ga4,cursor,marketing
|
|
6
|
-
Author: Daniel Klose
|
|
7
|
-
Author-email: Daniel Klose <info@daniel-klose.com>
|
|
8
|
-
License: MIT
|
|
9
|
-
Requires-Dist: fastmcp>=3.0.0
|
|
10
|
-
Requires-Dist: google-ads>=31.1.0
|
|
11
|
-
Requires-Dist: google-analytics-data>=0.20.0
|
|
12
|
-
Requires-Dist: google-analytics-admin>=0.27.0
|
|
13
|
-
Requires-Dist: google-api-python-client>=2.100.0
|
|
14
|
-
Requires-Dist: google-auth-oauthlib>=1.0.0
|
|
15
|
-
Requires-Dist: google-api-python-client>=2.0.0
|
|
16
|
-
Requires-Dist: pyyaml>=6.0
|
|
17
|
-
Requires-Dist: pytest>=8.0 ; extra == 'dev'
|
|
18
|
-
Requires-Dist: pytest-asyncio>=0.23 ; extra == 'dev'
|
|
19
|
-
Requires-Python: >=3.11
|
|
20
|
-
Project-URL: Homepage, https://github.com/kLOsk/adloop
|
|
21
|
-
Project-URL: Repository, https://github.com/kLOsk/adloop
|
|
22
|
-
Project-URL: Issues, https://github.com/kLOsk/adloop/issues
|
|
23
|
-
Project-URL: Changelog, https://github.com/kLOsk/adloop/releases
|
|
24
|
-
Provides-Extra: dev
|
|
25
|
-
Description-Content-Type: text/markdown
|
|
26
|
-
|
|
27
1
|
<!-- mcp-name: com.getadloop/adloop -->
|
|
28
2
|
|
|
29
3
|
<div align="center">
|
|
30
4
|
|
|
31
5
|
# AdLoop
|
|
32
6
|
|
|
33
|
-
**The AI command center for Google Ads, GA4, and tracking code.**
|
|
7
|
+
**The AI command center for Google Ads, Reddit Ads, GA4, and tracking code.**
|
|
34
8
|
|
|
35
9
|
[](https://pypi.org/project/adloop/)
|
|
36
10
|
[](LICENSE)
|
|
@@ -40,7 +14,7 @@ Description-Content-Type: text/markdown
|
|
|
40
14
|
[](https://developers.google.com/analytics/devguides/reporting/data/v1)
|
|
41
15
|
[](https://github.com/kLOsk/adloop)
|
|
42
16
|
|
|
43
|
-
An MCP server that gives your AI assistant read + write access to Google Ads and GA4 — with safety guardrails that prevent accidental spend.
|
|
17
|
+
An MCP server that gives your AI assistant read + write access to Google Ads, Reddit Ads and GA4 — with safety guardrails that prevent accidental spend.
|
|
44
18
|
|
|
45
19
|
**[☁️ Skip the setup — use AdLoop Cloud (free plan, no card)](https://getadloop.com)** · or self-host: `pip install adloop`
|
|
46
20
|
|
|
@@ -197,6 +171,27 @@ These tools read the live GTM container and join it with the codebase + GA4 to f
|
|
|
197
171
|
|
|
198
172
|
> **Setup for GSC tools** — Enable the **Search Console API** in your GCP project. Upgrading OAuth users must re-authorize once for the new scope (delete `~/.adloop/token.json`, run any tool). The killer combo: cross-reference organic queries with `get_keyword_performance` to find paid/organic cannibalization and untapped keyword opportunities.
|
|
199
173
|
|
|
174
|
+
### Reddit Ads Tools
|
|
175
|
+
|
|
176
|
+
A second ad platform, same safety model. Reddit is a separate connection: its own developer app, its own OAuth, no developer token and no approval process. Every tool takes `ad_account_id` (defaults to `reddit.ad_account_id`).
|
|
177
|
+
|
|
178
|
+
| Tool | What It Does |
|
|
179
|
+
|------|-------------|
|
|
180
|
+
| `list_reddit_accounts` | Discover businesses and ad accounts (currency, time zone, approval state) |
|
|
181
|
+
| `list_reddit_funding_instruments` | Billing instruments and posting profiles — prerequisites for creating campaigns and ads |
|
|
182
|
+
| `get_reddit_campaigns` / `get_reddit_ad_groups` / `get_reddit_ads` | Structure with configured vs effective status, budgets, bids, pixel, targeting, weekly schedule, rejection reasons; `include_copy` returns each ad's post (headline, body, destination, media) |
|
|
183
|
+
| `get_reddit_performance` | Spend, clicks, CTR, CPC, conversions, CPA, ROAS per account/campaign/ad group/ad, optional breakdown (date, country, community, keyword, placement, …), compact mode with insights |
|
|
184
|
+
| `run_reddit_report` | Raw reports endpoint for any metric (REACH, video, per-event conversions) |
|
|
185
|
+
| `get_reddit_pixels` | Pixels and when each event last fired — flags ad groups optimizing for events the pixel never sent |
|
|
186
|
+
| `search_reddit_targeting` | Communities, interests, geolocations, languages, keyword suggestions, and Reddit's related-community suggestions (by seed communities or website) |
|
|
187
|
+
| `get_reddit_account_history` | Who changed what and when: field, before/after, member |
|
|
188
|
+
| `estimate_reddit_ad_group` | Audience size, delivery estimate and suggested bid range for a planned ad group (Reddit's counterpart of `estimate_budget`) |
|
|
189
|
+
| `pause_reddit_entity` / `enable_reddit_entity` / `remove_reddit_entity` | Status changes through the preview gate (remove = ARCHIVE, irreversible, double-confirmed) |
|
|
190
|
+
| `update_reddit_campaign` / `update_reddit_ad_group` / `update_reddit_ad` | Budget, bid, run dates, weekly schedule (day names, viewer-local hours), targeting and placements (validated with Reddit at draft time), landing URL and comment changes with old → new previews, budget cap and bid-increase guards |
|
|
191
|
+
| `draft_reddit_campaign` / `draft_reddit_ad_group` / `draft_reddit_ad` | Create campaign → ad group (pixel + targeting required) → post + ad, or promote an existing post with `post_id`. Everything is created **PAUSED**. |
|
|
192
|
+
|
|
193
|
+
> **Setup for Reddit Ads tools** — In Reddit Ads Manager open **Business Manager → Developer Application → Create app** (business admins only; no approval wait). Register the redirect URL exactly as `http://localhost:8765/callback`, then run `adloop init` and complete the Reddit Ads step: it opens Reddit's consent page (scopes `adsread` + `adsedit`, permanent grant), stores the refresh token at `~/.adloop/reddit_token.json`, and lets you pick the default ad account. Reddit rate-limits per user (reporting: 60 requests/min) and requires a descriptive User-Agent, which AdLoop builds from your app id and Reddit username. Reddit has no validate-only mode, so `confirm_and_apply(dry_run=true)` re-reads the target and re-checks the safety caps instead.
|
|
194
|
+
|
|
200
195
|
### Planning Tools
|
|
201
196
|
|
|
202
197
|
| Tool | What It Does |
|
|
@@ -446,6 +441,10 @@ All configuration lives in `~/.adloop/config.yaml`. See [`config.yaml.example`](
|
|
|
446
441
|
| `ads` | `developer_token` | — | Your Google Ads API developer token |
|
|
447
442
|
| `ads` | `customer_id` | — | Default Google Ads customer ID (auto-discovered by `adloop init`) |
|
|
448
443
|
| `ads` | `login_customer_id` | — | Your MCC account ID |
|
|
444
|
+
| `reddit` | `client_id` / `client_secret` | *(empty)* | Your Reddit developer app (Business Manager → Developer Application) |
|
|
445
|
+
| `reddit` | `ad_account_id` | *(empty)* | Default Reddit ad account for every Reddit tool (picked by `adloop init`) |
|
|
446
|
+
| `reddit` | `username` | *(empty)* | Your Reddit username, used only in the User-Agent Reddit requires |
|
|
447
|
+
| `reddit` | `token_path` | `~/.adloop/reddit_token.json` | Where the Reddit refresh token is stored |
|
|
449
448
|
| `safety` | `max_daily_budget` | `50.00` | Maximum allowed daily budget per campaign |
|
|
450
449
|
| `safety` | `require_dry_run` | `true` | Force all writes to dry-run mode |
|
|
451
450
|
| `safety` | `two_phase_apply` | `false` | Refuse real applies until the plan had a dry-run pass |
|
|
@@ -468,6 +467,7 @@ Most MCP clients (claude.ai, ChatGPT, Cursor, …) load **every tool schema into
|
|
|
468
467
|
| `gsc` | Search Console reads |
|
|
469
468
|
| `web` | PageSpeed / Core Web Vitals |
|
|
470
469
|
| `merchant` | Merchant Center feed health |
|
|
470
|
+
| `reddit` | Reddit Ads reads, writes, and planning |
|
|
471
471
|
|
|
472
472
|
`health_check` and `confirm_and_apply` are always included, whatever you select. Unset = the full catalog; unknown names fail at startup with the valid list. The effect is real: `ads,ga4` drops the session cost to ~13k tokens, and a `ga4`-only client pays ~2k — nearly 90% less. Toolsets are per *client*, not per install: one AdLoop config can serve a trimmed Cursor and a full-catalog Claude Code side by side.
|
|
473
473
|
|
|
@@ -478,7 +478,7 @@ On [AdLoop Cloud](https://getadloop.com), the same feature is per API key: pick
|
|
|
478
478
|
```
|
|
479
479
|
src/adloop/
|
|
480
480
|
├── __init__.py # Entry point — routes 'adloop init' to wizard, otherwise starts MCP server
|
|
481
|
-
├── server.py # FastMCP server —
|
|
481
|
+
├── server.py # FastMCP server — every tool registration with safety annotations and toolset tags
|
|
482
482
|
├── config.py # Config loader (~/.adloop/config.yaml)
|
|
483
483
|
├── auth.py # OAuth 2.0 flow (user-supplied credentials, headless fallback) + service accounts; GA4 / Ads / GTM scopes
|
|
484
484
|
├── cli.py # Interactive 'adloop init' setup wizard
|
|
@@ -498,6 +498,11 @@ src/adloop/
|
|
|
498
498
|
├── gtm/
|
|
499
499
|
│ ├── client.py # Google Tag Manager API v2 client
|
|
500
500
|
│ └── read.py # Live container fetching, tag/trigger/variable parsing, workspace diff, version history
|
|
501
|
+
├── reddit/
|
|
502
|
+
│ ├── auth.py # Reddit OAuth2 (own app, permanent refresh token, loopback flow for adloop init)
|
|
503
|
+
│ ├── client.py # Reddit Ads API v3 REST client — bearer refresh, per-user rate limits, pagination
|
|
504
|
+
│ ├── read.py # Accounts, campaigns, ad groups, ads, performance reports, pixels, targeting lookups
|
|
505
|
+
│ └── write.py # Draft/preflight/apply for status, budget, bid, targeting, and PAUSED creation
|
|
501
506
|
└── safety/
|
|
502
507
|
├── guards.py # Budget caps, bid limits, blocked operations, Broad Match safety
|
|
503
508
|
├── preview.py # Change plans and previews
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "adloop"
|
|
3
|
-
version = "0.
|
|
4
|
-
description = "The AI command center for Google Ads, GA4, and tracking code."
|
|
3
|
+
version = "0.14.0"
|
|
4
|
+
description = "The AI command center for Google Ads, Reddit Ads, GA4, and tracking code."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.11"
|
|
7
7
|
keywords = [
|
|
8
8
|
"mcp",
|
|
9
9
|
"google-ads",
|
|
10
|
+
"reddit-ads",
|
|
10
11
|
"google-analytics",
|
|
11
12
|
"ga4",
|
|
12
13
|
"cursor",
|
|
@@ -21,6 +22,7 @@ dependencies = [
|
|
|
21
22
|
"google-auth-oauthlib>=1.0.0",
|
|
22
23
|
"google-api-python-client>=2.0.0",
|
|
23
24
|
"pyyaml>=6.0",
|
|
25
|
+
"requests>=2.31",
|
|
24
26
|
]
|
|
25
27
|
|
|
26
28
|
[[project.authors]]
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "adloop"
|
|
3
|
-
version = "0.
|
|
4
|
-
description = "The AI command center for Google Ads, GA4, and tracking code."
|
|
3
|
+
version = "0.14.0"
|
|
4
|
+
description = "The AI command center for Google Ads, Reddit Ads, GA4, and tracking code."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
authors = [
|
|
7
7
|
{ name = "Daniel Klose", email = "info@daniel-klose.com" }
|
|
8
8
|
]
|
|
9
9
|
requires-python = ">=3.11"
|
|
10
10
|
license = { text = "MIT" }
|
|
11
|
-
keywords = ["mcp", "google-ads", "google-analytics", "ga4", "cursor", "marketing"]
|
|
11
|
+
keywords = ["mcp", "google-ads", "reddit-ads", "google-analytics", "ga4", "cursor", "marketing"]
|
|
12
12
|
dependencies = [
|
|
13
13
|
"fastmcp>=3.0.0",
|
|
14
14
|
"google-ads>=31.1.0",
|
|
@@ -18,6 +18,9 @@ dependencies = [
|
|
|
18
18
|
"google-auth-oauthlib>=1.0.0",
|
|
19
19
|
"google-api-python-client>=2.0.0",
|
|
20
20
|
"pyyaml>=6.0",
|
|
21
|
+
# Reddit Ads has no SDK; the REST client (adloop.reddit.client) and the
|
|
22
|
+
# PageSpeed helper call requests directly.
|
|
23
|
+
"requests>=2.31",
|
|
21
24
|
]
|
|
22
25
|
|
|
23
26
|
[project.urls]
|