meta-ads-mcp-python 1.0.79__py3-none-any.whl
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.
- meta_ads_mcp/__init__.py +79 -0
- meta_ads_mcp/__main__.py +10 -0
- meta_ads_mcp/core/__init__.py +55 -0
- meta_ads_mcp/core/accounts.py +141 -0
- meta_ads_mcp/core/ads.py +2751 -0
- meta_ads_mcp/core/ads_library.py +74 -0
- meta_ads_mcp/core/adsets.py +666 -0
- meta_ads_mcp/core/api.py +431 -0
- meta_ads_mcp/core/auth.py +567 -0
- meta_ads_mcp/core/authentication.py +207 -0
- meta_ads_mcp/core/budget_schedules.py +70 -0
- meta_ads_mcp/core/callback_server.py +256 -0
- meta_ads_mcp/core/campaigns.py +379 -0
- meta_ads_mcp/core/duplication.py +523 -0
- meta_ads_mcp/core/http_auth_integration.py +307 -0
- meta_ads_mcp/core/insights.py +161 -0
- meta_ads_mcp/core/mcc.py +232 -0
- meta_ads_mcp/core/openai_deep_research.py +418 -0
- meta_ads_mcp/core/pipeboard_auth.py +510 -0
- meta_ads_mcp/core/reports.py +135 -0
- meta_ads_mcp/core/resources.py +46 -0
- meta_ads_mcp/core/server.py +391 -0
- meta_ads_mcp/core/targeting.py +542 -0
- meta_ads_mcp/core/utils.py +225 -0
- meta_ads_mcp/settings.py +33 -0
- meta_ads_mcp_python-1.0.79.dist-info/METADATA +187 -0
- meta_ads_mcp_python-1.0.79.dist-info/RECORD +29 -0
- meta_ads_mcp_python-1.0.79.dist-info/WHEEL +4 -0
- meta_ads_mcp_python-1.0.79.dist-info/entry_points.txt +3 -0
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
"""Utility functions for Meta Ads API."""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import pathlib
|
|
5
|
+
import platform
|
|
6
|
+
import sys
|
|
7
|
+
from typing import Any, Dict, List, Optional
|
|
8
|
+
|
|
9
|
+
import httpx
|
|
10
|
+
from loguru import logger
|
|
11
|
+
from PIL import Image as PILImage # noqa: F401 (re-exported for callers)
|
|
12
|
+
|
|
13
|
+
# ---------------------------------------------------------------------------
|
|
14
|
+
# Logging configuration (loguru)
|
|
15
|
+
# ---------------------------------------------------------------------------
|
|
16
|
+
# Remove the default stderr sink so we can control format and level precisely.
|
|
17
|
+
logger.remove()
|
|
18
|
+
|
|
19
|
+
_log_level = os.environ.get("LOG_LEVEL", "INFO").upper()
|
|
20
|
+
|
|
21
|
+
# Console sink: WARNING+ only -- keeps stdio MCP transport clean.
|
|
22
|
+
logger.add(sys.stderr, level="WARNING", format="{time} | {level} | {message}")
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def _log_file_path() -> pathlib.Path:
|
|
26
|
+
"""Return a platform-appropriate log file path, creating the directory."""
|
|
27
|
+
if platform.system() == "Windows":
|
|
28
|
+
base = pathlib.Path(os.environ.get("APPDATA", str(pathlib.Path.home())))
|
|
29
|
+
elif platform.system() == "Darwin":
|
|
30
|
+
base = pathlib.Path.home() / "Library" / "Application Support"
|
|
31
|
+
else:
|
|
32
|
+
base = pathlib.Path.home() / ".config"
|
|
33
|
+
log_dir = base / "meta-ads-mcp"
|
|
34
|
+
log_dir.mkdir(parents=True, exist_ok=True)
|
|
35
|
+
return log_dir / "meta_ads_debug.log"
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
# File sink: full detail for troubleshooting.
|
|
39
|
+
logger.add(
|
|
40
|
+
_log_file_path(),
|
|
41
|
+
level=_log_level,
|
|
42
|
+
rotation="10 MB",
|
|
43
|
+
retention="7 days",
|
|
44
|
+
format="{time:YYYY-MM-DD HH:mm:ss} | {level} | {name}:{line} | {message}",
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
# ---------------------------------------------------------------------------
|
|
48
|
+
# Convenience env-var constants (kept for backwards-compat with callers)
|
|
49
|
+
# ---------------------------------------------------------------------------
|
|
50
|
+
META_APP_ID: str = os.environ.get("META_APP_ID", "")
|
|
51
|
+
META_APP_SECRET: str = os.environ.get("META_APP_SECRET", "")
|
|
52
|
+
|
|
53
|
+
logger.info("meta-ads-mcp logging initialised (level={})", _log_level)
|
|
54
|
+
logger.info("Platform: {} {}", platform.system(), platform.release())
|
|
55
|
+
logger.info(
|
|
56
|
+
"Auth mode: {}",
|
|
57
|
+
"pipeboard" if os.environ.get("PIPEBOARD_API_TOKEN") else "direct-meta",
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
# ---------------------------------------------------------------------------
|
|
61
|
+
# Global image store (used by resources.py)
|
|
62
|
+
# ---------------------------------------------------------------------------
|
|
63
|
+
ad_creative_images: Dict[str, Any] = {}
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
# ---------------------------------------------------------------------------
|
|
67
|
+
# Creative image URL extraction
|
|
68
|
+
# ---------------------------------------------------------------------------
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def extract_creative_image_urls(creative: Dict[str, Any]) -> List[str]:
|
|
72
|
+
"""Extract image URLs from a creative object, ordered by quality.
|
|
73
|
+
|
|
74
|
+
Args:
|
|
75
|
+
creative: Meta Ads creative object.
|
|
76
|
+
|
|
77
|
+
Returns:
|
|
78
|
+
Deduplicated list of image URLs, highest quality first.
|
|
79
|
+
"""
|
|
80
|
+
image_urls: List[str] = []
|
|
81
|
+
|
|
82
|
+
# 1. image_urls_for_viewing (highest quality)
|
|
83
|
+
image_urls.extend(creative.get("image_urls_for_viewing") or [])
|
|
84
|
+
|
|
85
|
+
# 2. Direct image_url field
|
|
86
|
+
if creative.get("image_url"):
|
|
87
|
+
image_urls.append(creative["image_url"])
|
|
88
|
+
|
|
89
|
+
# 3. object_story_spec
|
|
90
|
+
story_spec = creative.get("object_story_spec", {})
|
|
91
|
+
link_data = story_spec.get("link_data", {})
|
|
92
|
+
for field in ("picture", "image_url"):
|
|
93
|
+
if link_data.get(field):
|
|
94
|
+
image_urls.append(link_data[field])
|
|
95
|
+
video_data = story_spec.get("video_data", {})
|
|
96
|
+
if video_data.get("image_url"):
|
|
97
|
+
image_urls.append(video_data["image_url"])
|
|
98
|
+
|
|
99
|
+
# 4. asset_feed_spec images
|
|
100
|
+
for img in (creative.get("asset_feed_spec") or {}).get("images", []):
|
|
101
|
+
if img.get("url"):
|
|
102
|
+
image_urls.append(img["url"])
|
|
103
|
+
|
|
104
|
+
# 5. thumbnail_url (lowest priority)
|
|
105
|
+
if creative.get("thumbnail_url"):
|
|
106
|
+
image_urls.append(creative["thumbnail_url"])
|
|
107
|
+
|
|
108
|
+
# Deduplicate, preserving order
|
|
109
|
+
seen: set = set()
|
|
110
|
+
unique: List[str] = []
|
|
111
|
+
for url in image_urls:
|
|
112
|
+
if url not in seen:
|
|
113
|
+
seen.add(url)
|
|
114
|
+
unique.append(url)
|
|
115
|
+
return unique
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
# ---------------------------------------------------------------------------
|
|
119
|
+
# Image download helpers
|
|
120
|
+
# ---------------------------------------------------------------------------
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
async def download_image(url: str) -> Optional[bytes]:
|
|
124
|
+
"""Download an image from a URL.
|
|
125
|
+
|
|
126
|
+
Args:
|
|
127
|
+
url: Image URL.
|
|
128
|
+
|
|
129
|
+
Returns:
|
|
130
|
+
Raw image bytes, or None on failure.
|
|
131
|
+
"""
|
|
132
|
+
headers = {"User-Agent": "curl/8.4.0", "Accept": "*/*"}
|
|
133
|
+
try:
|
|
134
|
+
async with httpx.AsyncClient(follow_redirects=True, timeout=30.0) as client:
|
|
135
|
+
response = await client.get(url, headers=headers)
|
|
136
|
+
if response.status_code == 200:
|
|
137
|
+
logger.debug("Downloaded {} bytes from {}", len(response.content), url)
|
|
138
|
+
return response.content
|
|
139
|
+
logger.warning("Image download failed: HTTP {} for {}", response.status_code, url)
|
|
140
|
+
except httpx.HTTPStatusError as exc:
|
|
141
|
+
logger.warning("HTTP error downloading {}: {}", url, exc)
|
|
142
|
+
except httpx.RequestError as exc:
|
|
143
|
+
logger.warning("Request error downloading {}: {}", url, exc)
|
|
144
|
+
except Exception:
|
|
145
|
+
logger.exception("Unexpected error downloading {}", url)
|
|
146
|
+
return None
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
async def try_multiple_download_methods(url: str) -> Optional[bytes]:
|
|
150
|
+
"""Try multiple strategies to download a Meta CDN image.
|
|
151
|
+
|
|
152
|
+
Args:
|
|
153
|
+
url: Image URL.
|
|
154
|
+
|
|
155
|
+
Returns:
|
|
156
|
+
Raw image bytes, or None if all methods fail.
|
|
157
|
+
"""
|
|
158
|
+
# Method 1: direct curl-style request
|
|
159
|
+
data = await download_image(url)
|
|
160
|
+
if data:
|
|
161
|
+
return data
|
|
162
|
+
|
|
163
|
+
logger.debug("Direct download failed, trying browser UA for {}", url)
|
|
164
|
+
|
|
165
|
+
# Method 2: browser User-Agent
|
|
166
|
+
try:
|
|
167
|
+
headers = {
|
|
168
|
+
"User-Agent": (
|
|
169
|
+
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
|
|
170
|
+
"AppleWebKit/537.36 (KHTML, like Gecko) "
|
|
171
|
+
"Chrome/91.0.4472.124 Safari/537.36"
|
|
172
|
+
),
|
|
173
|
+
"Accept": "image/webp,image/apng,image/*,*/*;q=0.8",
|
|
174
|
+
}
|
|
175
|
+
async with httpx.AsyncClient(follow_redirects=True, timeout=30.0) as client:
|
|
176
|
+
response = await client.get(url, headers=headers)
|
|
177
|
+
response.raise_for_status()
|
|
178
|
+
logger.debug("Browser-UA download succeeded: {} bytes", len(response.content))
|
|
179
|
+
return response.content
|
|
180
|
+
except Exception as exc:
|
|
181
|
+
logger.debug("Browser-UA download failed for {}: {}", url, exc)
|
|
182
|
+
|
|
183
|
+
# Method 3: seed cookies via a Facebook visit first
|
|
184
|
+
try:
|
|
185
|
+
async with httpx.AsyncClient(follow_redirects=True, timeout=30.0) as client:
|
|
186
|
+
await client.get("https://www.facebook.com/", timeout=30.0)
|
|
187
|
+
response = await client.get(url, timeout=30.0)
|
|
188
|
+
response.raise_for_status()
|
|
189
|
+
logger.debug("Facebook-session download succeeded: {} bytes", len(response.content))
|
|
190
|
+
return response.content
|
|
191
|
+
except Exception as exc:
|
|
192
|
+
logger.debug("Facebook-session download failed for {}: {}", url, exc)
|
|
193
|
+
|
|
194
|
+
return None
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
# ---------------------------------------------------------------------------
|
|
198
|
+
# Resource creation helper
|
|
199
|
+
# ---------------------------------------------------------------------------
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
def create_resource_from_image(
|
|
203
|
+
image_bytes: bytes, resource_id: str, name: str
|
|
204
|
+
) -> Dict[str, Any]:
|
|
205
|
+
"""Store image bytes and return a resource descriptor.
|
|
206
|
+
|
|
207
|
+
Args:
|
|
208
|
+
image_bytes: Raw image data.
|
|
209
|
+
resource_id: Unique identifier for the resource.
|
|
210
|
+
name: Human-readable name.
|
|
211
|
+
|
|
212
|
+
Returns:
|
|
213
|
+
Resource descriptor dict with uri and size.
|
|
214
|
+
"""
|
|
215
|
+
ad_creative_images[resource_id] = {
|
|
216
|
+
"data": image_bytes,
|
|
217
|
+
"mime_type": "image/jpeg",
|
|
218
|
+
"name": name,
|
|
219
|
+
}
|
|
220
|
+
return {
|
|
221
|
+
"resource_id": resource_id,
|
|
222
|
+
"resource_uri": f"meta-ads://images/{resource_id}",
|
|
223
|
+
"name": name,
|
|
224
|
+
"size": len(image_bytes),
|
|
225
|
+
}
|
meta_ads_mcp/settings.py
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"""Configuration management for meta-ads-mcp."""
|
|
2
|
+
|
|
3
|
+
from pydantic import Field
|
|
4
|
+
from pydantic_settings import BaseSettings
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Settings(BaseSettings):
|
|
8
|
+
"""Application settings loaded from environment variables."""
|
|
9
|
+
|
|
10
|
+
log_level: str = Field(default="INFO", description="Logging level")
|
|
11
|
+
|
|
12
|
+
# Meta direct-auth (optional -- Pipeboard auth takes precedence)
|
|
13
|
+
meta_app_id: str = Field(default="", description="Meta App ID for direct OAuth")
|
|
14
|
+
meta_app_secret: str = Field(default="", description="Meta App Secret for appsecret_proof signing")
|
|
15
|
+
|
|
16
|
+
# Pipeboard cloud auth (recommended)
|
|
17
|
+
pipeboard_api_token: str = Field(default="", description="Pipeboard API token for cloud-hosted auth")
|
|
18
|
+
|
|
19
|
+
# HTTP transport
|
|
20
|
+
server_host: str = Field(default="localhost", description="Host for streamable-http transport")
|
|
21
|
+
server_port: int = Field(default=8080, description="Port for streamable-http transport")
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def load_settings(**kwargs: object) -> Settings:
|
|
25
|
+
"""Load application settings from environment variables.
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
**kwargs: Override any setting value.
|
|
29
|
+
|
|
30
|
+
Returns:
|
|
31
|
+
Populated Settings instance.
|
|
32
|
+
"""
|
|
33
|
+
return Settings(**kwargs)
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: meta-ads-mcp-python
|
|
3
|
+
Version: 1.0.79
|
|
4
|
+
Summary: MCP server for Meta Ads API -- manage campaigns, ad sets, ads, and Business Manager accounts
|
|
5
|
+
Keywords: meta,facebook,ads,api,mcp,claude
|
|
6
|
+
Author: Yves Junqueira
|
|
7
|
+
Author-email: Yves Junqueira <yves.junqueira@gmail.com>
|
|
8
|
+
License: BUSL-1.1
|
|
9
|
+
Classifier: Development Status :: 4 - Beta
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: License :: Other/Proprietary License
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Requires-Dist: fastmcp>=2.0.0
|
|
15
|
+
Requires-Dist: loguru>=0.7.3
|
|
16
|
+
Requires-Dist: pydantic>=2.11.7
|
|
17
|
+
Requires-Dist: pydantic-settings>=2.10.1
|
|
18
|
+
Requires-Dist: httpx>=0.26.0
|
|
19
|
+
Requires-Dist: python-dotenv>=1.1.0
|
|
20
|
+
Requires-Dist: requests>=2.32.3
|
|
21
|
+
Requires-Dist: pillow>=10.0.0
|
|
22
|
+
Requires-Dist: python-dateutil>=2.8.2
|
|
23
|
+
Requires-Python: >=3.12
|
|
24
|
+
Project-URL: Homepage, https://github.com/locomotive-agency/meta-ads-mcp-python
|
|
25
|
+
Project-URL: Bug Tracker, https://github.com/locomotive-agency/meta-ads-mcp-python/issues
|
|
26
|
+
Description-Content-Type: text/markdown
|
|
27
|
+
|
|
28
|
+
# Meta Ads MCP
|
|
29
|
+
|
|
30
|
+
A [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) server for analysing Meta Ads campaigns through an AI interface. Retrieve performance data, visualize ad creatives, and surface insights for Facebook, Instagram, and other Meta platforms.
|
|
31
|
+
|
|
32
|
+
> **Read-only:** All tools are strictly read-only. No tool creates, modifies, or deletes any data.
|
|
33
|
+
|
|
34
|
+
> **Independent project:** This is an open-source project using Meta's public APIs. Not affiliated with or endorsed by Meta. For an officially approved Meta app, see [Pipeboard](https://pipeboard.co).
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## Quick Start (Remote MCP)
|
|
39
|
+
|
|
40
|
+
The fastest way to get started is the [Pipeboard remote MCP](https://pipeboard.co) — no local setup required.
|
|
41
|
+
|
|
42
|
+
Remote MCP URL: `https://mcp.pipeboard.co/meta-ads-mcp`
|
|
43
|
+
|
|
44
|
+
With token auth: `https://mcp.pipeboard.co/meta-ads-mcp?token=YOUR_PIPEBOARD_TOKEN`
|
|
45
|
+
|
|
46
|
+
Get your token at [pipeboard.co/api-tokens](https://pipeboard.co/api-tokens).
|
|
47
|
+
|
|
48
|
+
### Claude (Pro/Max)
|
|
49
|
+
|
|
50
|
+
1. Go to [claude.ai/settings/integrations](https://claude.ai/settings/integrations)
|
|
51
|
+
2. Click **Add Integration**, set the URL to `https://mcp.pipeboard.co/meta-ads-mcp`
|
|
52
|
+
3. Click **Connect** and follow the prompts.
|
|
53
|
+
|
|
54
|
+
### Cursor
|
|
55
|
+
|
|
56
|
+
Add to `~/.cursor/mcp.json`:
|
|
57
|
+
|
|
58
|
+
```json
|
|
59
|
+
{
|
|
60
|
+
"mcpServers": {
|
|
61
|
+
"meta-ads-remote": {
|
|
62
|
+
"url": "https://mcp.pipeboard.co/meta-ads-mcp?token=YOUR_PIPEBOARD_TOKEN"
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Other MCP Clients
|
|
69
|
+
|
|
70
|
+
Use the remote URL above. Full setup guides: [pipeboard.co](https://pipeboard.co)
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## Local Installation
|
|
75
|
+
|
|
76
|
+
> For advanced users. The remote MCP is recommended for most cases.
|
|
77
|
+
|
|
78
|
+
**Requirements:** Python 3.12+, a Meta Developer App (App ID + Secret), and [uv](https://github.com/astral-sh/uv).
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
pip install meta-ads-mcp
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### Authentication
|
|
85
|
+
|
|
86
|
+
Copy `.env.example` to `.env` and set one of:
|
|
87
|
+
|
|
88
|
+
```
|
|
89
|
+
PIPEBOARD_API_TOKEN=your_token # Recommended — no Meta app required
|
|
90
|
+
META_APP_ID=your_app_id # Direct Meta app credentials
|
|
91
|
+
META_APP_SECRET=your_app_secret
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Run
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
meta-ads-mcp # stdio (default)
|
|
98
|
+
python -m meta_ads_mcp --transport streamable-http --host localhost --port 8080 # HTTP
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Claude Desktop config
|
|
102
|
+
|
|
103
|
+
```json
|
|
104
|
+
{
|
|
105
|
+
"mcpServers": {
|
|
106
|
+
"meta-ads": {
|
|
107
|
+
"command": "meta-ads-mcp"
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
## Configuration
|
|
116
|
+
|
|
117
|
+
| Variable | Description |
|
|
118
|
+
|---|---|
|
|
119
|
+
| `PIPEBOARD_API_TOKEN` | Pipeboard API token (recommended) |
|
|
120
|
+
| `META_APP_ID` | Meta Developer App ID (direct auth) |
|
|
121
|
+
| `META_APP_SECRET` | Meta Developer App Secret (direct auth) |
|
|
122
|
+
| `LOG_LEVEL` | `DEBUG`, `INFO`, `WARNING`, `ERROR` (default: `INFO`) |
|
|
123
|
+
| `SERVER_HOST` | HTTP transport host (default: `localhost`) |
|
|
124
|
+
| `SERVER_PORT` | HTTP transport port (default: `8080`) |
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
## Available Tools
|
|
129
|
+
|
|
130
|
+
| Tool | Description |
|
|
131
|
+
|---|---|
|
|
132
|
+
| `mcp_meta_ads_get_ad_accounts` | List accessible ad accounts |
|
|
133
|
+
| `mcp_meta_ads_get_account_info` | Get details for a specific ad account |
|
|
134
|
+
| `mcp_meta_ads_get_account_pages` | Get pages associated with an ad account |
|
|
135
|
+
| `mcp_meta_ads_get_campaigns` | List campaigns with optional status filter |
|
|
136
|
+
| `mcp_meta_ads_get_campaign_details` | Get details for a specific campaign |
|
|
137
|
+
| `mcp_meta_ads_get_adsets` | List ad sets, optionally filtered by campaign |
|
|
138
|
+
| `mcp_meta_ads_get_adset_details` | Get details for a specific ad set |
|
|
139
|
+
| `mcp_meta_ads_get_ads` | List ads, optionally filtered by campaign or ad set |
|
|
140
|
+
| `mcp_meta_ads_get_ad_details` | Get details for a specific ad |
|
|
141
|
+
| `mcp_meta_ads_get_ad_creatives` | Get creative details (text, images, URLs) |
|
|
142
|
+
| `mcp_meta_ads_get_ad_image` | Download and visualize an ad image |
|
|
143
|
+
| `mcp_meta_ads_get_insights` | Get performance metrics with attribution windows and breakdowns |
|
|
144
|
+
| `mcp_meta_ads_get_login_link` | Get a login link for Meta authentication |
|
|
145
|
+
| `mcp_meta_ads_search_interests` | Search interest targeting options by keyword |
|
|
146
|
+
| `mcp_meta_ads_get_interest_suggestions` | Get interest suggestions based on existing interests |
|
|
147
|
+
| `mcp_meta_ads_validate_interests` | Validate interest names or IDs |
|
|
148
|
+
| `mcp_meta_ads_search_behaviors` | List available behavior targeting options |
|
|
149
|
+
| `mcp_meta_ads_search_demographics` | List demographic targeting options |
|
|
150
|
+
| `mcp_meta_ads_search_geo_locations` | Search geographic targeting locations |
|
|
151
|
+
| `mcp_meta_ads_search` | Generic search across accounts, campaigns, ads, and pages |
|
|
152
|
+
| `mcp_meta_ads_get_businesses` | List all Business Manager accounts |
|
|
153
|
+
| `mcp_meta_ads_get_business_ad_accounts` | List ad accounts under a Business Manager |
|
|
154
|
+
| `mcp_meta_ads_find_client_account` | Search for a client account across Business Managers |
|
|
155
|
+
| `mcp_meta_ads_get_business_details` | Get details for a specific Business Manager |
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
## Troubleshooting
|
|
160
|
+
|
|
161
|
+
- **Auth errors:** Check your token/credentials in `.env`. Use `mcp_meta_ads_get_login_link` to re-authenticate.
|
|
162
|
+
- **No accounts returned:** Ensure the user has access to at least one ad account in Meta Business Manager.
|
|
163
|
+
- **Tool not found:** Confirm the server is running and your client config is correct.
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
## Privacy and Security
|
|
168
|
+
|
|
169
|
+
- Remote MCP: auth is handled in the cloud, no tokens stored locally.
|
|
170
|
+
- Local install: tokens are cached on your machine. Never commit your `.env` file.
|
|
171
|
+
- The server never exposes your access token to the LLM.
|
|
172
|
+
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
## Licensing
|
|
176
|
+
|
|
177
|
+
Licensed under the [Business Source License 1.1](LICENSE). Free for individual and business use. Converts to Apache 2.0 on January 1, 2029. You may not offer this as a competing hosted service.
|
|
178
|
+
|
|
179
|
+
For commercial licensing: [info@pipeboard.co](mailto:info@pipeboard.co)
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
## Support
|
|
184
|
+
|
|
185
|
+
- [Discord](https://discord.gg/YzMwQ8zrjr)
|
|
186
|
+
- [GitHub Issues](https://github.com/pipeboard-co/meta-ads-mcp/issues)
|
|
187
|
+
- [Email](mailto:info@pipeboard.co)
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
meta_ads_mcp/__init__.py,sha256=-thYt7S219dpbxUk4NFJOxAjP3M2TgDv0ZTt_ygh48U,1759
|
|
2
|
+
meta_ads_mcp/__main__.py,sha256=XaQt3iXftG_7f0Zu7Wop9SeFgrD2WBn0EQOaPMc27d8,207
|
|
3
|
+
meta_ads_mcp/core/__init__.py,sha256=QBtXQtHlni_kg0DzsJk2w9yjMRQ481Wm_DEmtTMtxec,1982
|
|
4
|
+
meta_ads_mcp/core/accounts.py,sha256=Qfcp2p0EUqqUqFPzRnQMPKkblQL97Ka66vN5vEeXceo,5815
|
|
5
|
+
meta_ads_mcp/core/ads.py,sha256=SlqOaUDEAEKyV-h-Whze7v6HRZm4uRcL-3j6_EIyTCk,124995
|
|
6
|
+
meta_ads_mcp/core/ads_library.py,sha256=smGz9FhM6RIUjlQT4Jv1BaZmXahGdK21eRCB7QMhK-4,3228
|
|
7
|
+
meta_ads_mcp/core/adsets.py,sha256=og2WVmPyXO7c9PtrX8g21PfpcksmwAVZcOGzlqD-FZ0,37429
|
|
8
|
+
meta_ads_mcp/core/api.py,sha256=60DLCo3YsuqlbpI76q6qdW-jiVrFn3DsWdUPbeI9iMg,21645
|
|
9
|
+
meta_ads_mcp/core/auth.py,sha256=saZZyYE0nLgoUFVsIfTcAWq4XZN5orI0DCI5xmxGtbQ,23649
|
|
10
|
+
meta_ads_mcp/core/authentication.py,sha256=dQ-vFrTuP-uzkfOuAJf4d4RketOUnCZeF891LkHQcDg,10472
|
|
11
|
+
meta_ads_mcp/core/budget_schedules.py,sha256=ljTloal8ohFJTOSqaZhbRnvA6SRW0z5RvvFTkfVtxTk,2892
|
|
12
|
+
meta_ads_mcp/core/callback_server.py,sha256=fpDl9JEMpvbfmHBPj2R5T55JjeGEL9bbAjeWhOUAQcg,9354
|
|
13
|
+
meta_ads_mcp/core/campaigns.py,sha256=JAAOPbnxMWhwtNsOhqX9QmXWt8pSDX0MqJ1Ih9SeNTM,17162
|
|
14
|
+
meta_ads_mcp/core/duplication.py,sha256=fLZsJrSlvnLjdMLCww_nA1CiaYivbGLPxVcJbepzlzQ,22974
|
|
15
|
+
meta_ads_mcp/core/http_auth_integration.py,sha256=lGpKhfzJcyWugBcYEvypY-qnlt-3UDBLqh7xAUH0DGw,12473
|
|
16
|
+
meta_ads_mcp/core/insights.py,sha256=T0Qwsfd9QUiJOf8gAvhtp_zs5OCLmOhSbBpIHqyKQPo,9114
|
|
17
|
+
meta_ads_mcp/core/mcc.py,sha256=XozUBRGzh6V4YLEJjNQcam71GzgSR8L-WKAU9a6q3s4,8010
|
|
18
|
+
meta_ads_mcp/core/openai_deep_research.py,sha256=EdYSZAHK0llS6YthXSXWrU3cJn5F_pVeimIWD9M_LiY,19069
|
|
19
|
+
meta_ads_mcp/core/pipeboard_auth.py,sha256=06PHiSg1rUBRY4FJ-eo-EFi9cVe32hwhjDkxXHykPKY,24524
|
|
20
|
+
meta_ads_mcp/core/reports.py,sha256=4_6MgwkdXiGedh3cGVgFaCsiHrcaO9hiAl3-gAgCkgw,5813
|
|
21
|
+
meta_ads_mcp/core/resources.py,sha256=-zIIfZulpo76vcKv6jhAlQq91cR2SZ3cjYZt3ek3x0w,1236
|
|
22
|
+
meta_ads_mcp/core/server.py,sha256=jSUkOzwxIL7v8eIvuN9weBoq8R7s5GRSrec-AGFoFDY,17892
|
|
23
|
+
meta_ads_mcp/core/targeting.py,sha256=S5m3zVs4rnuwC4eIt0hLsTf7_mATUnsXYNTCXJkAXz0,25274
|
|
24
|
+
meta_ads_mcp/core/utils.py,sha256=dQJURUXyB_ojWk9NlftjanR48-cElA3iOT35XMTF01c,7832
|
|
25
|
+
meta_ads_mcp/settings.py,sha256=F-uPfXrnDFyW7cJ5NmWhg1PYmexyVHCCrwU2LXUDlo4,1171
|
|
26
|
+
meta_ads_mcp_python-1.0.79.dist-info/WHEEL,sha256=WvwXFgRajeoYkfRVmDhkP4Qlqo31Mk687zIO2QQoFmw,80
|
|
27
|
+
meta_ads_mcp_python-1.0.79.dist-info/entry_points.txt,sha256=1Jl6H25XiykQqFHYOYJQ4LJrrMd4o_Fn0ombZaHHP_g,64
|
|
28
|
+
meta_ads_mcp_python-1.0.79.dist-info/METADATA,sha256=H13RNdBQWRxonE5wnXMSjMCXmvh6O0hgNng1leZKxuE,6775
|
|
29
|
+
meta_ads_mcp_python-1.0.79.dist-info/RECORD,,
|