meta-ads-mcp 0.7.10__py3-none-any.whl → 0.8.0__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 +1 -1
- meta_ads_mcp/core/ads.py +239 -16
- meta_ads_mcp/core/openai_deep_research.py +57 -1
- {meta_ads_mcp-0.7.10.dist-info → meta_ads_mcp-0.8.0.dist-info}/METADATA +40 -12
- {meta_ads_mcp-0.7.10.dist-info → meta_ads_mcp-0.8.0.dist-info}/RECORD +8 -8
- {meta_ads_mcp-0.7.10.dist-info → meta_ads_mcp-0.8.0.dist-info}/WHEEL +0 -0
- {meta_ads_mcp-0.7.10.dist-info → meta_ads_mcp-0.8.0.dist-info}/entry_points.txt +0 -0
- {meta_ads_mcp-0.7.10.dist-info → meta_ads_mcp-0.8.0.dist-info}/licenses/LICENSE +0 -0
meta_ads_mcp/__init__.py
CHANGED
meta_ads_mcp/core/ads.py
CHANGED
|
@@ -633,7 +633,10 @@ async def create_ad_creative(
|
|
|
633
633
|
link_url: str = None,
|
|
634
634
|
message: str = None,
|
|
635
635
|
headline: str = None,
|
|
636
|
+
headlines: List[str] = None,
|
|
636
637
|
description: str = None,
|
|
638
|
+
descriptions: List[str] = None,
|
|
639
|
+
dynamic_creative_spec: Dict[str, Any] = None,
|
|
637
640
|
call_to_action_type: str = None,
|
|
638
641
|
instagram_actor_id: str = None
|
|
639
642
|
) -> str:
|
|
@@ -648,8 +651,11 @@ async def create_ad_creative(
|
|
|
648
651
|
page_id: Facebook Page ID to be used for the ad
|
|
649
652
|
link_url: Destination URL for the ad
|
|
650
653
|
message: Ad copy/text
|
|
651
|
-
headline:
|
|
652
|
-
|
|
654
|
+
headline: Single headline for simple ads (cannot be used with headlines)
|
|
655
|
+
headlines: List of headlines for dynamic creative testing (cannot be used with headline)
|
|
656
|
+
description: Single description for simple ads (cannot be used with descriptions)
|
|
657
|
+
descriptions: List of descriptions for dynamic creative testing (cannot be used with description)
|
|
658
|
+
dynamic_creative_spec: Dynamic creative optimization settings
|
|
653
659
|
call_to_action_type: Call to action button type (e.g., 'LEARN_MORE', 'SIGN_UP', 'SHOP_NOW')
|
|
654
660
|
instagram_actor_id: Optional Instagram account ID for Instagram placements
|
|
655
661
|
|
|
@@ -697,29 +703,98 @@ async def create_ad_creative(
|
|
|
697
703
|
"suggestion": "Please provide a page_id parameter or use get_account_pages to find available pages"
|
|
698
704
|
}, indent=2)
|
|
699
705
|
|
|
706
|
+
# Validate headline/description parameters - cannot mix simple and complex
|
|
707
|
+
if headline and headlines:
|
|
708
|
+
return json.dumps({"error": "Cannot specify both 'headline' and 'headlines'. Use 'headline' for single headline or 'headlines' for multiple."}, indent=2)
|
|
709
|
+
|
|
710
|
+
if description and descriptions:
|
|
711
|
+
return json.dumps({"error": "Cannot specify both 'description' and 'descriptions'. Use 'description' for single description or 'descriptions' for multiple."}, indent=2)
|
|
712
|
+
|
|
713
|
+
# Convert simple parameters to complex format for internal processing
|
|
714
|
+
final_headlines = None
|
|
715
|
+
final_descriptions = None
|
|
716
|
+
|
|
717
|
+
if headline:
|
|
718
|
+
final_headlines = [headline]
|
|
719
|
+
elif headlines:
|
|
720
|
+
final_headlines = headlines
|
|
721
|
+
|
|
722
|
+
if description:
|
|
723
|
+
final_descriptions = [description]
|
|
724
|
+
elif descriptions:
|
|
725
|
+
final_descriptions = descriptions
|
|
726
|
+
|
|
727
|
+
# Validate dynamic creative parameters
|
|
728
|
+
if final_headlines:
|
|
729
|
+
if len(final_headlines) > 5:
|
|
730
|
+
return json.dumps({"error": "Maximum 5 headlines allowed for dynamic creatives"}, indent=2)
|
|
731
|
+
for i, h in enumerate(final_headlines):
|
|
732
|
+
if len(h) > 40:
|
|
733
|
+
return json.dumps({"error": f"Headline {i+1} exceeds 40 character limit"}, indent=2)
|
|
734
|
+
|
|
735
|
+
if final_descriptions:
|
|
736
|
+
if len(final_descriptions) > 5:
|
|
737
|
+
return json.dumps({"error": "Maximum 5 descriptions allowed for dynamic creatives"}, indent=2)
|
|
738
|
+
for i, d in enumerate(final_descriptions):
|
|
739
|
+
if len(d) > 125:
|
|
740
|
+
return json.dumps({"error": f"Description {i+1} exceeds 125 character limit"}, indent=2)
|
|
741
|
+
|
|
700
742
|
# Prepare the creative data
|
|
701
743
|
creative_data = {
|
|
702
|
-
"name": name
|
|
703
|
-
|
|
744
|
+
"name": name
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
# Choose between asset_feed_spec (dynamic creative) or object_story_spec (traditional)
|
|
748
|
+
if final_headlines or final_descriptions:
|
|
749
|
+
# Use asset_feed_spec for dynamic creatives
|
|
750
|
+
asset_feed_spec = {
|
|
751
|
+
"ad_formats": ["SINGLE_IMAGE"],
|
|
752
|
+
"images": [{"hash": image_hash}],
|
|
753
|
+
"link_urls": [{"website_url": link_url if link_url else "https://facebook.com"}]
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
# Handle headlines
|
|
757
|
+
if final_headlines:
|
|
758
|
+
asset_feed_spec["headlines"] = [{"text": headline_text} for headline_text in final_headlines]
|
|
759
|
+
|
|
760
|
+
# Handle descriptions
|
|
761
|
+
if final_descriptions:
|
|
762
|
+
asset_feed_spec["descriptions"] = [{"text": description_text} for description_text in final_descriptions]
|
|
763
|
+
|
|
764
|
+
# Add message as primary_texts if provided
|
|
765
|
+
if message:
|
|
766
|
+
asset_feed_spec["primary_texts"] = [{"text": message}]
|
|
767
|
+
|
|
768
|
+
# Add call_to_action_types if provided
|
|
769
|
+
if call_to_action_type:
|
|
770
|
+
asset_feed_spec["call_to_action_types"] = [call_to_action_type]
|
|
771
|
+
|
|
772
|
+
creative_data["asset_feed_spec"] = asset_feed_spec
|
|
773
|
+
|
|
774
|
+
# For dynamic creatives, we need a simplified object_story_spec
|
|
775
|
+
creative_data["object_story_spec"] = {
|
|
776
|
+
"page_id": page_id
|
|
777
|
+
}
|
|
778
|
+
else:
|
|
779
|
+
# Use traditional object_story_spec for single creative
|
|
780
|
+
creative_data["object_story_spec"] = {
|
|
704
781
|
"page_id": page_id,
|
|
705
782
|
"link_data": {
|
|
706
783
|
"image_hash": image_hash,
|
|
707
784
|
"link": link_url if link_url else "https://facebook.com"
|
|
708
785
|
}
|
|
709
786
|
}
|
|
710
|
-
}
|
|
711
|
-
|
|
712
|
-
# Add optional parameters if provided
|
|
713
|
-
if message:
|
|
714
|
-
creative_data["object_story_spec"]["link_data"]["message"] = message
|
|
715
|
-
|
|
716
|
-
if headline:
|
|
717
|
-
creative_data["object_story_spec"]["link_data"]["name"] = headline
|
|
718
787
|
|
|
719
|
-
|
|
720
|
-
|
|
788
|
+
# Add optional parameters if provided
|
|
789
|
+
if message:
|
|
790
|
+
creative_data["object_story_spec"]["link_data"]["message"] = message
|
|
721
791
|
|
|
722
|
-
if
|
|
792
|
+
# Add dynamic creative spec if provided
|
|
793
|
+
if dynamic_creative_spec:
|
|
794
|
+
creative_data["dynamic_creative_spec"] = dynamic_creative_spec
|
|
795
|
+
|
|
796
|
+
# Only add call_to_action to object_story_spec if we're not using asset_feed_spec
|
|
797
|
+
if call_to_action_type and "asset_feed_spec" not in creative_data:
|
|
723
798
|
creative_data["object_story_spec"]["link_data"]["call_to_action"] = {
|
|
724
799
|
"type": call_to_action_type
|
|
725
800
|
}
|
|
@@ -739,7 +814,7 @@ async def create_ad_creative(
|
|
|
739
814
|
creative_id = data["id"]
|
|
740
815
|
creative_endpoint = f"{creative_id}"
|
|
741
816
|
creative_params = {
|
|
742
|
-
"fields": "id,name,status,thumbnail_url,image_url,image_hash,object_story_spec,url_tags,link_url"
|
|
817
|
+
"fields": "id,name,status,thumbnail_url,image_url,image_hash,object_story_spec,asset_feed_spec,url_tags,link_url"
|
|
743
818
|
}
|
|
744
819
|
|
|
745
820
|
creative_details = await make_api_request(creative_endpoint, access_token, creative_params)
|
|
@@ -759,6 +834,154 @@ async def create_ad_creative(
|
|
|
759
834
|
}, indent=2)
|
|
760
835
|
|
|
761
836
|
|
|
837
|
+
@mcp_server.tool()
|
|
838
|
+
@meta_api_tool
|
|
839
|
+
async def update_ad_creative(
|
|
840
|
+
access_token: str = None,
|
|
841
|
+
creative_id: str = None,
|
|
842
|
+
name: str = None,
|
|
843
|
+
message: str = None,
|
|
844
|
+
headline: str = None,
|
|
845
|
+
headlines: List[str] = None,
|
|
846
|
+
description: str = None,
|
|
847
|
+
descriptions: List[str] = None,
|
|
848
|
+
dynamic_creative_spec: Dict[str, Any] = None,
|
|
849
|
+
call_to_action_type: str = None
|
|
850
|
+
) -> str:
|
|
851
|
+
"""
|
|
852
|
+
Update an existing ad creative with new content or settings.
|
|
853
|
+
|
|
854
|
+
Args:
|
|
855
|
+
access_token: Meta API access token (optional - will use cached token if not provided)
|
|
856
|
+
creative_id: Meta Ads creative ID to update
|
|
857
|
+
name: New creative name
|
|
858
|
+
message: New ad copy/text
|
|
859
|
+
headline: Single headline for simple ads (cannot be used with headlines)
|
|
860
|
+
headlines: New list of headlines for dynamic creative testing (cannot be used with headline)
|
|
861
|
+
description: Single description for simple ads (cannot be used with descriptions)
|
|
862
|
+
descriptions: New list of descriptions for dynamic creative testing (cannot be used with description)
|
|
863
|
+
dynamic_creative_spec: New dynamic creative optimization settings
|
|
864
|
+
call_to_action_type: New call to action button type
|
|
865
|
+
|
|
866
|
+
Returns:
|
|
867
|
+
JSON response with updated creative details
|
|
868
|
+
"""
|
|
869
|
+
# Check required parameters
|
|
870
|
+
if not creative_id:
|
|
871
|
+
return json.dumps({"error": "No creative ID provided"}, indent=2)
|
|
872
|
+
|
|
873
|
+
# Validate headline/description parameters - cannot mix simple and complex
|
|
874
|
+
if headline and headlines:
|
|
875
|
+
return json.dumps({"error": "Cannot specify both 'headline' and 'headlines'. Use 'headline' for single headline or 'headlines' for multiple."}, indent=2)
|
|
876
|
+
|
|
877
|
+
if description and descriptions:
|
|
878
|
+
return json.dumps({"error": "Cannot specify both 'description' and 'descriptions'. Use 'description' for single description or 'descriptions' for multiple."}, indent=2)
|
|
879
|
+
|
|
880
|
+
# Convert simple parameters to complex format for internal processing
|
|
881
|
+
final_headlines = None
|
|
882
|
+
final_descriptions = None
|
|
883
|
+
|
|
884
|
+
if headline:
|
|
885
|
+
final_headlines = [headline]
|
|
886
|
+
elif headlines:
|
|
887
|
+
final_headlines = headlines
|
|
888
|
+
|
|
889
|
+
if description:
|
|
890
|
+
final_descriptions = [description]
|
|
891
|
+
elif descriptions:
|
|
892
|
+
final_descriptions = descriptions
|
|
893
|
+
|
|
894
|
+
# Validate dynamic creative parameters
|
|
895
|
+
if final_headlines:
|
|
896
|
+
if len(final_headlines) > 5:
|
|
897
|
+
return json.dumps({"error": "Maximum 5 headlines allowed for dynamic creatives"}, indent=2)
|
|
898
|
+
for i, h in enumerate(final_headlines):
|
|
899
|
+
if len(h) > 40:
|
|
900
|
+
return json.dumps({"error": f"Headline {i+1} exceeds 40 character limit"}, indent=2)
|
|
901
|
+
|
|
902
|
+
if final_descriptions:
|
|
903
|
+
if len(final_descriptions) > 5:
|
|
904
|
+
return json.dumps({"error": "Maximum 5 descriptions allowed for dynamic creatives"}, indent=2)
|
|
905
|
+
for i, d in enumerate(final_descriptions):
|
|
906
|
+
if len(d) > 125:
|
|
907
|
+
return json.dumps({"error": f"Description {i+1} exceeds 125 character limit"}, indent=2)
|
|
908
|
+
|
|
909
|
+
# Prepare the update data
|
|
910
|
+
update_data = {}
|
|
911
|
+
|
|
912
|
+
if name:
|
|
913
|
+
update_data["name"] = name
|
|
914
|
+
|
|
915
|
+
if message:
|
|
916
|
+
update_data["object_story_spec"] = {"link_data": {"message": message}}
|
|
917
|
+
|
|
918
|
+
# Handle dynamic creative assets via asset_feed_spec
|
|
919
|
+
if final_headlines or final_descriptions or dynamic_creative_spec:
|
|
920
|
+
asset_feed_spec = {}
|
|
921
|
+
|
|
922
|
+
# Add required ad_formats field for dynamic creatives
|
|
923
|
+
asset_feed_spec["ad_formats"] = ["SINGLE_IMAGE"]
|
|
924
|
+
|
|
925
|
+
# Handle headlines
|
|
926
|
+
if final_headlines:
|
|
927
|
+
asset_feed_spec["headlines"] = [{"text": headline_text} for headline_text in final_headlines]
|
|
928
|
+
|
|
929
|
+
# Handle descriptions
|
|
930
|
+
if final_descriptions:
|
|
931
|
+
asset_feed_spec["descriptions"] = [{"text": description_text} for description_text in final_descriptions]
|
|
932
|
+
|
|
933
|
+
# Add message as primary_texts if provided
|
|
934
|
+
if message:
|
|
935
|
+
asset_feed_spec["primary_texts"] = [{"text": message}]
|
|
936
|
+
|
|
937
|
+
update_data["asset_feed_spec"] = asset_feed_spec
|
|
938
|
+
|
|
939
|
+
# Add dynamic creative spec if provided
|
|
940
|
+
if dynamic_creative_spec:
|
|
941
|
+
update_data["dynamic_creative_spec"] = dynamic_creative_spec
|
|
942
|
+
|
|
943
|
+
# Handle call_to_action - add to asset_feed_spec if using dynamic creative, otherwise to object_story_spec
|
|
944
|
+
if call_to_action_type:
|
|
945
|
+
if "asset_feed_spec" in update_data:
|
|
946
|
+
update_data["asset_feed_spec"]["call_to_action_types"] = [call_to_action_type]
|
|
947
|
+
else:
|
|
948
|
+
if "object_story_spec" not in update_data:
|
|
949
|
+
update_data["object_story_spec"] = {"link_data": {}}
|
|
950
|
+
update_data["object_story_spec"]["link_data"]["call_to_action"] = {
|
|
951
|
+
"type": call_to_action_type
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
# Prepare the API endpoint for updating the creative
|
|
955
|
+
endpoint = f"{creative_id}"
|
|
956
|
+
|
|
957
|
+
try:
|
|
958
|
+
# Make API request to update the creative
|
|
959
|
+
data = await make_api_request(endpoint, access_token, update_data, method="POST")
|
|
960
|
+
|
|
961
|
+
# If successful, get more details about the updated creative
|
|
962
|
+
if "id" in data:
|
|
963
|
+
creative_endpoint = f"{creative_id}"
|
|
964
|
+
creative_params = {
|
|
965
|
+
"fields": "id,name,status,thumbnail_url,image_url,image_hash,object_story_spec,url_tags,link_url,dynamic_creative_spec"
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
creative_details = await make_api_request(creative_endpoint, access_token, creative_params)
|
|
969
|
+
return json.dumps({
|
|
970
|
+
"success": True,
|
|
971
|
+
"creative_id": creative_id,
|
|
972
|
+
"details": creative_details
|
|
973
|
+
}, indent=2)
|
|
974
|
+
|
|
975
|
+
return json.dumps(data, indent=2)
|
|
976
|
+
|
|
977
|
+
except Exception as e:
|
|
978
|
+
return json.dumps({
|
|
979
|
+
"error": "Failed to update ad creative",
|
|
980
|
+
"details": str(e),
|
|
981
|
+
"update_data_sent": update_data
|
|
982
|
+
}, indent=2)
|
|
983
|
+
|
|
984
|
+
|
|
762
985
|
async def _discover_pages_for_account(account_id: str, access_token: str) -> dict:
|
|
763
986
|
"""
|
|
764
987
|
Internal function to discover pages for an account using multiple approaches.
|
|
@@ -77,6 +77,32 @@ class MetaAdsDataManager:
|
|
|
77
77
|
logger.error(f"Error fetching ads for {account_id}: {e}")
|
|
78
78
|
return []
|
|
79
79
|
|
|
80
|
+
async def _get_pages_for_account(self, access_token: str, account_id: str) -> List[Dict[str, Any]]:
|
|
81
|
+
"""Get pages associated with an account"""
|
|
82
|
+
try:
|
|
83
|
+
# Import the page discovery function from ads module
|
|
84
|
+
from .ads import _discover_pages_for_account
|
|
85
|
+
|
|
86
|
+
# Ensure account_id has the 'act_' prefix
|
|
87
|
+
if not account_id.startswith("act_"):
|
|
88
|
+
account_id = f"act_{account_id}"
|
|
89
|
+
|
|
90
|
+
page_discovery_result = await _discover_pages_for_account(account_id, access_token)
|
|
91
|
+
|
|
92
|
+
if not page_discovery_result.get("success"):
|
|
93
|
+
return []
|
|
94
|
+
|
|
95
|
+
# Return page data in a consistent format
|
|
96
|
+
return [{
|
|
97
|
+
"id": page_discovery_result["page_id"],
|
|
98
|
+
"name": page_discovery_result.get("page_name", "Unknown"),
|
|
99
|
+
"source": page_discovery_result.get("source", "unknown"),
|
|
100
|
+
"account_id": account_id
|
|
101
|
+
}]
|
|
102
|
+
except Exception as e:
|
|
103
|
+
logger.error(f"Error fetching pages for {account_id}: {e}")
|
|
104
|
+
return []
|
|
105
|
+
|
|
80
106
|
async def search_records(self, query: str, access_token: str) -> List[str]:
|
|
81
107
|
"""Search Meta Ads data and return matching record IDs
|
|
82
108
|
|
|
@@ -176,6 +202,34 @@ class MetaAdsDataManager:
|
|
|
176
202
|
},
|
|
177
203
|
"raw_data": ad
|
|
178
204
|
}
|
|
205
|
+
|
|
206
|
+
# If query specifically mentions "page" or "pages", also search pages
|
|
207
|
+
if any(term in ['page', 'pages', 'facebook page'] for term in query_terms):
|
|
208
|
+
for account in accounts[:5]: # Limit to first 5 accounts for performance
|
|
209
|
+
pages = await self._get_pages_for_account(access_token, account['id'])
|
|
210
|
+
for page in pages:
|
|
211
|
+
page_text = f"{page.get('name', '')} {page.get('source', '')}".lower()
|
|
212
|
+
|
|
213
|
+
if any(term in page_text for term in query_terms):
|
|
214
|
+
page_record_id = f"page:{page['id']}"
|
|
215
|
+
matching_ids.append(page_record_id)
|
|
216
|
+
|
|
217
|
+
# Cache the page data
|
|
218
|
+
self._cache[page_record_id] = {
|
|
219
|
+
"id": page_record_id,
|
|
220
|
+
"type": "page",
|
|
221
|
+
"title": f"Facebook Page: {page.get('name', 'Unnamed Page')}",
|
|
222
|
+
"text": f"Facebook Page {page.get('name', 'Unnamed')} (ID: {page.get('id', 'N/A')}) - Source: {page.get('source', 'Unknown')}, Account: {account.get('name', 'Unknown')}",
|
|
223
|
+
"metadata": {
|
|
224
|
+
"page_id": page.get('id'),
|
|
225
|
+
"page_name": page.get('name'),
|
|
226
|
+
"source": page.get('source'),
|
|
227
|
+
"account_id": account.get('id'),
|
|
228
|
+
"account_name": account.get('name'),
|
|
229
|
+
"data_type": "meta_ads_page"
|
|
230
|
+
},
|
|
231
|
+
"raw_data": page
|
|
232
|
+
}
|
|
179
233
|
|
|
180
234
|
except Exception as e:
|
|
181
235
|
logger.error(f"Error during search operation: {e}")
|
|
@@ -219,7 +273,7 @@ async def search(
|
|
|
219
273
|
Search through Meta Ads data and return matching record IDs.
|
|
220
274
|
|
|
221
275
|
This tool is required for OpenAI ChatGPT Deep Research integration.
|
|
222
|
-
It searches across ad accounts, campaigns, and
|
|
276
|
+
It searches across ad accounts, campaigns, ads, and pages to find relevant records
|
|
223
277
|
based on the provided query.
|
|
224
278
|
|
|
225
279
|
Args:
|
|
@@ -233,6 +287,7 @@ async def search(
|
|
|
233
287
|
search(query="active campaigns")
|
|
234
288
|
search(query="account spending")
|
|
235
289
|
search(query="facebook ads performance")
|
|
290
|
+
search(query="facebook pages")
|
|
236
291
|
"""
|
|
237
292
|
if not query:
|
|
238
293
|
return json.dumps({
|
|
@@ -285,6 +340,7 @@ async def fetch(
|
|
|
285
340
|
fetch(id="account:act_123456789")
|
|
286
341
|
fetch(id="campaign:23842588888640185")
|
|
287
342
|
fetch(id="ad:23842614006130185")
|
|
343
|
+
fetch(id="page:123456789")
|
|
288
344
|
"""
|
|
289
345
|
if not id:
|
|
290
346
|
return json.dumps({
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: meta-ads-mcp
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.8.0
|
|
4
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
|
|
@@ -111,9 +111,11 @@ For detailed step-by-step instructions, authentication setup, debugging, and tro
|
|
|
111
111
|
- **Automated Monitoring**: Ask any MCP-compatible LLM to track performance metrics and alert you about significant changes
|
|
112
112
|
- **Budget Optimization**: Get recommendations for reallocating budget to better-performing ad sets
|
|
113
113
|
- **Creative Improvement**: Receive feedback on ad copy, imagery, and calls-to-action
|
|
114
|
+
- **Dynamic Creative Testing**: Easy API for both simple ads (single headline/description) and advanced A/B testing (multiple headlines/descriptions)
|
|
114
115
|
- **Campaign Management**: Request changes to campaigns, ad sets, and ads (all changes require explicit confirmation)
|
|
115
116
|
- **Cross-Platform Integration**: Works with Facebook, Instagram, and all Meta ad platforms
|
|
116
117
|
- **Universal LLM Support**: Compatible with any MCP client including Claude Desktop, Cursor, Cherry Studio, and more
|
|
118
|
+
- **Enhanced Search**: Generic search function includes page searching when queries mention "page" or "pages"
|
|
117
119
|
- **Simple Authentication**: Easy setup with secure OAuth authentication
|
|
118
120
|
- **Cross-Platform Support**: Works on Windows, macOS, and Linux
|
|
119
121
|
|
|
@@ -260,14 +262,32 @@ For local installation configuration, authentication options, and advanced techn
|
|
|
260
262
|
- `page_id`: Facebook Page ID for the ad
|
|
261
263
|
- `link_url`: Destination URL
|
|
262
264
|
- `message`: Ad copy/text
|
|
263
|
-
- `headline`:
|
|
264
|
-
- `
|
|
265
|
+
- `headline`: Single headline for simple ads (cannot be used with headlines)
|
|
266
|
+
- `headlines`: List of headlines for dynamic creative testing (cannot be used with headline)
|
|
267
|
+
- `description`: Single description for simple ads (cannot be used with descriptions)
|
|
268
|
+
- `descriptions`: List of descriptions for dynamic creative testing (cannot be used with description)
|
|
269
|
+
- `dynamic_creative_spec`: Dynamic creative optimization settings
|
|
265
270
|
- `call_to_action_type`: CTA button type (e.g., 'LEARN_MORE')
|
|
266
271
|
- `instagram_actor_id`: Optional Instagram account ID
|
|
267
272
|
- `access_token` (optional): Meta API access token
|
|
268
273
|
- Returns: Confirmation with new creative details
|
|
269
274
|
|
|
270
|
-
15. `
|
|
275
|
+
15. `mcp_meta_ads_update_ad_creative`
|
|
276
|
+
- Update an existing ad creative with new content or settings
|
|
277
|
+
- Inputs:
|
|
278
|
+
- `creative_id`: Meta Ads creative ID to update
|
|
279
|
+
- `name`: New creative name
|
|
280
|
+
- `message`: New ad copy/text
|
|
281
|
+
- `headline`: Single headline for simple ads (cannot be used with headlines)
|
|
282
|
+
- `headlines`: New list of headlines for dynamic creative testing (cannot be used with headline)
|
|
283
|
+
- `description`: Single description for simple ads (cannot be used with descriptions)
|
|
284
|
+
- `descriptions`: New list of descriptions for dynamic creative testing (cannot be used with description)
|
|
285
|
+
- `dynamic_creative_spec`: New dynamic creative optimization settings
|
|
286
|
+
- `call_to_action_type`: New call to action button type
|
|
287
|
+
- `access_token` (optional): Meta API access token (will use cached token if not provided)
|
|
288
|
+
- Returns: Confirmation with updated creative details
|
|
289
|
+
|
|
290
|
+
16. `mcp_meta_ads_upload_ad_image`
|
|
271
291
|
- Upload an image to use in Meta Ads creatives
|
|
272
292
|
- Inputs:
|
|
273
293
|
- `account_id`: Meta Ads account ID (format: act_XXXXXXXXX)
|
|
@@ -276,14 +296,14 @@ For local installation configuration, authentication options, and advanced techn
|
|
|
276
296
|
- `access_token` (optional): Meta API access token
|
|
277
297
|
- Returns: JSON response with image details including hash
|
|
278
298
|
|
|
279
|
-
|
|
299
|
+
17. `mcp_meta_ads_get_ad_image`
|
|
280
300
|
- Get, download, and visualize a Meta ad image in one step
|
|
281
301
|
- Inputs:
|
|
282
302
|
- `access_token` (optional): Meta API access token (will use cached token if not provided)
|
|
283
303
|
- `ad_id`: Meta Ads ad ID
|
|
284
304
|
- Returns: The ad image ready for direct visual analysis
|
|
285
305
|
|
|
286
|
-
|
|
306
|
+
18. `mcp_meta_ads_update_ad`
|
|
287
307
|
- Update an ad with new settings
|
|
288
308
|
- Inputs:
|
|
289
309
|
- `ad_id`: Meta Ads ad ID
|
|
@@ -292,7 +312,7 @@ For local installation configuration, authentication options, and advanced techn
|
|
|
292
312
|
- `access_token` (optional): Meta API access token (will use cached token if not provided)
|
|
293
313
|
- Returns: Confirmation with updated ad details and a confirmation link
|
|
294
314
|
|
|
295
|
-
|
|
315
|
+
19. `mcp_meta_ads_update_adset`
|
|
296
316
|
- Update an ad set with new settings including frequency caps
|
|
297
317
|
- Inputs:
|
|
298
318
|
- `adset_id`: Meta Ads ad set ID
|
|
@@ -304,7 +324,7 @@ For local installation configuration, authentication options, and advanced techn
|
|
|
304
324
|
- `access_token` (optional): Meta API access token (will use cached token if not provided)
|
|
305
325
|
- Returns: Confirmation with updated ad set details and a confirmation link
|
|
306
326
|
|
|
307
|
-
|
|
327
|
+
20. `mcp_meta_ads_get_insights`
|
|
308
328
|
- Get performance insights for a campaign, ad set, ad or account
|
|
309
329
|
- Inputs:
|
|
310
330
|
- `access_token` (optional): Meta API access token (will use cached token if not provided)
|
|
@@ -314,13 +334,13 @@ For local installation configuration, authentication options, and advanced techn
|
|
|
314
334
|
- `level`: Level of aggregation (ad, adset, campaign, account)
|
|
315
335
|
- Returns: Performance metrics for the specified object
|
|
316
336
|
|
|
317
|
-
|
|
337
|
+
21. `mcp_meta_ads_get_login_link`
|
|
318
338
|
- Get a clickable login link for Meta Ads authentication
|
|
319
339
|
- Inputs:
|
|
320
340
|
- `access_token` (optional): Meta API access token (will use cached token if not provided)
|
|
321
341
|
- Returns: A clickable resource link for Meta authentication
|
|
322
342
|
|
|
323
|
-
|
|
343
|
+
22. `mcp_meta-ads_create_budget_schedule`
|
|
324
344
|
- Create a budget schedule for a Meta Ads campaign.
|
|
325
345
|
- Inputs:
|
|
326
346
|
- `campaign_id`: Meta Ads campaign ID.
|
|
@@ -331,7 +351,7 @@ For local installation configuration, authentication options, and advanced techn
|
|
|
331
351
|
- `access_token` (optional): Meta API access token.
|
|
332
352
|
- Returns: JSON string with the ID of the created budget schedule or an error message.
|
|
333
353
|
|
|
334
|
-
|
|
354
|
+
23. `mcp_meta_ads_search_interests`
|
|
335
355
|
- Search for interest targeting options by keyword
|
|
336
356
|
- Inputs:
|
|
337
357
|
- `access_token` (optional): Meta API access token (will use cached token if not provided)
|
|
@@ -339,7 +359,7 @@ For local installation configuration, authentication options, and advanced techn
|
|
|
339
359
|
- `limit`: Maximum number of results to return (default: 25)
|
|
340
360
|
- Returns: Interest data with id, name, audience_size, and path fields
|
|
341
361
|
|
|
342
|
-
|
|
362
|
+
24. `mcp_meta_ads_get_interest_suggestions`
|
|
343
363
|
- Get interest suggestions based on existing interests
|
|
344
364
|
- Inputs:
|
|
345
365
|
- `access_token` (optional): Meta API access token (will use cached token if not provided)
|
|
@@ -379,6 +399,14 @@ For local installation configuration, authentication options, and advanced techn
|
|
|
379
399
|
- `limit`: Maximum number of results to return (default: 25)
|
|
380
400
|
- Returns: Location data with key, name, type, and geographic hierarchy information
|
|
381
401
|
|
|
402
|
+
28. `mcp_meta_ads_search` (Enhanced)
|
|
403
|
+
- Generic search across accounts, campaigns, ads, and pages
|
|
404
|
+
- Automatically includes page searching when query mentions "page" or "pages"
|
|
405
|
+
- Inputs:
|
|
406
|
+
- `access_token` (optional): Meta API access token (will use cached token if not provided)
|
|
407
|
+
- `query`: Search query string (e.g., "Injury Payouts pages", "active campaigns")
|
|
408
|
+
- Returns: List of matching record IDs in ChatGPT-compatible format
|
|
409
|
+
|
|
382
410
|
## Privacy and Security
|
|
383
411
|
|
|
384
412
|
Meta Ads MCP follows security best practices with secure token management and automatic authentication handling.
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
meta_ads_mcp/__init__.py,sha256=
|
|
1
|
+
meta_ads_mcp/__init__.py,sha256=4HWdOQ8Yuh6n5U-xcuRp8D193V0TmExUNZMJzGhQbNE,1492
|
|
2
2
|
meta_ads_mcp/__main__.py,sha256=XaQt3iXftG_7f0Zu7Wop9SeFgrD2WBn0EQOaPMc27d8,207
|
|
3
3
|
meta_ads_mcp/core/__init__.py,sha256=6nYdue6yRepkt6JTAoPGhGbS51qfDSvmczRrDwYOG6A,1709
|
|
4
4
|
meta_ads_mcp/core/accounts.py,sha256=4IAdGLZ4WE4j4pGW6E0qaXcXqbUIW6Wk2kuQUtlmRTQ,4030
|
|
5
|
-
meta_ads_mcp/core/ads.py,sha256=
|
|
5
|
+
meta_ads_mcp/core/ads.py,sha256=mRXIcIg5YG4f-Q5VH9GxmI_TRu3SJWkqMpHJ7mXqgH8,54051
|
|
6
6
|
meta_ads_mcp/core/ads_library.py,sha256=BBGVbtjO5eFV42iiY3XPU-wIV8HupzUKpHgPBrydSvU,3232
|
|
7
7
|
meta_ads_mcp/core/adsets.py,sha256=vY5JNHmGK1a_sQ5B1LnjxLYXzs5_jOajTTjWHRDJ4_Y,12518
|
|
8
8
|
meta_ads_mcp/core/api.py,sha256=aAzM6Q75VQOFXtr5D-mDmBRhxWK4wsiODsJYnR3mpDI,14994
|
|
@@ -14,15 +14,15 @@ meta_ads_mcp/core/campaigns.py,sha256=0yDVgi7rN4eMQk1_w0A2vnoXd8y0t8R77Ji4gna1Gj
|
|
|
14
14
|
meta_ads_mcp/core/duplication.py,sha256=UUmTDFx9o5ZsPQG2Rb9c4ZyuKUVN3FfTjebfTIHHdo4,18984
|
|
15
15
|
meta_ads_mcp/core/http_auth_integration.py,sha256=lGpKhfzJcyWugBcYEvypY-qnlt-3UDBLqh7xAUH0DGw,12473
|
|
16
16
|
meta_ads_mcp/core/insights.py,sha256=Qr1wq-1VT9HwF4w11rIRM4IBYdrksJ-6EOv3p33ZtKw,2613
|
|
17
|
-
meta_ads_mcp/core/openai_deep_research.py,sha256=
|
|
17
|
+
meta_ads_mcp/core/openai_deep_research.py,sha256=QOVoX_9D-j3qzQV5jVqM09ly6--SuxonmV0bafeOKhI,16292
|
|
18
18
|
meta_ads_mcp/core/pipeboard_auth.py,sha256=yT2-e9dpmkMOg6rMJWaQAMg4DZu4RxlDV5zkTm-G--o,25168
|
|
19
19
|
meta_ads_mcp/core/reports.py,sha256=Dv3hfsPOR7IZ9WrYrKd_6SNgZl-USIphg7knva3UYAw,5747
|
|
20
20
|
meta_ads_mcp/core/resources.py,sha256=-zIIfZulpo76vcKv6jhAlQq91cR2SZ3cjYZt3ek3x0w,1236
|
|
21
21
|
meta_ads_mcp/core/server.py,sha256=WhbAag7xdhbGcp7rnU4sKhqXJ8Slapa_ba3T23Yp_2U,17889
|
|
22
22
|
meta_ads_mcp/core/targeting.py,sha256=3HW1qirEdwaQurlBZGenbIwawcb5J06ghJKRfgu9ZEs,6318
|
|
23
23
|
meta_ads_mcp/core/utils.py,sha256=ytj41yC5SqduLrAiZYBSd6OUwlJRaIClTwnnYKpNFds,9387
|
|
24
|
-
meta_ads_mcp-0.
|
|
25
|
-
meta_ads_mcp-0.
|
|
26
|
-
meta_ads_mcp-0.
|
|
27
|
-
meta_ads_mcp-0.
|
|
28
|
-
meta_ads_mcp-0.
|
|
24
|
+
meta_ads_mcp-0.8.0.dist-info/METADATA,sha256=3jytygSKtYVuVQ4AExF9ViFQdkInKEh5hf8uk9Rb8hU,22434
|
|
25
|
+
meta_ads_mcp-0.8.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
26
|
+
meta_ads_mcp-0.8.0.dist-info/entry_points.txt,sha256=Dv2RkoBjRJBqj6CyhwqGIiwPCD-SCL1-7B9-zmVRuv0,57
|
|
27
|
+
meta_ads_mcp-0.8.0.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
28
|
+
meta_ads_mcp-0.8.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|