@mcp_server.tool()
@meta_api_tool
async def create_campaign(
account_id: str,
name: str,
objective: str,
access_token: Optional[str] = None,
status: str = "PAUSED",
special_ad_categories: Optional[List[str]] = None,
daily_budget: Optional[int] = None,
lifetime_budget: Optional[int] = None,
buying_type: Optional[str] = None,
bid_strategy: Optional[str] = None,
bid_cap: Optional[int] = None,
spend_cap: Optional[int] = None,
campaign_budget_optimization: Optional[bool] = None,
ab_test_control_setups: Optional[List[Dict[str, Any]]] = None,
use_adset_level_budgets: bool = False
) -> str:
"""
Create a new campaign in a Meta Ads account.
Args:
account_id: Meta Ads account ID (format: act_XXXXXXXXX)
name: Campaign name
objective: Campaign objective (ODAX, outcome-based). Must be one of:
OUTCOME_AWARENESS, OUTCOME_TRAFFIC, OUTCOME_ENGAGEMENT,
OUTCOME_LEADS, OUTCOME_SALES, OUTCOME_APP_PROMOTION.
Note: Legacy objectives like BRAND_AWARENESS, LINK_CLICKS,
CONVERSIONS, APP_INSTALLS, etc. are not valid for new
campaigns and will cause a 400 error. Use the outcome-based
values above (e.g., BRAND_AWARENESS → OUTCOME_AWARENESS).
access_token: Meta API access token (optional - will use cached token if not provided)
status: Initial campaign status (default: PAUSED)
special_ad_categories: List of special ad categories if applicable
daily_budget: Daily budget in account currency (in cents) as a string (only used if use_adset_level_budgets=False)
lifetime_budget: Lifetime budget in account currency (in cents) as a string (only used if use_adset_level_budgets=False)
buying_type: Buying type (e.g., 'AUCTION')
bid_strategy: Bid strategy. Must be one of: 'LOWEST_COST_WITHOUT_CAP', 'LOWEST_COST_WITH_BID_CAP', 'COST_CAP', 'LOWEST_COST_WITH_MIN_ROAS'.
bid_cap: Bid cap in account currency (in cents) as a string
spend_cap: Spending limit for the campaign in account currency (in cents) as a string
campaign_budget_optimization: Whether to enable campaign budget optimization (only used if use_adset_level_budgets=False)
ab_test_control_setups: Settings for A/B testing (e.g., [{"name":"Creative A", "ad_format":"SINGLE_IMAGE"}])
use_adset_level_budgets: If True, budgets will be set at the ad set level instead of campaign level (default: False)
"""
# Check required parameters
if not account_id:
return json.dumps({"error": "No account ID provided"}, indent=2)
if not name:
return json.dumps({"error": "No campaign name provided"}, indent=2)
if not objective:
return json.dumps({"error": "No campaign objective provided"}, indent=2)
# Special_ad_categories is required by the API, set default if not provided
if special_ad_categories is None:
special_ad_categories = []
# For this example, we'll add a fixed daily budget if none is provided and we're not using ad set level budgets
if not daily_budget and not lifetime_budget and not use_adset_level_budgets:
daily_budget = "1000" # Default to $10 USD
endpoint = f"{account_id}/campaigns"
params = {
"name": name,
"objective": objective,
"status": status,
"special_ad_categories": json.dumps(special_ad_categories) # Properly format as JSON string
}
# Only set campaign-level budgets if we're not using ad set level budgets
if not use_adset_level_budgets:
# Convert budget values to strings if they aren't already
if daily_budget is not None:
params["daily_budget"] = str(daily_budget)
if lifetime_budget is not None:
params["lifetime_budget"] = str(lifetime_budget)
if campaign_budget_optimization is not None:
params["campaign_budget_optimization"] = "true" if campaign_budget_optimization else "false"
# Add new parameters
if buying_type:
params["buying_type"] = buying_type
if bid_strategy:
params["bid_strategy"] = bid_strategy
if bid_cap is not None:
params["bid_cap"] = str(bid_cap)
if spend_cap is not None:
params["spend_cap"] = str(spend_cap)
if ab_test_control_setups:
params["ab_test_control_setups"] = json.dumps(ab_test_control_setups)
try:
data = await make_api_request(endpoint, access_token, params, method="POST")
# Add a note about budget strategy if using ad set level budgets
if use_adset_level_budgets:
data["budget_strategy"] = "ad_set_level"
data["note"] = "Campaign created with ad set level budgets. Set budgets when creating ad sets within this campaign."
return json.dumps(data, indent=2)
except Exception as e:
error_msg = str(e)
return json.dumps({
"error": "Failed to create campaign",
"details": error_msg,
"params_sent": params
}, indent=2)