meta-ads-mcp 0.3.0__tar.gz → 0.3.2__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.
Files changed (36) hide show
  1. meta_ads_mcp-0.3.2/Dockerfile +25 -0
  2. {meta_ads_mcp-0.3.0 → meta_ads_mcp-0.3.2}/PKG-INFO +44 -114
  3. {meta_ads_mcp-0.3.0 → meta_ads_mcp-0.3.2}/README.md +42 -112
  4. {meta_ads_mcp-0.3.0 → meta_ads_mcp-0.3.2}/meta_ads_mcp/__init__.py +1 -1
  5. {meta_ads_mcp-0.3.0 → meta_ads_mcp-0.3.2}/meta_ads_mcp/api.py +57 -3
  6. {meta_ads_mcp-0.3.0 → meta_ads_mcp-0.3.2}/meta_ads_mcp/core/adsets.py +1 -1
  7. {meta_ads_mcp-0.3.0 → meta_ads_mcp-0.3.2}/meta_ads_mcp/core/api.py +2 -2
  8. {meta_ads_mcp-0.3.0 → meta_ads_mcp-0.3.2}/meta_ads_mcp/core/auth.py +15 -4
  9. {meta_ads_mcp-0.3.0 → meta_ads_mcp-0.3.2}/meta_ads_mcp/core/authentication.py +1 -1
  10. {meta_ads_mcp-0.3.0 → meta_ads_mcp-0.3.2}/meta_ads_mcp/core/callback_server.py +55 -1
  11. {meta_ads_mcp-0.3.0 → meta_ads_mcp-0.3.2}/meta_ads_mcp/core/pipeboard_auth.py +1 -1
  12. {meta_ads_mcp-0.3.0 → meta_ads_mcp-0.3.2}/pyproject.toml +2 -2
  13. meta_ads_mcp-0.3.2/smithery.yaml +33 -0
  14. {meta_ads_mcp-0.3.0 → meta_ads_mcp-0.3.2}/test_pipeboard_auth.py +1 -1
  15. {meta_ads_mcp-0.3.0 → meta_ads_mcp-0.3.2}/.gitignore +0 -0
  16. {meta_ads_mcp-0.3.0 → meta_ads_mcp-0.3.2}/LICENSE +0 -0
  17. {meta_ads_mcp-0.3.0 → meta_ads_mcp-0.3.2}/META_API_NOTES.md +0 -0
  18. {meta_ads_mcp-0.3.0 → meta_ads_mcp-0.3.2}/debug_meta_api_tool.py +0 -0
  19. {meta_ads_mcp-0.3.0 → meta_ads_mcp-0.3.2}/debug_token_flow.py +0 -0
  20. {meta_ads_mcp-0.3.0 → meta_ads_mcp-0.3.2}/future_improvements.md +0 -0
  21. {meta_ads_mcp-0.3.0 → meta_ads_mcp-0.3.2}/images/meta-ads-example.png +0 -0
  22. {meta_ads_mcp-0.3.0 → meta_ads_mcp-0.3.2}/meta-ads-mcp +0 -0
  23. {meta_ads_mcp-0.3.0 → meta_ads_mcp-0.3.2}/meta_ads_auth.sh +0 -0
  24. {meta_ads_mcp-0.3.0 → meta_ads_mcp-0.3.2}/meta_ads_mcp/__main__.py +0 -0
  25. {meta_ads_mcp-0.3.0 → meta_ads_mcp-0.3.2}/meta_ads_mcp/core/__init__.py +0 -0
  26. {meta_ads_mcp-0.3.0 → meta_ads_mcp-0.3.2}/meta_ads_mcp/core/accounts.py +0 -0
  27. {meta_ads_mcp-0.3.0 → meta_ads_mcp-0.3.2}/meta_ads_mcp/core/ads.py +0 -0
  28. {meta_ads_mcp-0.3.0 → meta_ads_mcp-0.3.2}/meta_ads_mcp/core/campaigns.py +0 -0
  29. {meta_ads_mcp-0.3.0 → meta_ads_mcp-0.3.2}/meta_ads_mcp/core/insights.py +0 -0
  30. {meta_ads_mcp-0.3.0 → meta_ads_mcp-0.3.2}/meta_ads_mcp/core/resources.py +0 -0
  31. {meta_ads_mcp-0.3.0 → meta_ads_mcp-0.3.2}/meta_ads_mcp/core/server.py +0 -0
  32. {meta_ads_mcp-0.3.0 → meta_ads_mcp-0.3.2}/meta_ads_mcp/core/utils.py +0 -0
  33. {meta_ads_mcp-0.3.0 → meta_ads_mcp-0.3.2}/meta_auth_test.sh +0 -0
  34. {meta_ads_mcp-0.3.0 → meta_ads_mcp-0.3.2}/requirements.txt +0 -0
  35. {meta_ads_mcp-0.3.0 → meta_ads_mcp-0.3.2}/setup.py +0 -0
  36. {meta_ads_mcp-0.3.0 → meta_ads_mcp-0.3.2}/test_meta_ads_auth.py +0 -0
@@ -0,0 +1,25 @@
1
+ FROM python:3.11-slim
2
+
3
+ # Install system dependencies
4
+ RUN apt-get update && \
5
+ apt-get install -y --no-install-recommends gcc && \
6
+ rm -rf /var/lib/apt/lists/*
7
+
8
+ # Set working directory
9
+ WORKDIR /app
10
+
11
+ # Install uv
12
+ RUN pip install --upgrade pip && \
13
+ pip install uv
14
+
15
+ # Copy requirements file
16
+ COPY requirements.txt .
17
+
18
+ # Install dependencies using uv with --system flag
19
+ RUN uv pip install --system -r requirements.txt
20
+
21
+ # Copy the rest of the application
22
+ COPY . .
23
+
24
+ # Command to run the Meta Ads MCP server
25
+ CMD ["python", "-m", "meta_ads_mcp"]
@@ -1,10 +1,10 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: meta-ads-mcp
3
- Version: 0.3.0
3
+ Version: 0.3.2
4
4
  Summary: Model Calling Protocol (MCP) plugin for interacting with Meta Ads API
5
5
  Project-URL: Homepage, https://github.com/nictuku/meta-ads-mcp
6
6
  Project-URL: Bug Tracker, https://github.com/nictuku/meta-ads-mcp/issues
7
- Author-email: Your Name <your.email@example.com>
7
+ Author-email: Yves Junqueira <yves.junqueira@gmail.com>
8
8
  License: MIT
9
9
  License-File: LICENSE
10
10
  Keywords: ads,api,claude,facebook,mcp,meta
@@ -31,7 +31,7 @@ A [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) server for in
31
31
  <img width="380" height="200" src="https://glama.ai/mcp/servers/@pipeboard-co/meta-ads-mcp/badge" alt="Meta Ads MCP server" />
32
32
  </a>
33
33
 
34
- Screenhot: using an LLM to understand your ad performance.
34
+ Screenshot: using an LLM to understand your ad performance.
35
35
 
36
36
  ![Meta Ads MCP in action: Visualize ad performance metrics and creative details directly in Claude or your favorite MCP client, with rich insights about campaign reach, engagement, and costs](./images/meta-ads-example.png)
37
37
 
@@ -55,11 +55,7 @@ Screenhot: using an LLM to understand your ad performance.
55
55
  When using uv no specific installation is needed. We can use uvx to directly run meta-ads-mcp:
56
56
 
57
57
  ```bash
58
- # RECOMMENDED: Use with Pipeboard authentication
59
- export PIPEBOARD_API_TOKEN=your_pipeboard_token # Get your token at https://pipeboard.co
60
- uvx meta-ads-mcp
61
-
62
- # Alternative: Use with direct Meta authentication
58
+ # Run with Meta authentication
63
59
  uvx meta-ads-mcp --app-id YOUR_META_ADS_APP_ID
64
60
  ```
65
61
 
@@ -87,50 +83,26 @@ pip install meta-ads-mcp
87
83
  After installation, you can run it as:
88
84
 
89
85
  ```bash
90
- # RECOMMENDED: Use with Pipeboard authentication
91
- export PIPEBOARD_API_TOKEN=your_pipeboard_token # Get your token at https://pipeboard.co
92
- python -m meta_ads_mcp
93
-
94
- # Alternative: Use with direct Meta authentication
86
+ # Run with Meta authentication
95
87
  python -m meta_ads_mcp --app-id YOUR_META_ADS_APP_ID
96
88
  ```
97
89
 
98
90
  ## Configuration
99
91
 
100
- ### Quick Start with Pipeboard Authentication (Recommended)
101
-
102
- The easiest way to configure Meta Ads MCP is using Pipeboard authentication:
92
+ ### Create a Meta Developer App (Required)
103
93
 
104
- 1. Sign up at [Pipeboard.co](https://pipeboard.co) and generate an API token - **Get your free token at [https://pipeboard.co](https://pipeboard.co)**
105
- 2. Set the environment variable:
106
- ```bash
107
- export PIPEBOARD_API_TOKEN=your_pipeboard_token # Token obtainable via https://pipeboard.co
108
- ```
109
- 3. Run meta-ads-mcp without needing to set up a Meta Developer App:
110
- ```bash
111
- uvx meta-ads-mcp
112
- ```
94
+ Before using the MCP server, you'll need to set up a Meta Developer App:
113
95
 
114
- This method provides longer-lived tokens (60 days), simplified setup, and automatic token renewal.
96
+ 1. Go to [Meta for Developers](https://developers.facebook.com/) and create a new app
97
+ 2. Choose the "Consumer" app type
98
+ 3. In your app settings, add the "Marketing API" product
99
+ 4. Configure your app's OAuth redirect URI to include `http://localhost:8888/callback`
100
+ 5. Note your App ID (Client ID) for use with the MCP
115
101
 
116
102
  ### Usage with Cursor or Claude Desktop
117
103
 
118
104
  Add this to your `claude_desktop_config.json` to integrate with Claude or `~/.cursor/mcp.json` to integrate with Cursor:
119
105
 
120
- ```json
121
- "mcpServers": {
122
- "meta-ads": {
123
- "command": "uvx",
124
- "args": ["meta-ads-mcp"],
125
- "env": {
126
- "PIPEBOARD_API_TOKEN": "your_pipeboard_token" // Token obtainable via https://pipeboard.co
127
- }
128
- }
129
- }
130
- ```
131
-
132
- Or if you prefer direct Meta authentication (using your own Facebook app):
133
-
134
106
  ```json
135
107
  "mcpServers": {
136
108
  "meta-ads": {
@@ -274,54 +246,13 @@ Or if you prefer direct Meta authentication (using your own Facebook app):
274
246
 
275
247
  16. `mcp_meta_ads_get_login_link`
276
248
  - Get a clickable login link for Meta Ads authentication
277
- - NOTE: This method should only be used if you're using your own Facebook app. If using Pipeboard authentication (recommended), set the PIPEBOARD_API_TOKEN environment variable instead (token obtainable via https://pipeboard.co).
278
249
  - Inputs:
279
250
  - `access_token` (optional): Meta API access token (will use cached token if not provided)
280
251
  - Returns: A clickable resource link for Meta authentication
281
252
 
282
- ## Create a Meta Developer App
283
-
284
- Before using the MCP server, you'll need to set up a Meta Developer App:
285
-
286
- 1. Go to [Meta for Developers](https://developers.facebook.com/) and create a new app
287
- 2. Choose the "Consumer" app type
288
- 3. In your app settings, add the "Marketing API" product
289
- 4. Configure your app's OAuth redirect URI to include `http://localhost:8888/callback`
290
- 5. Note your App ID (Client ID) for use with the MCP
291
-
292
253
  ## Authentication
293
254
 
294
- The Meta Ads MCP supports two authentication methods:
295
-
296
- ### 1. Pipeboard Authentication (Recommended ⭐)
297
-
298
- This method uses [Pipeboard.co](https://pipeboard.co) to manage Meta API authentication, providing longer-lived tokens and a simplified flow:
299
-
300
- 1. **Get your Pipeboard token**: Sign up at [https://pipeboard.co](https://pipeboard.co) to generate your free API token
301
- 2. Set the `PIPEBOARD_API_TOKEN` environment variable with your token:
302
- ```bash
303
- export PIPEBOARD_API_TOKEN=your_pipeboard_token
304
- ```
305
- 3. Run the Meta Ads MCP normally - it will automatically detect and use Pipeboard authentication:
306
- ```bash
307
- uvx meta-ads-mcp
308
- ```
309
- 4. The first time you run a command, you'll be provided with a login URL to authorize with Meta
310
-
311
- **Benefits of Pipeboard authentication:**
312
- - ✅ Longer-lived tokens (60 days)
313
- - ✅ No need to configure a Meta Developer App
314
- - ✅ Simpler setup with just an API token
315
- - ✅ Automatic token renewal
316
-
317
- To test the Pipeboard authentication flow:
318
- ```bash
319
- python test_pipeboard_auth.py --api-token YOUR_PIPEBOARD_TOKEN
320
- ```
321
-
322
- ### 2. Direct Meta OAuth (Legacy)
323
-
324
- The traditional OAuth 2.0 flow designed for desktop apps. This method should only be used if you are using your own Facebook app instead of Pipeboard.
255
+ The Meta Ads MCP uses Meta's OAuth 2.0 authentication flow, designed for desktop apps:
325
256
 
326
257
  When authenticating, it will:
327
258
 
@@ -330,7 +261,7 @@ When authenticating, it will:
330
261
  3. Ask you to authorize the app
331
262
  4. Redirect back to the local server to extract and store the token securely
332
263
 
333
- This method requires you to [create a Meta Developer App](#create-a-meta-developer-app) first.
264
+ This method requires you to [create a Meta Developer App](#create-a-meta-developer-app) as described above.
334
265
 
335
266
  ## Troubleshooting and Logging
336
267
 
@@ -348,19 +279,11 @@ Log files are stored in a platform-specific location:
348
279
 
349
280
  #### Authentication Issues
350
281
 
351
- If you're having authentication problems:
352
-
353
- 1. **Recommended: Use Pipeboard Authentication**
354
- - Set `export PIPEBOARD_API_TOKEN=your_token` and retry
355
- - This provides longer-lived tokens and better reliability
356
- - Verify your token in the Pipeboard dashboard
357
-
358
- 2. For App ID issues (when using direct authentication):
359
- If you encounter errors like `(#200) Provide valid app ID`, check the following:
360
- - Ensure you've set up a Meta Developer App correctly
361
- - Verify that you're passing the correct App ID using one of these methods:
362
- - Set the `META_APP_ID` environment variable: `export META_APP_ID=your_app_id`
363
- - Pass it as a command-line argument: `meta-ads-mcp --app-id your_app_id`
282
+ If you encounter errors like `(#200) Provide valid app ID`, check the following:
283
+ - Ensure you've set up a Meta Developer App correctly
284
+ - Verify that you're passing the correct App ID using one of these methods:
285
+ - Set the `META_APP_ID` environment variable: `export META_APP_ID=your_app_id`
286
+ - Pass it as a command-line argument: `meta-ads-mcp --app-id your_app_id`
364
287
 
365
288
  #### API Errors
366
289
 
@@ -399,15 +322,24 @@ uvx meta-ads-mcp --app-id=your_app_id
399
322
  The Meta Ads MCP follows security best practices:
400
323
 
401
324
  1. Tokens are cached in a platform-specific secure location:
402
- - Windows: `%APPDATA%\meta-ads-mcp\token_cache.json` or `%APPDATA%\meta-ads-mcp\pipeboard_token_cache.json`
403
- - macOS: `~/Library/Application Support/meta-ads-mcp/token_cache.json` or `~/Library/Application Support/meta-ads-mcp/pipeboard_token_cache.json`
404
- - Linux: `~/.config/meta-ads-mcp/token_cache.json` or `~/.config/meta-ads-mcp/pipeboard_token_cache.json`
325
+ - Windows: `%APPDATA%\meta-ads-mcp\token_cache.json`
326
+ - macOS: `~/Library/Application Support/meta-ads-mcp/token_cache.json`
327
+ - Linux: `~/.config/meta-ads-mcp/token_cache.json`
405
328
 
406
329
  2. You do not need to provide your access token for each command; it will be automatically retrieved from the cache.
407
330
 
408
- 3. You can set the following environment variables instead of passing them as arguments:
409
- - `META_APP_ID`: Your Meta App ID (Client ID) - for direct OAuth method
410
- - `PIPEBOARD_API_TOKEN`: Your Pipeboard API token - for Pipeboard authentication method
331
+ 3. You can set the `META_APP_ID` environment variable instead of passing it as an argument:
332
+ ```bash
333
+ export META_APP_ID=your_app_id
334
+ uvx meta-ads-mcp
335
+ ```
336
+
337
+ 4. You can provide a direct access token using the `META_ACCESS_TOKEN` environment variable. This bypasses both the local token cache and the Pipeboard authentication method:
338
+ ```bash
339
+ export META_ACCESS_TOKEN=your_access_token
340
+ uvx meta-ads-mcp
341
+ ```
342
+ This is useful for CI/CD pipelines or when you already have a valid access token from another source.
411
343
 
412
344
  ## Testing
413
345
 
@@ -429,10 +361,9 @@ python test_meta_ads_auth.py --app-id YOUR_APP_ID --force-login
429
361
 
430
362
  When using the Meta Ads MCP with an LLM interface (like Claude):
431
363
 
432
- 1. If using direct Meta authentication (your own Facebook app), test authentication by calling the `mcp_meta_ads_get_login_link` tool
433
- 2. If using Pipeboard authentication (recommended), ensure the PIPEBOARD_API_TOKEN environment variable is set (token obtainable via https://pipeboard.co)
434
- 3. Verify account access by calling `mcp_meta_ads_get_ad_accounts`
435
- 4. Check specific account details with `mcp_meta_ads_get_account_info`
364
+ 1. Test authentication by calling the `mcp_meta_ads_get_login_link` tool
365
+ 2. Verify account access by calling `mcp_meta_ads_get_ad_accounts`
366
+ 3. Check specific account details with `mcp_meta_ads_get_account_info`
436
367
 
437
368
  These functions will automatically handle authentication if needed and provide a clickable login link if required.
438
369
 
@@ -443,20 +374,19 @@ These functions will automatically handle authentication if needed and provide a
443
374
  If you encounter authentication issues:
444
375
 
445
376
  1. When using the LLM interface:
446
- - If using direct Meta authentication (your own Facebook app), use the `mcp_meta_ads_get_login_link` tool to generate a fresh authentication link
447
- - If using Pipeboard authentication (recommended), ensure the PIPEBOARD_API_TOKEN environment variable is set (token obtainable via https://pipeboard.co)
377
+ - Use the `mcp_meta_ads_get_login_link` tool to generate a fresh authentication link
448
378
  - Ensure you click the link and complete the authorization flow in your browser
449
379
  - Check that the callback server is running properly (the tool will report this)
450
380
 
451
- 2. When using Pipeboard authentication:
452
- - Verify your `PIPEBOARD_API_TOKEN` is set correctly (token obtainable via https://pipeboard.co)
453
- - Check if you need to complete the authorization process by visiting the provided login URL
454
- - Try forcing a new login: `python test_pipeboard_auth.py --force-login`
455
-
456
- 3. When using direct Meta OAuth:
381
+ 2. When using direct Meta OAuth:
457
382
  - Run with `--force-login` to get a fresh token: `uvx meta-ads-mcp --login --app-id YOUR_APP_ID --force-login`
458
383
  - Make sure the terminal has permissions to open a browser window
459
384
 
385
+ 3. Skip authentication entirely by providing a token directly:
386
+ - If you already have a valid access token, you can bypass the authentication flow:
387
+ - `export META_ACCESS_TOKEN=your_access_token`
388
+ - This will ignore both the local token cache and the Pipeboard authentication
389
+
460
390
  ### API Errors
461
391
 
462
392
  If you receive errors from the Meta API:
@@ -8,7 +8,7 @@ A [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) server for in
8
8
  <img width="380" height="200" src="https://glama.ai/mcp/servers/@pipeboard-co/meta-ads-mcp/badge" alt="Meta Ads MCP server" />
9
9
  </a>
10
10
 
11
- Screenhot: using an LLM to understand your ad performance.
11
+ Screenshot: using an LLM to understand your ad performance.
12
12
 
13
13
  ![Meta Ads MCP in action: Visualize ad performance metrics and creative details directly in Claude or your favorite MCP client, with rich insights about campaign reach, engagement, and costs](./images/meta-ads-example.png)
14
14
 
@@ -32,11 +32,7 @@ Screenhot: using an LLM to understand your ad performance.
32
32
  When using uv no specific installation is needed. We can use uvx to directly run meta-ads-mcp:
33
33
 
34
34
  ```bash
35
- # RECOMMENDED: Use with Pipeboard authentication
36
- export PIPEBOARD_API_TOKEN=your_pipeboard_token # Get your token at https://pipeboard.co
37
- uvx meta-ads-mcp
38
-
39
- # Alternative: Use with direct Meta authentication
35
+ # Run with Meta authentication
40
36
  uvx meta-ads-mcp --app-id YOUR_META_ADS_APP_ID
41
37
  ```
42
38
 
@@ -64,50 +60,26 @@ pip install meta-ads-mcp
64
60
  After installation, you can run it as:
65
61
 
66
62
  ```bash
67
- # RECOMMENDED: Use with Pipeboard authentication
68
- export PIPEBOARD_API_TOKEN=your_pipeboard_token # Get your token at https://pipeboard.co
69
- python -m meta_ads_mcp
70
-
71
- # Alternative: Use with direct Meta authentication
63
+ # Run with Meta authentication
72
64
  python -m meta_ads_mcp --app-id YOUR_META_ADS_APP_ID
73
65
  ```
74
66
 
75
67
  ## Configuration
76
68
 
77
- ### Quick Start with Pipeboard Authentication (Recommended)
78
-
79
- The easiest way to configure Meta Ads MCP is using Pipeboard authentication:
69
+ ### Create a Meta Developer App (Required)
80
70
 
81
- 1. Sign up at [Pipeboard.co](https://pipeboard.co) and generate an API token - **Get your free token at [https://pipeboard.co](https://pipeboard.co)**
82
- 2. Set the environment variable:
83
- ```bash
84
- export PIPEBOARD_API_TOKEN=your_pipeboard_token # Token obtainable via https://pipeboard.co
85
- ```
86
- 3. Run meta-ads-mcp without needing to set up a Meta Developer App:
87
- ```bash
88
- uvx meta-ads-mcp
89
- ```
71
+ Before using the MCP server, you'll need to set up a Meta Developer App:
90
72
 
91
- This method provides longer-lived tokens (60 days), simplified setup, and automatic token renewal.
73
+ 1. Go to [Meta for Developers](https://developers.facebook.com/) and create a new app
74
+ 2. Choose the "Consumer" app type
75
+ 3. In your app settings, add the "Marketing API" product
76
+ 4. Configure your app's OAuth redirect URI to include `http://localhost:8888/callback`
77
+ 5. Note your App ID (Client ID) for use with the MCP
92
78
 
93
79
  ### Usage with Cursor or Claude Desktop
94
80
 
95
81
  Add this to your `claude_desktop_config.json` to integrate with Claude or `~/.cursor/mcp.json` to integrate with Cursor:
96
82
 
97
- ```json
98
- "mcpServers": {
99
- "meta-ads": {
100
- "command": "uvx",
101
- "args": ["meta-ads-mcp"],
102
- "env": {
103
- "PIPEBOARD_API_TOKEN": "your_pipeboard_token" // Token obtainable via https://pipeboard.co
104
- }
105
- }
106
- }
107
- ```
108
-
109
- Or if you prefer direct Meta authentication (using your own Facebook app):
110
-
111
83
  ```json
112
84
  "mcpServers": {
113
85
  "meta-ads": {
@@ -251,54 +223,13 @@ Or if you prefer direct Meta authentication (using your own Facebook app):
251
223
 
252
224
  16. `mcp_meta_ads_get_login_link`
253
225
  - Get a clickable login link for Meta Ads authentication
254
- - NOTE: This method should only be used if you're using your own Facebook app. If using Pipeboard authentication (recommended), set the PIPEBOARD_API_TOKEN environment variable instead (token obtainable via https://pipeboard.co).
255
226
  - Inputs:
256
227
  - `access_token` (optional): Meta API access token (will use cached token if not provided)
257
228
  - Returns: A clickable resource link for Meta authentication
258
229
 
259
- ## Create a Meta Developer App
260
-
261
- Before using the MCP server, you'll need to set up a Meta Developer App:
262
-
263
- 1. Go to [Meta for Developers](https://developers.facebook.com/) and create a new app
264
- 2. Choose the "Consumer" app type
265
- 3. In your app settings, add the "Marketing API" product
266
- 4. Configure your app's OAuth redirect URI to include `http://localhost:8888/callback`
267
- 5. Note your App ID (Client ID) for use with the MCP
268
-
269
230
  ## Authentication
270
231
 
271
- The Meta Ads MCP supports two authentication methods:
272
-
273
- ### 1. Pipeboard Authentication (Recommended ⭐)
274
-
275
- This method uses [Pipeboard.co](https://pipeboard.co) to manage Meta API authentication, providing longer-lived tokens and a simplified flow:
276
-
277
- 1. **Get your Pipeboard token**: Sign up at [https://pipeboard.co](https://pipeboard.co) to generate your free API token
278
- 2. Set the `PIPEBOARD_API_TOKEN` environment variable with your token:
279
- ```bash
280
- export PIPEBOARD_API_TOKEN=your_pipeboard_token
281
- ```
282
- 3. Run the Meta Ads MCP normally - it will automatically detect and use Pipeboard authentication:
283
- ```bash
284
- uvx meta-ads-mcp
285
- ```
286
- 4. The first time you run a command, you'll be provided with a login URL to authorize with Meta
287
-
288
- **Benefits of Pipeboard authentication:**
289
- - ✅ Longer-lived tokens (60 days)
290
- - ✅ No need to configure a Meta Developer App
291
- - ✅ Simpler setup with just an API token
292
- - ✅ Automatic token renewal
293
-
294
- To test the Pipeboard authentication flow:
295
- ```bash
296
- python test_pipeboard_auth.py --api-token YOUR_PIPEBOARD_TOKEN
297
- ```
298
-
299
- ### 2. Direct Meta OAuth (Legacy)
300
-
301
- The traditional OAuth 2.0 flow designed for desktop apps. This method should only be used if you are using your own Facebook app instead of Pipeboard.
232
+ The Meta Ads MCP uses Meta's OAuth 2.0 authentication flow, designed for desktop apps:
302
233
 
303
234
  When authenticating, it will:
304
235
 
@@ -307,7 +238,7 @@ When authenticating, it will:
307
238
  3. Ask you to authorize the app
308
239
  4. Redirect back to the local server to extract and store the token securely
309
240
 
310
- This method requires you to [create a Meta Developer App](#create-a-meta-developer-app) first.
241
+ This method requires you to [create a Meta Developer App](#create-a-meta-developer-app) as described above.
311
242
 
312
243
  ## Troubleshooting and Logging
313
244
 
@@ -325,19 +256,11 @@ Log files are stored in a platform-specific location:
325
256
 
326
257
  #### Authentication Issues
327
258
 
328
- If you're having authentication problems:
329
-
330
- 1. **Recommended: Use Pipeboard Authentication**
331
- - Set `export PIPEBOARD_API_TOKEN=your_token` and retry
332
- - This provides longer-lived tokens and better reliability
333
- - Verify your token in the Pipeboard dashboard
334
-
335
- 2. For App ID issues (when using direct authentication):
336
- If you encounter errors like `(#200) Provide valid app ID`, check the following:
337
- - Ensure you've set up a Meta Developer App correctly
338
- - Verify that you're passing the correct App ID using one of these methods:
339
- - Set the `META_APP_ID` environment variable: `export META_APP_ID=your_app_id`
340
- - Pass it as a command-line argument: `meta-ads-mcp --app-id your_app_id`
259
+ If you encounter errors like `(#200) Provide valid app ID`, check the following:
260
+ - Ensure you've set up a Meta Developer App correctly
261
+ - Verify that you're passing the correct App ID using one of these methods:
262
+ - Set the `META_APP_ID` environment variable: `export META_APP_ID=your_app_id`
263
+ - Pass it as a command-line argument: `meta-ads-mcp --app-id your_app_id`
341
264
 
342
265
  #### API Errors
343
266
 
@@ -376,15 +299,24 @@ uvx meta-ads-mcp --app-id=your_app_id
376
299
  The Meta Ads MCP follows security best practices:
377
300
 
378
301
  1. Tokens are cached in a platform-specific secure location:
379
- - Windows: `%APPDATA%\meta-ads-mcp\token_cache.json` or `%APPDATA%\meta-ads-mcp\pipeboard_token_cache.json`
380
- - macOS: `~/Library/Application Support/meta-ads-mcp/token_cache.json` or `~/Library/Application Support/meta-ads-mcp/pipeboard_token_cache.json`
381
- - Linux: `~/.config/meta-ads-mcp/token_cache.json` or `~/.config/meta-ads-mcp/pipeboard_token_cache.json`
302
+ - Windows: `%APPDATA%\meta-ads-mcp\token_cache.json`
303
+ - macOS: `~/Library/Application Support/meta-ads-mcp/token_cache.json`
304
+ - Linux: `~/.config/meta-ads-mcp/token_cache.json`
382
305
 
383
306
  2. You do not need to provide your access token for each command; it will be automatically retrieved from the cache.
384
307
 
385
- 3. You can set the following environment variables instead of passing them as arguments:
386
- - `META_APP_ID`: Your Meta App ID (Client ID) - for direct OAuth method
387
- - `PIPEBOARD_API_TOKEN`: Your Pipeboard API token - for Pipeboard authentication method
308
+ 3. You can set the `META_APP_ID` environment variable instead of passing it as an argument:
309
+ ```bash
310
+ export META_APP_ID=your_app_id
311
+ uvx meta-ads-mcp
312
+ ```
313
+
314
+ 4. You can provide a direct access token using the `META_ACCESS_TOKEN` environment variable. This bypasses both the local token cache and the Pipeboard authentication method:
315
+ ```bash
316
+ export META_ACCESS_TOKEN=your_access_token
317
+ uvx meta-ads-mcp
318
+ ```
319
+ This is useful for CI/CD pipelines or when you already have a valid access token from another source.
388
320
 
389
321
  ## Testing
390
322
 
@@ -406,10 +338,9 @@ python test_meta_ads_auth.py --app-id YOUR_APP_ID --force-login
406
338
 
407
339
  When using the Meta Ads MCP with an LLM interface (like Claude):
408
340
 
409
- 1. If using direct Meta authentication (your own Facebook app), test authentication by calling the `mcp_meta_ads_get_login_link` tool
410
- 2. If using Pipeboard authentication (recommended), ensure the PIPEBOARD_API_TOKEN environment variable is set (token obtainable via https://pipeboard.co)
411
- 3. Verify account access by calling `mcp_meta_ads_get_ad_accounts`
412
- 4. Check specific account details with `mcp_meta_ads_get_account_info`
341
+ 1. Test authentication by calling the `mcp_meta_ads_get_login_link` tool
342
+ 2. Verify account access by calling `mcp_meta_ads_get_ad_accounts`
343
+ 3. Check specific account details with `mcp_meta_ads_get_account_info`
413
344
 
414
345
  These functions will automatically handle authentication if needed and provide a clickable login link if required.
415
346
 
@@ -420,20 +351,19 @@ These functions will automatically handle authentication if needed and provide a
420
351
  If you encounter authentication issues:
421
352
 
422
353
  1. When using the LLM interface:
423
- - If using direct Meta authentication (your own Facebook app), use the `mcp_meta_ads_get_login_link` tool to generate a fresh authentication link
424
- - If using Pipeboard authentication (recommended), ensure the PIPEBOARD_API_TOKEN environment variable is set (token obtainable via https://pipeboard.co)
354
+ - Use the `mcp_meta_ads_get_login_link` tool to generate a fresh authentication link
425
355
  - Ensure you click the link and complete the authorization flow in your browser
426
356
  - Check that the callback server is running properly (the tool will report this)
427
357
 
428
- 2. When using Pipeboard authentication:
429
- - Verify your `PIPEBOARD_API_TOKEN` is set correctly (token obtainable via https://pipeboard.co)
430
- - Check if you need to complete the authorization process by visiting the provided login URL
431
- - Try forcing a new login: `python test_pipeboard_auth.py --force-login`
432
-
433
- 3. When using direct Meta OAuth:
358
+ 2. When using direct Meta OAuth:
434
359
  - Run with `--force-login` to get a fresh token: `uvx meta-ads-mcp --login --app-id YOUR_APP_ID --force-login`
435
360
  - Make sure the terminal has permissions to open a browser window
436
361
 
362
+ 3. Skip authentication entirely by providing a token directly:
363
+ - If you already have a valid access token, you can bypass the authentication flow:
364
+ - `export META_ACCESS_TOKEN=your_access_token`
365
+ - This will ignore both the local token cache and the Pipeboard authentication
366
+
437
367
  ### API Errors
438
368
 
439
369
  If you receive errors from the Meta API:
@@ -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.3.0"
10
+ __version__ = "0.3.2"
11
11
 
12
12
  __all__ = [
13
13
  'get_ad_accounts',
@@ -22,7 +22,7 @@ from http.server import HTTPServer, BaseHTTPRequestHandler
22
22
  mcp_server = FastMCP("meta-ads-generated", use_consistent_tool_format=True)
23
23
 
24
24
  # Constants
25
- META_GRAPH_API_VERSION = "v20.0"
25
+ META_GRAPH_API_VERSION = "v22.0"
26
26
  META_GRAPH_API_BASE = f"https://graph.facebook.com/{META_GRAPH_API_VERSION}"
27
27
  USER_AGENT = "meta-ads-mcp/1.0"
28
28
 
@@ -48,6 +48,13 @@ callback_server_port = None
48
48
  # Global token container for communication between threads
49
49
  token_container = {"token": None, "expires_in": None, "user_id": None}
50
50
 
51
+ # Add these at the top of the file with the other global variables
52
+ callback_server_instance = None
53
+ server_shutdown_timer = None
54
+
55
+ # Add this near other constants in the file
56
+ CALLBACK_SERVER_TIMEOUT = 180 # 3 minutes timeout
57
+
51
58
  # Configuration class to store app ID and other config
52
59
  class MetaConfig:
53
60
  _instance = None
@@ -253,7 +260,7 @@ class AuthManager:
253
260
  def get_auth_url(self) -> str:
254
261
  """Generate the Facebook OAuth URL for desktop app flow"""
255
262
  return (
256
- f"https://www.facebook.com/v18.0/dialog/oauth?"
263
+ f"https://www.facebook.com/v22.0/dialog/oauth?"
257
264
  f"client_id={self.app_id}&"
258
265
  f"redirect_uri={self.redirect_uri}&"
259
266
  f"scope={AUTH_SCOPE}&"
@@ -1875,13 +1882,50 @@ async def try_multiple_download_methods(url: str) -> Optional[bytes]:
1875
1882
 
1876
1883
  return None
1877
1884
 
1885
+ def shutdown_callback_server():
1886
+ """Shutdown the callback server if it's running"""
1887
+ global callback_server_thread, callback_server_running, callback_server_port, callback_server_instance, server_shutdown_timer
1888
+
1889
+ with callback_server_lock:
1890
+ if not callback_server_running:
1891
+ print("Callback server is not running")
1892
+ return
1893
+
1894
+ if server_shutdown_timer is not None:
1895
+ server_shutdown_timer.cancel()
1896
+ server_shutdown_timer = None
1897
+
1898
+ print(f"Shutting down callback server on port {callback_server_port}")
1899
+
1900
+ # Shutdown the server if it exists
1901
+ if callback_server_instance:
1902
+ try:
1903
+ callback_server_instance.shutdown()
1904
+ callback_server_instance = None
1905
+ callback_server_running = False
1906
+ print("Callback server has been shut down")
1907
+ except Exception as e:
1908
+ print(f"Error shutting down callback server: {e}")
1909
+ else:
1910
+ print("No server instance to shut down")
1911
+
1878
1912
  def start_callback_server():
1879
1913
  """Start the callback server if it's not already running"""
1880
- global callback_server_thread, callback_server_running, callback_server_port
1914
+ global callback_server_thread, callback_server_running, callback_server_port, callback_server_instance, server_shutdown_timer
1881
1915
 
1882
1916
  with callback_server_lock:
1883
1917
  if callback_server_running:
1884
1918
  print(f"Callback server already running on port {callback_server_port}")
1919
+
1920
+ # Reset the shutdown timer if one exists
1921
+ if server_shutdown_timer is not None:
1922
+ server_shutdown_timer.cancel()
1923
+
1924
+ server_shutdown_timer = threading.Timer(CALLBACK_SERVER_TIMEOUT, shutdown_callback_server)
1925
+ server_shutdown_timer.daemon = True
1926
+ server_shutdown_timer.start()
1927
+ print(f"Reset server shutdown timer to {CALLBACK_SERVER_TIMEOUT} seconds")
1928
+
1885
1929
  return callback_server_port
1886
1930
 
1887
1931
  # Find an available port
@@ -1913,6 +1957,7 @@ def start_callback_server():
1913
1957
 
1914
1958
  # Create and start server in a daemon thread
1915
1959
  server = HTTPServer(('localhost', port), handler_class)
1960
+ callback_server_instance = server
1916
1961
  print(f"Callback server starting on port {port}")
1917
1962
 
1918
1963
  # Create a simple flag to signal when the server is ready
@@ -1942,6 +1987,15 @@ def start_callback_server():
1942
1987
 
1943
1988
  callback_server_running = True
1944
1989
 
1990
+ # Set a timer to shutdown the server after CALLBACK_SERVER_TIMEOUT seconds
1991
+ if server_shutdown_timer is not None:
1992
+ server_shutdown_timer.cancel()
1993
+
1994
+ server_shutdown_timer = threading.Timer(CALLBACK_SERVER_TIMEOUT, shutdown_callback_server)
1995
+ server_shutdown_timer.daemon = True
1996
+ server_shutdown_timer.start()
1997
+ print(f"Server will automatically shut down after {CALLBACK_SERVER_TIMEOUT} seconds of inactivity")
1998
+
1945
1999
  # Verify the server is actually accepting connections
1946
2000
  try:
1947
2001
  with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
@@ -6,7 +6,7 @@ from .api import meta_api_tool, make_api_request
6
6
  from .accounts import get_ad_accounts
7
7
  from .server import mcp_server
8
8
  import asyncio
9
- from .callback_server import start_callback_server, update_confirmation
9
+ from .callback_server import start_callback_server, shutdown_callback_server, update_confirmation
10
10
  import urllib.parse
11
11
 
12
12
 
@@ -6,11 +6,11 @@ import httpx
6
6
  import asyncio
7
7
  import functools
8
8
  import os
9
- from .auth import needs_authentication, get_current_access_token, auth_manager, start_callback_server
9
+ from .auth import needs_authentication, get_current_access_token, auth_manager, start_callback_server, shutdown_callback_server
10
10
  from .utils import logger
11
11
 
12
12
  # Constants
13
- META_GRAPH_API_VERSION = "v20.0"
13
+ META_GRAPH_API_VERSION = "v22.0"
14
14
  META_GRAPH_API_BASE = f"https://graph.facebook.com/{META_GRAPH_API_VERSION}"
15
15
  USER_AGENT = "meta-ads-mcp/1.0"
16
16
 
@@ -13,9 +13,10 @@ import requests
13
13
 
14
14
  # Import from the new callback server module
15
15
  from .callback_server import (
16
- start_callback_server,
16
+ start_callback_server,
17
+ shutdown_callback_server,
17
18
  token_container,
18
- update_confirmation
19
+ callback_server_port
19
20
  )
20
21
 
21
22
  # Import the new Pipeboard authentication
@@ -187,7 +188,7 @@ class AuthManager:
187
188
  def get_auth_url(self) -> str:
188
189
  """Generate the Facebook OAuth URL for desktop app flow"""
189
190
  return (
190
- f"https://www.facebook.com/v18.0/dialog/oauth?"
191
+ f"https://www.facebook.com/v22.0/dialog/oauth?"
191
192
  f"client_id={self.app_id}&"
192
193
  f"redirect_uri={self.redirect_uri}&"
193
194
  f"scope={AUTH_SCOPE}&"
@@ -359,7 +360,7 @@ def exchange_token_for_long_lived(short_lived_token):
359
360
  return None
360
361
 
361
362
  # Make the API request to exchange the token
362
- url = "https://graph.facebook.com/v18.0/oauth/access_token"
363
+ url = "https://graph.facebook.com/v22.0/oauth/access_token"
363
364
  params = {
364
365
  "grant_type": "fb_exchange_token",
365
366
  "client_id": app_id,
@@ -398,6 +399,16 @@ def exchange_token_for_long_lived(short_lived_token):
398
399
 
399
400
  async def get_current_access_token() -> Optional[str]:
400
401
  """Get the current access token from auth manager"""
402
+ # Check for environment variable first - this takes highest precedence
403
+ env_token = os.environ.get("META_ACCESS_TOKEN")
404
+ if env_token:
405
+ logger.debug("Using access token from META_ACCESS_TOKEN environment variable")
406
+ # Basic validation
407
+ if len(env_token) < 20: # Most Meta tokens are much longer
408
+ logger.error(f"TOKEN VALIDATION FAILED: Token from environment variable appears malformed (length: {len(env_token)})")
409
+ return None
410
+ return env_token
411
+
401
412
  # Use the singleton auth manager
402
413
  global auth_manager
403
414
 
@@ -4,7 +4,7 @@ import json
4
4
  import asyncio
5
5
  import os
6
6
  from .api import meta_api_tool
7
- from .auth import start_callback_server, auth_manager, get_current_access_token
7
+ from .auth import start_callback_server, shutdown_callback_server, auth_manager, get_current_access_token
8
8
  from .server import mcp_server
9
9
  from .utils import logger, META_APP_SECRET
10
10
  from .pipeboard_auth import pipeboard_auth_manager
@@ -24,6 +24,11 @@ callback_server_thread = None
24
24
  callback_server_lock = threading.Lock()
25
25
  callback_server_running = False
26
26
  callback_server_port = None
27
+ callback_server_instance = None
28
+ server_shutdown_timer = None
29
+
30
+ # Timeout in seconds before shutting down the callback server
31
+ CALLBACK_SERVER_TIMEOUT = 180 # 3 minutes timeout
27
32
 
28
33
 
29
34
  class CallbackHandler(BaseHTTPRequestHandler):
@@ -877,6 +882,35 @@ class CallbackHandler(BaseHTTPRequestHandler):
877
882
  return
878
883
 
879
884
 
885
+ def shutdown_callback_server():
886
+ """
887
+ Shutdown the callback server if it's running
888
+ """
889
+ global callback_server_thread, callback_server_running, callback_server_port, callback_server_instance, server_shutdown_timer
890
+
891
+ with callback_server_lock:
892
+ if not callback_server_running:
893
+ print("Callback server is not running")
894
+ return
895
+
896
+ if server_shutdown_timer is not None:
897
+ server_shutdown_timer.cancel()
898
+ server_shutdown_timer = None
899
+
900
+ print(f"Shutting down callback server on port {callback_server_port}")
901
+
902
+ # Shutdown the server if it exists
903
+ if callback_server_instance:
904
+ try:
905
+ callback_server_instance.shutdown()
906
+ callback_server_instance = None
907
+ callback_server_running = False
908
+ print("Callback server has been shut down")
909
+ except Exception as e:
910
+ print(f"Error shutting down callback server: {e}")
911
+ else:
912
+ print("No server instance to shut down")
913
+
880
914
  def start_callback_server() -> int:
881
915
  """
882
916
  Start the callback server if it's not already running
@@ -884,11 +918,21 @@ def start_callback_server() -> int:
884
918
  Returns:
885
919
  Port number the server is running on
886
920
  """
887
- global callback_server_thread, callback_server_running, callback_server_port
921
+ global callback_server_thread, callback_server_running, callback_server_port, callback_server_instance, server_shutdown_timer
888
922
 
889
923
  with callback_server_lock:
890
924
  if callback_server_running:
891
925
  print(f"Callback server already running on port {callback_server_port}")
926
+
927
+ # Reset the shutdown timer if one exists
928
+ if server_shutdown_timer is not None:
929
+ server_shutdown_timer.cancel()
930
+
931
+ server_shutdown_timer = threading.Timer(CALLBACK_SERVER_TIMEOUT, shutdown_callback_server)
932
+ server_shutdown_timer.daemon = True
933
+ server_shutdown_timer.start()
934
+ print(f"Reset server shutdown timer to {CALLBACK_SERVER_TIMEOUT} seconds")
935
+
892
936
  return callback_server_port
893
937
 
894
938
  # Find an available port
@@ -909,6 +953,7 @@ def start_callback_server() -> int:
909
953
  try:
910
954
  # Create and start server in a daemon thread
911
955
  server = HTTPServer(('localhost', port), CallbackHandler)
956
+ callback_server_instance = server
912
957
  print(f"Callback server starting on port {port}")
913
958
 
914
959
  # Create a simple flag to signal when the server is ready
@@ -938,6 +983,15 @@ def start_callback_server() -> int:
938
983
 
939
984
  callback_server_running = True
940
985
 
986
+ # Set a timer to shutdown the server after CALLBACK_SERVER_TIMEOUT seconds
987
+ if server_shutdown_timer is not None:
988
+ server_shutdown_timer.cancel()
989
+
990
+ server_shutdown_timer = threading.Timer(CALLBACK_SERVER_TIMEOUT, shutdown_callback_server)
991
+ server_shutdown_timer.daemon = True
992
+ server_shutdown_timer.start()
993
+ print(f"Server will automatically shut down after {CALLBACK_SERVER_TIMEOUT} seconds of inactivity")
994
+
941
995
  # Verify the server is actually accepting connections
942
996
  try:
943
997
  with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
@@ -418,7 +418,7 @@ class PipeboardAuthManager:
418
418
 
419
419
  try:
420
420
  # Make a simple request to the /me endpoint to test the token
421
- META_GRAPH_API_VERSION = "v20.0"
421
+ META_GRAPH_API_VERSION = "v22.0"
422
422
  url = f"https://graph.facebook.com/{META_GRAPH_API_VERSION}/me"
423
423
  headers = {"Authorization": f"Bearer {self.token_info.access_token}"}
424
424
 
@@ -4,12 +4,12 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "meta-ads-mcp"
7
- version = "0.3.0"
7
+ version = "0.3.2"
8
8
  description = "Model Calling Protocol (MCP) plugin for interacting with Meta Ads API"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
11
11
  authors = [
12
- {name = "Your Name", email = "your.email@example.com"},
12
+ {name = "Yves Junqueira", email = "yves.junqueira@gmail.com"},
13
13
  ]
14
14
  keywords = ["meta", "facebook", "ads", "api", "mcp", "claude"]
15
15
  license = {text = "MIT"}
@@ -0,0 +1,33 @@
1
+ startCommand:
2
+ type: stdio
3
+ configSchema:
4
+ type: object
5
+ properties:
6
+ pipeboardApiToken:
7
+ type: string
8
+ description: "Pipeboard API token for Meta authentication (recommended). Get your free token at https://pipeboard.co"
9
+ metaAppId:
10
+ type: string
11
+ description: "Meta App ID (Client ID) for direct OAuth method (only needed if not using Pipeboard authentication)"
12
+ required: []
13
+ commandFunction: |
14
+ (config) => {
15
+ const env = {};
16
+ const args = ["-m", "meta_ads_mcp"];
17
+
18
+ // Add Pipeboard API token to environment if provided (recommended auth method)
19
+ if (config.pipeboardApiToken) {
20
+ env.PIPEBOARD_API_TOKEN = config.pipeboardApiToken;
21
+ }
22
+
23
+ // Add Meta App ID as command-line argument if provided (alternative auth method)
24
+ if (config.metaAppId) {
25
+ args.push("--app-id", config.metaAppId);
26
+ }
27
+
28
+ return {
29
+ command: 'python',
30
+ args: args,
31
+ env: env
32
+ };
33
+ }
@@ -26,7 +26,7 @@ from meta_ads_mcp.core.pipeboard_auth import pipeboard_auth_manager, PIPEBOARD_A
26
26
  from meta_ads_mcp.api import get_ad_accounts
27
27
 
28
28
  # Define Meta Graph API base URL for testing access token directly
29
- META_GRAPH_API_VERSION = "v20.0"
29
+ META_GRAPH_API_VERSION = "v22.0"
30
30
  META_GRAPH_API_BASE = f"https://graph.facebook.com/{META_GRAPH_API_VERSION}"
31
31
 
32
32
  def test_server_connectivity(server_url, port=3000):
File without changes
File without changes
File without changes
File without changes