meta-ads-mcp 0.3.10__tar.gz → 0.4.1__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.
- {meta_ads_mcp-0.3.10 → meta_ads_mcp-0.4.1}/PKG-INFO +11 -20
- {meta_ads_mcp-0.3.10 → meta_ads_mcp-0.4.1}/README.md +5 -16
- {meta_ads_mcp-0.3.10 → meta_ads_mcp-0.4.1}/meta_ads_mcp/__init__.py +1 -3
- {meta_ads_mcp-0.3.10 → meta_ads_mcp-0.4.1}/meta_ads_mcp/core/__init__.py +2 -2
- {meta_ads_mcp-0.3.10 → meta_ads_mcp-0.4.1}/meta_ads_mcp/core/adsets.py +15 -6
- {meta_ads_mcp-0.3.10 → meta_ads_mcp-0.4.1}/meta_ads_mcp/core/auth.py +29 -17
- {meta_ads_mcp-0.3.10 → meta_ads_mcp-0.4.1}/meta_ads_mcp/core/authentication.py +17 -8
- {meta_ads_mcp-0.3.10 → meta_ads_mcp-0.4.1}/meta_ads_mcp/core/callback_server.py +9 -0
- meta_ads_mcp-0.4.1/meta_ads_mcp/core/duplication.py +411 -0
- meta_ads_mcp-0.4.1/meta_ads_mcp/core/insights.py +62 -0
- {meta_ads_mcp-0.3.10 → meta_ads_mcp-0.4.1}/pyproject.toml +6 -4
- meta_ads_mcp-0.4.1/tests/README_REGRESSION_TESTS.md +185 -0
- meta_ads_mcp-0.4.1/tests/test_duplication.py +136 -0
- meta_ads_mcp-0.4.1/tests/test_duplication_regression.py +805 -0
- meta_ads_mcp-0.3.10/meta_ads_mcp/core/insights.py +0 -429
- {meta_ads_mcp-0.3.10 → meta_ads_mcp-0.4.1}/.github/workflows/publish.yml +0 -0
- {meta_ads_mcp-0.3.10 → meta_ads_mcp-0.4.1}/.github/workflows/test.yml +0 -0
- {meta_ads_mcp-0.3.10 → meta_ads_mcp-0.4.1}/.gitignore +0 -0
- {meta_ads_mcp-0.3.10 → meta_ads_mcp-0.4.1}/CUSTOM_META_APP.md +0 -0
- {meta_ads_mcp-0.3.10 → meta_ads_mcp-0.4.1}/Dockerfile +0 -0
- {meta_ads_mcp-0.3.10 → meta_ads_mcp-0.4.1}/LICENSE +0 -0
- {meta_ads_mcp-0.3.10 → meta_ads_mcp-0.4.1}/LOCAL_INSTALLATION.md +0 -0
- {meta_ads_mcp-0.3.10 → meta_ads_mcp-0.4.1}/META_API_NOTES.md +0 -0
- {meta_ads_mcp-0.3.10 → meta_ads_mcp-0.4.1}/RELEASE.md +0 -0
- {meta_ads_mcp-0.3.10 → meta_ads_mcp-0.4.1}/STREAMABLE_HTTP_SETUP.md +0 -0
- {meta_ads_mcp-0.3.10 → meta_ads_mcp-0.4.1}/examples/README.md +0 -0
- {meta_ads_mcp-0.3.10 → meta_ads_mcp-0.4.1}/examples/example_http_client.py +0 -0
- {meta_ads_mcp-0.3.10 → meta_ads_mcp-0.4.1}/future_improvements.md +0 -0
- {meta_ads_mcp-0.3.10 → meta_ads_mcp-0.4.1}/images/meta-ads-example.png +0 -0
- {meta_ads_mcp-0.3.10 → meta_ads_mcp-0.4.1}/meta_ads_auth.sh +0 -0
- {meta_ads_mcp-0.3.10 → meta_ads_mcp-0.4.1}/meta_ads_mcp/__main__.py +0 -0
- {meta_ads_mcp-0.3.10 → meta_ads_mcp-0.4.1}/meta_ads_mcp/core/accounts.py +0 -0
- {meta_ads_mcp-0.3.10 → meta_ads_mcp-0.4.1}/meta_ads_mcp/core/ads.py +0 -0
- {meta_ads_mcp-0.3.10 → meta_ads_mcp-0.4.1}/meta_ads_mcp/core/ads_library.py +0 -0
- {meta_ads_mcp-0.3.10 → meta_ads_mcp-0.4.1}/meta_ads_mcp/core/api.py +0 -0
- {meta_ads_mcp-0.3.10 → meta_ads_mcp-0.4.1}/meta_ads_mcp/core/budget_schedules.py +0 -0
- {meta_ads_mcp-0.3.10 → meta_ads_mcp-0.4.1}/meta_ads_mcp/core/campaigns.py +0 -0
- {meta_ads_mcp-0.3.10 → meta_ads_mcp-0.4.1}/meta_ads_mcp/core/http_auth_integration.py +0 -0
- {meta_ads_mcp-0.3.10 → meta_ads_mcp-0.4.1}/meta_ads_mcp/core/pipeboard_auth.py +0 -0
- {meta_ads_mcp-0.3.10 → meta_ads_mcp-0.4.1}/meta_ads_mcp/core/reports.py +0 -0
- {meta_ads_mcp-0.3.10 → meta_ads_mcp-0.4.1}/meta_ads_mcp/core/resources.py +0 -0
- {meta_ads_mcp-0.3.10 → meta_ads_mcp-0.4.1}/meta_ads_mcp/core/server.py +0 -0
- {meta_ads_mcp-0.3.10 → meta_ads_mcp-0.4.1}/meta_ads_mcp/core/utils.py +0 -0
- {meta_ads_mcp-0.3.10 → meta_ads_mcp-0.4.1}/requirements.txt +0 -0
- {meta_ads_mcp-0.3.10 → meta_ads_mcp-0.4.1}/setup.py +0 -0
- {meta_ads_mcp-0.3.10 → meta_ads_mcp-0.4.1}/smithery.yaml +0 -0
- {meta_ads_mcp-0.3.10 → meta_ads_mcp-0.4.1}/tests/README.md +0 -0
- {meta_ads_mcp-0.3.10 → meta_ads_mcp-0.4.1}/tests/__init__.py +0 -0
- {meta_ads_mcp-0.3.10 → meta_ads_mcp-0.4.1}/tests/conftest.py +0 -0
- {meta_ads_mcp-0.3.10 → meta_ads_mcp-0.4.1}/tests/test_http_transport.py +0 -0
- {meta_ads_mcp-0.3.10 → meta_ads_mcp-0.4.1}/tests/test_openai.py +0 -0
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: meta-ads-mcp
|
|
3
|
-
Version: 0.
|
|
4
|
-
Summary: Model
|
|
3
|
+
Version: 0.4.1
|
|
4
|
+
Summary: Model Context Protocol (MCP) plugin for interacting with Meta Ads API
|
|
5
5
|
Project-URL: Homepage, https://github.com/pipeboard-co/meta-ads-mcp
|
|
6
6
|
Project-URL: Bug Tracker, https://github.com/pipeboard-co/meta-ads-mcp/issues
|
|
7
7
|
Author-email: Yves Junqueira <yves.junqueira@gmail.com>
|
|
8
|
-
License:
|
|
8
|
+
License: Apache-2.0
|
|
9
9
|
License-File: LICENSE
|
|
10
10
|
Keywords: ads,api,claude,facebook,mcp,meta
|
|
11
|
-
Classifier: License :: OSI Approved ::
|
|
11
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
12
12
|
Classifier: Operating System :: OS Independent
|
|
13
13
|
Classifier: Programming Language :: Python :: 3
|
|
14
14
|
Requires-Python: >=3.10
|
|
@@ -16,6 +16,8 @@ Requires-Dist: httpx>=0.26.0
|
|
|
16
16
|
Requires-Dist: mcp[cli]>=1.10.1
|
|
17
17
|
Requires-Dist: pathlib>=1.0.1
|
|
18
18
|
Requires-Dist: pillow>=10.0.0
|
|
19
|
+
Requires-Dist: pytest-asyncio>=1.0.0
|
|
20
|
+
Requires-Dist: pytest>=8.4.1
|
|
19
21
|
Requires-Dist: python-dateutil>=2.8.2
|
|
20
22
|
Requires-Dist: python-dotenv>=1.1.0
|
|
21
23
|
Requires-Dist: requests>=2.32.3
|
|
@@ -63,17 +65,14 @@ That's it! You can now ask Claude to analyze your Meta ad campaigns, get perform
|
|
|
63
65
|
|
|
64
66
|
### For Cursor Users
|
|
65
67
|
|
|
66
|
-
Add
|
|
68
|
+
Add the following to your `~/.cursor/mcp.json`. Once you enable the remote MCP, click on "Needs login" to finish the login process.
|
|
69
|
+
|
|
67
70
|
|
|
68
71
|
```json
|
|
69
72
|
{
|
|
70
73
|
"mcpServers": {
|
|
71
74
|
"meta-ads-remote": {
|
|
72
|
-
"
|
|
73
|
-
"args": [
|
|
74
|
-
"mcp-remote",
|
|
75
|
-
"https://mcp.pipeboard.co/meta-ads-mcp"
|
|
76
|
-
]
|
|
75
|
+
"url": "https://mcp.pipeboard.co/meta-ads-mcp"
|
|
77
76
|
}
|
|
78
77
|
}
|
|
79
78
|
}
|
|
@@ -313,21 +312,13 @@ For local installation configuration, authentication options, and advanced techn
|
|
|
313
312
|
- `level`: Level of aggregation (ad, adset, campaign, account)
|
|
314
313
|
- Returns: Performance metrics for the specified object
|
|
315
314
|
|
|
316
|
-
20. `
|
|
317
|
-
- Debug image download issues and report detailed diagnostics
|
|
318
|
-
- Inputs:
|
|
319
|
-
- `access_token` (optional): Meta API access token (will use cached token if not provided)
|
|
320
|
-
- `url`: Direct image URL to test (optional)
|
|
321
|
-
- `ad_id`: Meta Ads ad ID (optional, used if url is not provided)
|
|
322
|
-
- Returns: Diagnostic information about image download attempts
|
|
323
|
-
|
|
324
|
-
21. `mcp_meta_ads_get_login_link`
|
|
315
|
+
20. `mcp_meta_ads_get_login_link`
|
|
325
316
|
- Get a clickable login link for Meta Ads authentication
|
|
326
317
|
- Inputs:
|
|
327
318
|
- `access_token` (optional): Meta API access token (will use cached token if not provided)
|
|
328
319
|
- Returns: A clickable resource link for Meta authentication
|
|
329
320
|
|
|
330
|
-
|
|
321
|
+
21. `mcp_meta-ads_create_budget_schedule`
|
|
331
322
|
- Create a budget schedule for a Meta Ads campaign.
|
|
332
323
|
- Inputs:
|
|
333
324
|
- `campaign_id`: Meta Ads campaign ID.
|
|
@@ -40,17 +40,14 @@ That's it! You can now ask Claude to analyze your Meta ad campaigns, get perform
|
|
|
40
40
|
|
|
41
41
|
### For Cursor Users
|
|
42
42
|
|
|
43
|
-
Add
|
|
43
|
+
Add the following to your `~/.cursor/mcp.json`. Once you enable the remote MCP, click on "Needs login" to finish the login process.
|
|
44
|
+
|
|
44
45
|
|
|
45
46
|
```json
|
|
46
47
|
{
|
|
47
48
|
"mcpServers": {
|
|
48
49
|
"meta-ads-remote": {
|
|
49
|
-
"
|
|
50
|
-
"args": [
|
|
51
|
-
"mcp-remote",
|
|
52
|
-
"https://mcp.pipeboard.co/meta-ads-mcp"
|
|
53
|
-
]
|
|
50
|
+
"url": "https://mcp.pipeboard.co/meta-ads-mcp"
|
|
54
51
|
}
|
|
55
52
|
}
|
|
56
53
|
}
|
|
@@ -290,21 +287,13 @@ For local installation configuration, authentication options, and advanced techn
|
|
|
290
287
|
- `level`: Level of aggregation (ad, adset, campaign, account)
|
|
291
288
|
- Returns: Performance metrics for the specified object
|
|
292
289
|
|
|
293
|
-
20. `
|
|
294
|
-
- Debug image download issues and report detailed diagnostics
|
|
295
|
-
- Inputs:
|
|
296
|
-
- `access_token` (optional): Meta API access token (will use cached token if not provided)
|
|
297
|
-
- `url`: Direct image URL to test (optional)
|
|
298
|
-
- `ad_id`: Meta Ads ad ID (optional, used if url is not provided)
|
|
299
|
-
- Returns: Diagnostic information about image download attempts
|
|
300
|
-
|
|
301
|
-
21. `mcp_meta_ads_get_login_link`
|
|
290
|
+
20. `mcp_meta_ads_get_login_link`
|
|
302
291
|
- Get a clickable login link for Meta Ads authentication
|
|
303
292
|
- Inputs:
|
|
304
293
|
- `access_token` (optional): Meta API access token (will use cached token if not provided)
|
|
305
294
|
- Returns: A clickable resource link for Meta authentication
|
|
306
295
|
|
|
307
|
-
|
|
296
|
+
21. `mcp_meta-ads_create_budget_schedule`
|
|
308
297
|
- Create a budget schedule for a Meta Ads campaign.
|
|
309
298
|
- Inputs:
|
|
310
299
|
- `campaign_id`: Meta Ads campaign ID.
|
|
@@ -7,7 +7,7 @@ with the Claude LLM.
|
|
|
7
7
|
|
|
8
8
|
from meta_ads_mcp.core.server import main
|
|
9
9
|
|
|
10
|
-
__version__ = "0.
|
|
10
|
+
__version__ = "0.4.1"
|
|
11
11
|
|
|
12
12
|
__all__ = [
|
|
13
13
|
'get_ad_accounts',
|
|
@@ -24,7 +24,6 @@ __all__ = [
|
|
|
24
24
|
'get_ad_image',
|
|
25
25
|
'update_ad',
|
|
26
26
|
'get_insights',
|
|
27
|
-
'debug_image_download',
|
|
28
27
|
'get_login_link',
|
|
29
28
|
'login_cli',
|
|
30
29
|
'main'
|
|
@@ -46,7 +45,6 @@ from .core import (
|
|
|
46
45
|
get_ad_image,
|
|
47
46
|
update_ad,
|
|
48
47
|
get_insights,
|
|
49
|
-
debug_image_download,
|
|
50
48
|
get_login_link,
|
|
51
49
|
login_cli,
|
|
52
50
|
main
|
|
@@ -5,13 +5,14 @@ from .accounts import get_ad_accounts, get_account_info
|
|
|
5
5
|
from .campaigns import get_campaigns, get_campaign_details, create_campaign
|
|
6
6
|
from .adsets import get_adsets, get_adset_details, update_adset
|
|
7
7
|
from .ads import get_ads, get_ad_details, get_ad_creatives, get_ad_image, update_ad
|
|
8
|
-
from .insights import get_insights
|
|
8
|
+
from .insights import get_insights
|
|
9
9
|
from .authentication import get_login_link
|
|
10
10
|
from .server import login_cli, main
|
|
11
11
|
from .auth import login
|
|
12
12
|
from .ads_library import search_ads_archive
|
|
13
13
|
from .budget_schedules import create_budget_schedule
|
|
14
14
|
from . import reports # Import module to register conditional tools
|
|
15
|
+
from . import duplication # Import module to register conditional duplication tools
|
|
15
16
|
|
|
16
17
|
__all__ = [
|
|
17
18
|
'mcp_server',
|
|
@@ -29,7 +30,6 @@ __all__ = [
|
|
|
29
30
|
'get_ad_image',
|
|
30
31
|
'update_ad',
|
|
31
32
|
'get_insights',
|
|
32
|
-
'debug_image_download',
|
|
33
33
|
'get_login_link',
|
|
34
34
|
'login_cli',
|
|
35
35
|
'login',
|
|
@@ -270,12 +270,21 @@ async def update_adset(adset_id: str, frequency_control_specs: List[Dict[str, An
|
|
|
270
270
|
current_details = json.loads(current_details_json)
|
|
271
271
|
|
|
272
272
|
# Start the callback server if not already running
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
273
|
+
try:
|
|
274
|
+
port = start_callback_server()
|
|
275
|
+
|
|
276
|
+
# Generate confirmation URL with properly encoded parameters
|
|
277
|
+
changes_json = json.dumps(changes)
|
|
278
|
+
encoded_changes = urllib.parse.quote(changes_json)
|
|
279
|
+
confirmation_url = f"http://localhost:{port}/confirm-update?adset_id={adset_id}&token={access_token}&changes={encoded_changes}"
|
|
280
|
+
except Exception as e:
|
|
281
|
+
return json.dumps({
|
|
282
|
+
"error": "Callback server disabled",
|
|
283
|
+
"message": f"Cannot create confirmation URL: {str(e)}",
|
|
284
|
+
"suggestion": "Manual update confirmation not available when META_ADS_DISABLE_CALLBACK_SERVER is set",
|
|
285
|
+
"adset_id": adset_id,
|
|
286
|
+
"proposed_changes": changes
|
|
287
|
+
}, indent=2)
|
|
279
288
|
|
|
280
289
|
# Reset the update confirmation
|
|
281
290
|
update_confirmation.clear()
|
|
@@ -216,22 +216,27 @@ class AuthManager:
|
|
|
216
216
|
return self.token_info.access_token
|
|
217
217
|
|
|
218
218
|
# Start the callback server if not already running
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
219
|
+
try:
|
|
220
|
+
port = start_callback_server()
|
|
221
|
+
|
|
222
|
+
# Update redirect URI with the actual port
|
|
223
|
+
self.redirect_uri = f"http://localhost:{port}/callback"
|
|
224
|
+
|
|
225
|
+
# Generate the auth URL
|
|
226
|
+
auth_url = self.get_auth_url()
|
|
227
|
+
|
|
228
|
+
# Open browser with auth URL
|
|
229
|
+
logger.info(f"Opening browser with URL: {auth_url}")
|
|
230
|
+
webbrowser.open(auth_url)
|
|
231
|
+
|
|
232
|
+
# We don't wait for the token here anymore
|
|
233
|
+
# The token will be processed by the callback server
|
|
234
|
+
# Just return None to indicate we've started the flow
|
|
235
|
+
return None
|
|
236
|
+
except Exception as e:
|
|
237
|
+
logger.error(f"Failed to start callback server: {e}")
|
|
238
|
+
logger.info("Callback server disabled. OAuth authentication flow cannot be used.")
|
|
239
|
+
return None
|
|
235
240
|
|
|
236
241
|
def get_access_token(self) -> Optional[str]:
|
|
237
242
|
"""
|
|
@@ -477,7 +482,14 @@ def login():
|
|
|
477
482
|
|
|
478
483
|
try:
|
|
479
484
|
# Start the callback server first
|
|
480
|
-
|
|
485
|
+
try:
|
|
486
|
+
port = start_callback_server()
|
|
487
|
+
except Exception as callback_error:
|
|
488
|
+
print(f"Error: {callback_error}")
|
|
489
|
+
print("Callback server is disabled. Please use alternative authentication methods:")
|
|
490
|
+
print("- Set PIPEBOARD_API_TOKEN environment variable for Pipeboard authentication")
|
|
491
|
+
print("- Or provide a direct META_ACCESS_TOKEN environment variable")
|
|
492
|
+
return
|
|
481
493
|
|
|
482
494
|
# Get the auth URL and open the browser
|
|
483
495
|
auth_url = auth_manager.get_auth_url()
|
|
@@ -90,14 +90,23 @@ async def get_login_link(access_token: str = None) -> str:
|
|
|
90
90
|
# IMPORTANT: Start the callback server first by calling our helper function
|
|
91
91
|
# This ensures the server is ready before we provide the URL to the user
|
|
92
92
|
logger.info("Starting callback server for authentication")
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
93
|
+
try:
|
|
94
|
+
port = start_callback_server()
|
|
95
|
+
logger.info(f"Callback server started on port {port}")
|
|
96
|
+
|
|
97
|
+
# Generate direct login URL
|
|
98
|
+
auth_manager.redirect_uri = f"http://localhost:{port}/callback" # Ensure port is set correctly
|
|
99
|
+
logger.info(f"Setting redirect URI to {auth_manager.redirect_uri}")
|
|
100
|
+
login_url = auth_manager.get_auth_url()
|
|
101
|
+
logger.info(f"Generated login URL: {login_url}")
|
|
102
|
+
except Exception as e:
|
|
103
|
+
logger.error(f"Failed to start callback server: {e}")
|
|
104
|
+
return json.dumps({
|
|
105
|
+
"error": "Callback server disabled",
|
|
106
|
+
"message": str(e),
|
|
107
|
+
"suggestion": "Use Pipeboard authentication (set PIPEBOARD_API_TOKEN) or provide a direct access token",
|
|
108
|
+
"authentication_method": "meta_oauth_disabled"
|
|
109
|
+
}, indent=2)
|
|
101
110
|
|
|
102
111
|
# Check if we can exchange for long-lived tokens
|
|
103
112
|
token_exchange_supported = bool(META_APP_SECRET)
|
|
@@ -917,7 +917,16 @@ def start_callback_server() -> int:
|
|
|
917
917
|
|
|
918
918
|
Returns:
|
|
919
919
|
Port number the server is running on
|
|
920
|
+
|
|
921
|
+
Raises:
|
|
922
|
+
Exception: If callback server is disabled via META_ADS_DISABLE_CALLBACK_SERVER environment variable
|
|
920
923
|
"""
|
|
924
|
+
# Check if callback server is disabled via environment variable
|
|
925
|
+
if os.environ.get("META_ADS_DISABLE_CALLBACK_SERVER"):
|
|
926
|
+
logger.info("Callback server disabled via META_ADS_DISABLE_CALLBACK_SERVER environment variable")
|
|
927
|
+
print("Callback server is disabled. OAuth authentication flow cannot be used.")
|
|
928
|
+
raise Exception("Callback server disabled via META_ADS_DISABLE_CALLBACK_SERVER environment variable. Use alternative authentication methods.")
|
|
929
|
+
|
|
921
930
|
global callback_server_thread, callback_server_running, callback_server_port, callback_server_instance, server_shutdown_timer
|
|
922
931
|
|
|
923
932
|
with callback_server_lock:
|