Skip to main content
Glama
shinypebble

microsoft-ads-mcp

by shinypebble

Server Configuration

Describes the environment variables required to run the server.

NameRequiredDescriptionDefault
READ_ONLYNotrue registers no write tools at all (default false)false
MICROSOFT_ADS_CLIENT_IDYesAzure AD app (client) id
MICROSOFT_ADS_ACCOUNT_IDNoDiscovered via search_accounts if unset
MICROSOFT_ADS_CUSTOMER_IDNoDiscovered via search_accounts if unset
MICROSOFT_ADS_ENVIRONMENTNoproduction (default) or sandboxproduction
MICROSOFT_ADS_CLIENT_SECRETNoOnly for web/confidential app registrations
MICROSOFT_ADS_REFRESH_TOKENNoRun non-interactively; else mint one via the auth tools
MICROSOFT_ADS_DEVELOPER_TOKENYesFrom the developer portal

Capabilities

Features and capabilities supported by this server

CapabilityDetails
tools
{
  "listChanged": true
}
logging
{}
prompts
{
  "listChanged": false
}
resources
{
  "subscribe": false,
  "listChanged": false
}
extensions
{
  "io.modelcontextprotocol/ui": {}
}
experimental
{}

Tools

Functions exposed to the LLM to take actions

NameDescription
account_healthA

Validate credentials and report the environment and write mode.

Call this first. read_only tells you whether write tools are available this session; environment is production or sandbox. auth_state discriminates why auth failed (e.g. no_token vs token_rejected); branch on needs_interactive_auth rather than the message string.

get_auth_urlA

Begin one-time sign-in: returns an OAuth sign-in URL to give the user.

The URL targets the account's identity provider (Microsoft by default, or Google for Google-federated accounts). Present it to the user as a clickable sign-in link, and ask them to sign in with the account that manages the ad account. After they sign in, the browser lands on a near-blank page whose address-bar URL contains a code= value; have them paste that full URL back, then call complete_auth with it.

Only needed once, when no refresh token is configured. The minted token is persisted and auto-refreshed thereafter, so the user never has to repeat this.

complete_authA

Finish sign-in: exchange the browser's redirect URL for a saved refresh token.

Call this with the URL the user pasted back after completing get_auth_url.

search_accountsA

List every Microsoft Advertising account reachable by the authenticated user.

get_campaignsA

List Search campaigns in the configured account.

get_ad_groupsB

List ad groups in a campaign.

get_keywordsA

List keywords in an ad group.

get_adsA

List text/responsive-search ads in an ad group.

get_budgetsA

Per-campaign budget view (daily budget and any shared-budget id).

get_account_url_optionsA

Read the account-level URL tracking / tracking template that every campaign inherits.

This is the account-level URL options: the tracking template (tracking URL template), Final URL suffix, msclkid auto-tagging, and parallel tracking that per-campaign, ad-group, ad, and keyword values inherit. Those per-entity values are typically blank and inherit from here, so this answers "where is the tracking template set?" and how UTM / msclkid click tracking is configured -- check this (not just the entity hierarchy) to confirm how clicks are tracked. msclkid_auto_tagging_enabled is what appends the Microsoft Click ID (msclkid) for conversion attribution. Confirm these before activating paused campaigns. To see the resolved (effective) value for a specific campaign or ad group and which level set it, see get_effective_url_settings; to change these, see set_account_url_options.

get_effective_url_settingsA

Resolve the effective URL tracking (tracking template, Final URL suffix, URL custom parameters) for a campaign or ad group, and which level set each.

URL tracking follows Microsoft's inherited / override order (keyword > ad > ad group > campaign > account): a value set at a deeper level wins, otherwise it inherits from its parent, ultimately the account-level URL options. So a campaign or ad group can show a null tracking template while the account template is what actually applies. This walks that inheritance chain and returns the effective tracking_url_template / final_url_suffix / url_custom_parameters plus a *_source ("ad_group", "campaign", or "account") for each, so you do not have to manually cross-reference get_account_url_options with the per-entity reads. Also surfaces msclkid_auto_tagging_enabled. Use it to answer "what tracking template actually applies here, and where is it set?" before activating a campaign.

get_negative_keywordsA

List negative keywords attached to campaigns or ad groups.

get_website_exclusionsA

List the website / mobile-app-id exclusions (negative sites) blocked on a campaign.

These prevent ads from serving on the listed sites/apps. Add or remove them with add_website_exclusions / remove_website_exclusions.

get_ad_extensionsA

List ad extensions in the account (call, callout, sitelink, etc.).

By default this enumerates all association scopes (Account, Campaign, AdGroup) and merges them, so extensions attached at the campaign or ad-group level are included — most extensions are associated to a campaign, not the account, so scoping to Account alone often looks empty. Pass an explicit association_type to narrow to one scope.

get_conversion_goalsA

List conversion goals (all types). Pass goal_ids to fetch specific goals.

Each goal reports exclude_from_bidding — the inverse of the UI's "Include in conversions" checkbox and the single switch for whether the goal steers automated bidding: false means it counts in the Conversions column and ECPC/tCPA bid math, true means it only shows under All conversions. Also surfaces count_type (All/Unique), conversion_window_in_minutes, goal_category, and the revenue model (revenue_type / revenue_value / revenue_currency_code). Confirm exclude_from_bidding is false before relying on a goal to drive spend; flip it with update_conversion_goal.

get_uet_tagsA

List UET tags. Pass tag_ids to fetch specific tags.

set_active_accountA

Switch which account subsequent tool calls read from and write to (this session only).

Use search_accounts to find ids. The OAuth credential is unchanged; this only rescopes calls. Confirm the target with account_health afterwards before any write.

get_location_targetsB

List the location targets/exclusions on a campaign.

get_location_intentA

Read a campaign's location-intent setting (presence vs. broader reach).

Returns the single LocationIntent criterion's intent_option: PeopleIn (only people physically in the targeted locations) or PeopleInOrSearchingForOrViewingPages (people in, searching for, or viewing pages about them; Microsoft's default). Legacy campaigns may still report the deprecated PeopleSearchingForOrViewingPages.

get_ad_schedulesA

Read a campaign's ad-schedule (dayparting) windows and their time-zone context.

Returns each window (day, from_hour/from_minute, to_hour/to_minute, bid_adjustment) plus the campaign's time_zone and use_searcher_time_zone flag. When use_searcher_time_zone is false, the hours run in the campaign time_zone; remove a window with remove_ad_schedules using its criterion_id.

get_device_bid_adjustmentsA

Read a campaign's device bid adjustments (Computers / Smartphones / Tablets).

Each row's bid_adjustment is a percent modifier (-100 to 900; -100 excludes the device). An empty list means no device modifier is set, so every device serves at the base bid. Note Microsoft calls mobile "Smartphones". Set one with set_device_bid_adjustment.

resolve_postal_codesA

Resolve ZIP / postal codes to Microsoft LocationIds (for location targeting).

Downloads and caches Microsoft's geo-locations file on first use.

bulk_downloadA

Export the account to a Bulk file; returns the result file URL when ready.

Submits a Bulk download and polls to completion (the file can be large, so the URL is returned rather than the contents).

run_performance_reportA

Run a performance report end-to-end and return the parsed rows.

Unlike a raw submit, this submits the report, polls until it is ready, downloads the CSV, and parses it — so the rows come back inline.

estimate_keyword_bidsA

Estimate the bid to reach the first page (or mainline) for keywords -- the "estimated first page bid" from Keyword Planner.

For each keyword, returns one estimate per match type: estimated_min_bid (the headline first-page/mainline bid) plus modeled average CPC, CTR, and weekly clicks/impressions/cost ranges. Estimates are account-scoped and may be null where Microsoft has no data.

get_keyword_ideasA

Discover keyword ideas from seed phrases and/or a landing-page URL (Keyword Planner).

Each idea reports avg_monthly_searches (+ the monthly history), a rough suggested_bid, and a competition bucket (Low/Medium/High). Provide at least one of keywords or url.

get_keyword_traffic_estimatesA

Estimate weekly traffic (clicks/impressions/cost/position) for keywords at a given bid.

Each keyword's estimate is a min..max bracket at the supplied max_cpc and match type -- useful to gauge search volume and likely spend before launching. (estimate_keyword_bids also returns weekly clicks/impressions/cost, so reach for this when you specifically want the traffic at a bid you choose rather than at the first-page suggested bid.)

check_first_page_bidsA

Flag keywords whose bid is below the estimated first-page bid ("Below first page bid").

This is the API-driven version of the delivery state the UI shows as "Below first page bid". For each keyword in the ad group it looks up the Keyword Planner first-page bid estimate (at the keyword's own match type) and compares it against the keyword's effective bid -- the keyword's own bid, or the ad group's default bid when the keyword has none. The result lists the under-bid keywords first (largest shortfall first) with each one's current_bid, estimated_first_page_bid, and bid_source, plus counts. Use it when diagnosing low impressions, or before activating a campaign, to find keywords that won't reach the first page at their current bid.

create_campaignA

Create a Search campaign (PAUSED by default for safety).

update_campaign_statusB

Set a campaign Active or Paused.

update_campaignA

Update an existing campaign in place. Only the fields you pass change.

create_ad_groupA

Create an ad group (PAUSED) in a campaign.

update_ad_groupA

Update an existing ad group in place. Only the fields you pass change.

add_keywordsB

Add keywords (Active) to an ad group.

update_keywordA

Update an existing keyword in place. Only the fields you pass change.

create_responsive_search_adB

Create a Responsive Search Ad (PAUSED).

update_responsive_search_adA

Update an existing Responsive Search Ad in place. Only the fields you pass change.

Use this to repoint a Final URL or refresh copy without recreating the ad.

set_account_url_optionsA

Set account-level URL options / tracking template (applies account-wide; every campaign inherits them).

The cleanest way to apply a tracking template (tracking URL template), Final URL suffix, msclkid auto-tagging, or parallel tracking across the whole account at once -- the inherited URL settings -- instead of editing each campaign/ad/keyword. Only the fields you pass change. Read the current values first with get_account_url_options, and use get_effective_url_settings to confirm what a given campaign/ad group resolves to afterward.

delete_campaignB

Delete one or more campaigns by id.

delete_ad_groupB

Delete one or more ad groups by id.

delete_adB

Delete one or more ads by id.

delete_keywordB

Delete one or more keywords by id.

add_negative_keywordsB

Attach negative keywords to a campaign or ad group.

remove_negative_keywordsA

Remove negative keywords from a campaign or ad group, identified by id.

Resolve ids first with get_negative_keywords (deletion is by id, not text).

add_website_exclusionsA

Block websites / mobile-app ids on a campaign so ads won't serve there.

Additive: new sites are merged with the campaign's existing exclusions (read-modify-write), so this never clobbers what's already blocked. Pass bare domains or paths (e.g. "example.com", "example.com/section") or mobile-app ids; a leading http(s):// is stripped for you. Microsoft sites (e.g. MSN.com) can't be excluded and there's a ~2500-site cap per campaign -- such rejections come back in partial_errors. View with get_website_exclusions.

remove_website_exclusionsA

Unblock previously excluded websites / app ids on a campaign (matched by URL).

Read-modify-write: the named sites are filtered out and the rest are re-set, so other exclusions are retained. Removal is by URL (case-insensitive), not by id. List the current exclusions first with get_website_exclusions.

update_call_extensionA

Update an existing call extension in place (e.g. the brand's phone number or tracking).

Microsoft replaces the whole call extension on update, so phone number and country code are always required; when you omit them (e.g. to flip only is_call_tracking_enabled) this tool fetches the current extension and re-sends them, so a single-field toggle is safe.

add_callout_extensionA

Create a callout extension and optionally attach it to a campaign or ad group.

add_sitelink_extensionA

Create a sitelink extension and optionally attach it to a campaign or ad group.

update_sitelink_extensionA

Update an existing sitelink extension in place (e.g. add or edit its descriptions).

Microsoft replaces the whole sitelink on update, so display text and the final URL are always required; when you omit any field (e.g. to add only descriptions to an existing sitelink) this tool fetches the current extension and re-sends it, so a partial update is safe. Microsoft requires the two description lines together — a sitelink with description1 must also have description2.

add_structured_snippet_extensionA

Create a structured snippet extension and optionally attach it to a campaign/ad group.

A structured snippet is a header followed by a short list of values (e.g. header "Brands" with values ["Acme", "Globex", "Initech"]).

update_structured_snippet_extensionA

Update an existing structured snippet extension in place (edit its header or values).

Microsoft replaces the whole snippet on update, so the header and values are always required; when you omit either (e.g. to change only the values) this tool fetches the current extension and re-sends the other, so a partial update is safe.

add_call_extensionA

Create a call extension and optionally attach it to a campaign or ad group.

delete_ad_extensionA

Delete account-level ad extensions by id.

Removes the extension objects entirely (not just their campaign/ad-group associations).

create_conversion_goalA

Create a conversion goal. Goals are created Active (a goal does not spend; a paused goal silently fails to record conversions) — pass status="Paused" to override.

Conversion goals CANNOT be deleted (Microsoft has no delete API) — they can only be paused or renamed, so name them deliberately.

Microsoft has no native "calls from ads" goal. The bid-eligible path for phone calls is an "OfflineConversion" goal fed by apply_offline_conversions (keyed by MSCLKID) — create that goal here, then upload qualifying calls with apply_offline_conversions.

update_conversion_goalA

Update a conversion goal in place. Only the fields you pass change.

The key bidding lever is exclude_from_bidding — the inverse of the web UI's "Include in conversions" checkbox. exclude_from_bidding=false keeps the goal in the Conversions column and in automated-bidding math (ECPC / tCPA); true drops it from both (it still reports under All conversions). Confirm this is false before relying on a goal to steer spend. Read the current values first with get_conversion_goals.

apply_offline_conversionsA

Import offline conversions against an OfflineConversion goal, keyed by MSCLKID.

This is the bid-eligible path for phone calls: create an OfflineConversion goal with create_conversion_goal, apply your own qualifying filter to the call-center log (e.g. keep calls >=60s), then upload one record per qualifying call. Each record is attributed to the click that drove it and counted under the goal whose name matches conversion_name. Returns per-record errors in partial_errors (the API returns no ids).

Note: wait ~2 hours after creating an OfflineConversion goal before uploading — earlier uploads are rejected with "OfflineConversionNotAcceptedForGoal" (expected, not a bug).

update_uet_tagB

Update a UET tag's name and/or description in place.

add_location_targetsA

Target (or exclude) Microsoft LocationIds on a campaign.

Resolve ZIPs to LocationIds first with resolve_postal_codes.

set_location_intentA

Set who sees a campaign's ads relative to its targeted locations (location intent).

Updates the campaign's single LocationIntent criterion in place (created by Microsoft with a default of "PeopleInOrSearchingForOrViewingPages"). Read the current value first with get_location_intent.

set_device_bid_adjustmentA

Set a campaign's bid adjustment for one device (e.g. a mobile modifier).

Microsoft calls mobile "Smartphones" (there is no "Mobile"); "Computers" is desktop/laptop. Device criterions are created as a set, so the first time you set any device this also creates the other two at a neutral 0. Read the current values first with get_device_bid_adjustments.

remove_location_targetsA

Remove location targets/exclusions from a campaign by criterion id.

add_ad_schedulesA

Add ad-schedule (dayparting) windows to a campaign.

Each window restricts serving to one day and time range and is additive (a campaign with no schedule serves all hours). Hours are 0-24; minutes are 15-minute granularity, so only 0/15/30/45 are valid (e.g. 09:15-16:45 -> from_hour 9, from_minute 15, to_hour 16, to_minute 45). Times run in the campaign time zone (see get_campaigns / get_ad_schedules) unless you pass use_searcher_time_zone=true. Read existing windows with get_ad_schedules first to avoid duplicates.

A new window for a day may NOT overlap an existing window on that same day -- the API rejects the add (returned as ok=false with a partial error, not a crash). To change or extend a window, remove_ad_schedules the old criterion first and then add the new one, in that order (adding the overlapping window first fails); or use replace_ad_schedule, which does the remove-then-add for a single window in one call.

remove_ad_schedulesA

Remove ad-schedule (dayparting) windows from a campaign by criterion id.

replace_ad_scheduleA

Replace one ad-schedule (dayparting) window: remove the old criterion, add a new one.

The API rejects adding a window that overlaps an existing same-day window, so an in-place edit is impossible; this does the only safe sequence -- remove the old criterion, then add new_window -- in one call. Get the criterion_id from get_ad_schedules. If the remove fails, nothing changes; if the add fails after the remove, the result says so (the old window is gone, so that slot is briefly uncovered until you re-add it).

bulk_uploadB

Apply ready-made Bulk CSV rows to the account; polls to completion.

Prompts

Interactive templates invoked by user choice

NameDescription

No prompts

Resources

Contextual data attached and managed by the client

NameDescription
microsoft-ads-optimizer/SKILL.mdPlaybook for managing and reporting on a Microsoft Advertising account via the microsoft-ads MCP server.
microsoft-ads-optimizer/_manifestFile listing for microsoft-ads-optimizer

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/shinypebble/microsoft-ads-mcp'

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