Skip to main content
Glama
EfrainTorres

ArmaVita Meta Ads MCP

update_ad_creative

Modify existing Meta ad creative elements like text, headlines, descriptions, and call-to-action to improve campaign performance and A/B testing.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
ad_creative_idYes
meta_access_tokenNo
nameNo
primary_textNo
primary_text_variantsNo
headline_textNo
headline_variantsNo
description_textNo
description_variantsNo
optimization_typeNo
dynamic_creative_specNo
call_to_action_typeNo
lead_form_idNo
ad_formatsNo

Implementation Reference

  • Implementation of the 'update_ad_creative' tool handler.
    async def update_ad_creative(
        ad_creative_id: str,
        meta_access_token: Optional[str] = None,
        name: Optional[str] = None,
        primary_text: Optional[str] = None,
        primary_text_variants: Optional[List[str]] = None,
        headline_text: Optional[str] = None,
        headline_variants: Optional[List[str]] = None,
        description_text: Optional[str] = None,
        description_variants: Optional[List[str]] = None,
        optimization_type: Optional[str] = None,
        dynamic_creative_spec: Optional[Dict[str, Any]] = None,
        call_to_action_type: Optional[str] = None,
        lead_form_id: Optional[str] = None,
        ad_formats: Optional[List[str]] = None,
    ) -> str:
        if not ad_creative_id:
            return _json({"error": "No creative ID provided"})
    
        primary_text_variants = _normalize_list_argument(primary_text_variants)
        headline_variants = _normalize_list_argument(headline_variants)
        description_variants = _normalize_list_argument(description_variants)
        ad_formats = _normalize_list_argument(ad_formats)
    
        attempted_content_fields = [
            field
            for field, value in {
                "primary_text": primary_text,
                "primary_text_variants": primary_text_variants,
                "headline_text": headline_text,
                "headline_variants": headline_variants,
                "description_text": description_text,
                "description_variants": description_variants,
                "call_to_action_type": call_to_action_type,
                "lead_form_id": lead_form_id,
            }.items()
            if value is not None
        ]
    
        if attempted_content_fields:
            return _json(
                {
                    "error": "Content updates are not allowed on existing creatives",
                    "explanation": (
                        "The Meta API does not allow updating content fields (primary_text, headline_text, description_text, CTA, image, video, URL) "
                        "on existing creatives."
                    ),
                    "workaround": (
                        "Create a new creative via create_ad_creative, then call update_ad with the new ad_creative_id."
                    ),
                    "ad_creative_id": ad_creative_id,
                    "attempted_content_fields": attempted_content_fields,
                }
            )
    
        if optimization_type and optimization_type != "DEGREES_OF_FREEDOM":
            return _json({"error": f"Invalid optimization_type '{optimization_type}'. Only 'DEGREES_OF_FREEDOM' is supported."})
    
        update_payload: Dict[str, Any] = {}
        if name:
            update_payload["name"] = name
    
        if optimization_type or dynamic_creative_spec or ad_formats:
            resolved_update_formats = list(ad_formats) if ad_formats else (
                ["AUTOMATIC_FORMAT"] if optimization_type == "DEGREES_OF_FREEDOM" else ["SINGLE_IMAGE"]
            )
            feed: Dict[str, Any] = {
                "ad_formats": resolved_update_formats,
            }
            if optimization_type:
                feed["optimization_type"] = optimization_type
            update_payload["asset_feed_spec"] = feed
    
        if dynamic_creative_spec:
            update_payload["dynamic_creative_spec"] = dynamic_creative_spec
    
        if not update_payload:
            return _json({"error": "No update parameters provided"})
    
        try:
            result = await make_api_request(ad_creative_id, meta_access_token, update_payload, method="POST")
        except Exception as exc:  # noqa: BLE001
            return _json(
                {
                    "error": "Failed to update ad creative",
                    "details": str(exc),
                    "update_data_sent": update_payload,
                }
            )
    
        if isinstance(result, dict) and result.get("id"):
            details = await make_api_request(
                ad_creative_id,
                meta_access_token,
                {
                    "fields": (
                        "id,name,status,thumbnail_url,image_url,image_hash,object_story_spec,"
                        "url_tags,link_url,dynamic_creative_spec"
                    )
                },
            )
            return _json({"success": True, "ad_creative_id": ad_creative_id, "details": details})
    
        error_obj = result.get("error", {}) if isinstance(result, dict) else {}
        details = error_obj.get("details", {}) if isinstance(error_obj, dict) else {}
        inner = details.get("error", {}) if isinstance(details, dict) else {}
        error_subcode = inner.get("error_subcode") if isinstance(inner, dict) else error_obj.get("error_subcode")
    
        if error_subcode == 1815573:
            return _json(
                {
                    "error": "Content updates are not allowed on existing creatives",
                    "explanation": (
                        "The Meta API does not allow updating content fields (primary_text, headline_text, description_text, CTA, image, video, URL) "
                        "on existing creatives."
                    ),
                    "workaround": (
                        "Create a new creative via create_ad_creative, then call update_ad with the new ad_creative_id."
                    ),
                    "ad_creative_id": ad_creative_id,
                    "attempted_updates": update_payload,
                }
            )
    
        return _json(result if isinstance(result, dict) else {"data": result})

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/EfrainTorres/armavita-meta-ads-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server