mcp-microsoft-ads (wvuhskr/mcp-microsoft-ads) is an MCP server listed on the M8ven Trust Index. It scores 45 out of 100, grade D. It declares 47 tools. No publisher has claimed this listing.

D
Warning
45/100

mcp-microsoft-ads

Enables AI assistants to manage Microsoft Advertising accounts, including campaigns, ad groups, keywords, audiences, and reporting, with safety-first write controls such as opt-in mutations, draft-and-confirm workflows, spend ceilings, and audit logging.

Warning. Serious findings were identified. Review the full report before connecting. Grades reflect the full trust pyramid: code, verification depth, and reputation. New projects cap at C until adoption is earned.

How we verified

Code Verified⚡ Live Monitored: not connected

Verified is a snapshot. Live keeps it current, and builds your track record.

⚡ Connect GitHub → continuous verification on every pushwhy connect →

Who stands behind it

wvuhskr

Source: Glama

Is this your MCP?

Claim it to get a verified publisher badge, a free copy of our full audit findings, and direct contact for any high-priority issues we find. Or connect your repo for our deepest verification, Live Monitored: read-only, revoke anytime. What we access →

Install from

The grade above is for the source repository. Registries can serve a different version, so we mark the ones we were not able to read.

// key findings
🚨
Reads files from sensitive locations
Touches: ~/.mcp-microsoft-ads/credentials.yaml
// tools this server exposes47 tools

These names and descriptions are the publisher's own, read from the source code. We print them as written. Our assessment is the findings above, not this list.

update_ad_group

Draft an ad-group update. target_cpa sets an explicit MaxConversions tCPA on the ad group (MS Search campaigns on the development account run MaxConversions with no target — this INTRODUCES one). cpc_bid is allowed ONLY when the ad group's effective bid strategy is in the MANUAL_BIDDING allowlist (r

draft_responsive_search_ad

Draft a Responsive Search Ad. 3-15 headlines, 2-4 descriptions. Ad copy claims MUST be verified against the advertiser's website before use — don't claim anything not actually present on the site (site-verified-claims policy). Blocklist (settings-configured blocked_terms) enforced on every headline/

create_custom_audience

Draft a remarketing list targeting site visitors (needs the account's UET tag; errors if none exists — create one in the MS Ads UI first). url_contains: substring the visited page URL must contain; defaults to the configured advertiser_domain setting when omitted — error naming both if neither is se

add_audience_targeting

Draft audience targeting on a campaign. audience_type disambiguates which id namespace audience_id is in — one of: RemarketingList, Custom, InMarket, Product, SimilarRemarketingList, CombinedList, CustomerList, ImpressionBasedRemarketingList, CustomSegment (WSDL AudienceType enum). bid_adjustment_pc

update_campaign

Draft a campaign update (budget / status Active|Paused / tCPA). tCPA at campaign level is only operative on PMax — for Search use update_ad_group. Returns a draft; apply with confirm_and_apply.

draft_campaign

Draft a new campaign — ALWAYS created Paused. campaign_type: Search | PerformanceMax. time_zone/language default to EasternTimeUSCanada/English (US-centric defaults) — override for other markets.

confirm_and_apply

Execute a previously drafted write. The ONLY path that mutates the account.

create_conversion_action

Draft a conversion goal. goal_type: Event | Url | Duration (only supported values on the development account). Each goal_type REQUIRES its matching match-criteria arg — without one the goal creates "successfully" but can never record a conversion: - Url: url_expression (matched with UrlOperator="Con

set_conversion_action_primary_status

Draft a campaign-goal association. MS models 'primary for this campaign' as a campaign conversion goal association (associate = campaign optimizes to it; disassociate = falls back to account-level goals).

get_entities

Fetch entity state. entity: campaigns | ad_groups | keywords | ads | asset_groups | campaign_criterions. parent_id required for all but campaigns. campaign_criterions returns DayTime, Location, LocationIntent, Radius criterion types (Audience not readable via this API). NOTE: campaign BiddingScheme

draft_sitelinks

Draft sitelinks on a campaign. sitelinks: [{text, url, description1?, description2?}]. Copy claims must be site-verified (the advertiser's website).

create_callouts

Draft callout extensions (max 25 chars each).

create_structured_snippets

Draft a structured snippet (header must be an MS-supported header, e.g. 'Services'; 3+ values required).

remove_extension

Draft removal: disassociate from campaign, then delete from library.

search_geo_targets

Search targetable/excludable locations by name (MS ships a file, not a query API; cached locally 30 days). Returns location ids for geo write tools.

exclude_geo_target

Draft a location EXCLUSION on a campaign. location_id from search_geo_targets.

remove_geo_target

Draft removal of a campaign criterion by id, via DeleteCampaignCriterions with CriterionType="Targets" — the Targets group covers Location, DayTime, Radius, and other campaign-criterion types, so this deletes whatever criterion id is passed, not Location only. ids from get_entities('campaign_criteri

health_check

Verify auth chain: token refresh + Customer Management GetUser round-trip.

list_accounts

List ALL advertiser accounts visible to the authenticated user (paged SearchAccounts under the hood; `truncated` is true only if the 1000-account safety cap was hit — raise MAX_PAGES if that ever happens for real).

get_account_info

Authenticated user + roles + configured account/customer ids.

discover_keywords

Keyword ideas from seed keywords and/or a landing-page URL (Ad Insight GetKeywordIdeas). Scoped to the location/language/network configured via advertiser settings' keyword_research block (defaults: US/English/Owned&Operated+Syndicated).

get_keyword_forecasts

Traffic estimates (clicks/impressions/CPC/cost) for candidate keywords at a given max CPC (defaults to the account's MS_ADS_MAX_CPC cap). Scoped to the location/language/network configured via advertiser settings (see discover_keywords).

list_recommendations

Account recommendations (MS Ad Insight GetRecommendations). recommendation_type is passed through as-is to MS — live probing found the API rejects a null type but every documented RecommendationType enum value also faulted (607, account/feature gating, not a code issue); pass whatever type MS has en

apply_recommendation

Draft applying an MS recommendation (mutates the account — rails apply).

dismiss_recommendation

Draft dismissing an MS recommendation.

draft_keywords

Draft new keywords under an ad group — created Paused. keywords: [{text, match_type: Broad|Phrase|Exact, bid: optional float}]. Blocklist (settings-configured blocked_terms) + bid cap (MS_ADS_MAX_CPC) enforced.

update_keyword_bid

Draft a keyword CPC bid change (MS_ADS_MAX_CPC cap enforced). Allowed ONLY when the ad group's effective bid strategy is in the MANUAL_BIDDING allowlist (rails.py). Pre-rejected for Smart Bidding: UpdateKeywords silently ignores Bid there instead of erroring (live-verified — empty PartialErrors, bid

remove_keywords

Draft keyword deletion (irreversible — pause_entity is the reversible lever).

upload_image_asset

Draft an image upload to the account media library (for image extensions / PMax asset groups). Returns media id on apply. PNG/JPEG.

get_negative_keywords

Campaign-level negatives + ALL shared negative keyword lists (with items and campaign associations). Always call before recommending/adding negatives.

add_negative_keywords

Draft negatives. scope: campaign | ad_group | shared_list. keywords: [{text, match_type: Phrase|Exact}]. Checks existing negatives first and skips duplicates (check-existing-lists-first rule). Blocklist NOT applied — negating a settings-blocked term is desired. scope='ad_group' REQUIRES campaign_id

remove_negative_keywords

Draft negative removal by id. scope: campaign | ad_group | shared_list. keyword_ids come from get_negative_keywords. scope='ad_group' REQUIRES campaign_id for consistency with add_negative_keywords — validation only, DeleteNegativeKeywordsFromEntities has no parent field per WSDL.

create_pmax_campaign

Draft a Performance Max campaign + first asset group — created PAUSED. time_zone defaults to EasternTimeUSCanada (US-centric default) — override for other markets. target_cpa is required by default (require_pmax_target_cpa setting, default true) — never create PMax without a target; removing one lat

create_portfolio_bidding_strategy

Draft a portfolio bid strategy (account library, shared across campaigns). strategy_type: MaxConversions | MaxClicks | TargetImpressionShare. Returns a draft; apply with confirm_and_apply.

list_extensions

Ad extensions. campaign_id=None: full account library (sitelinks, callouts, structured snippets...). campaign_id set: only extensions associated with that campaign.

get_conversion_actions

Conversion goals (nil ids returns all goals of the given types).

get_policy_issues

Disapproved ads + keywords in an ad group (editorial review failures).

remove_entity

Draft PERMANENT deletion of campaign | ad_group | keyword | ad. Irreversible — prefer pause_entity. ad_group needs parent_id=campaign id; keyword/ad need parent_id=ad group id.

get_campaign_performance

Campaign performance (impressions/clicks/spend/conversions/CPA).

get_ad_performance

Per-ad performance.

get_keyword_performance

Per-keyword performance incl. QualityScore.

get_geo_performance

Geographic performance.

get_search_terms

Search query report.

run_report

Arbitrary report (replaces Google run_gaql for metrics pulls). report_type = exact v13 request type name e.g. 'AgeGenderAudienceReportRequest'.

set_campaign_schedule

REPLACE a campaign's ad schedule. week = 7 dicts {day, from_hour, to_hour} (0-23 hour clock; to_hour is the hour service stops, e.g. to_hour=22 serves until 22:00). MUST cover all 7 days — a campaign with any DayTime rows serves only inside them, so a partial week silently narrows delivery. Deletes

pause_entity

Draft a pause. entity_type: campaign | ad_group | keyword | ad. keyword/ad need parent_id = ad group id; ad_group needs parent_id = campaign id.

enable_entity

Draft an enable (Status=Active). Same shape as pause_entity.

// environment variables
To run this server yourself, you supply these values. They go in your own MCP client configuration and stay on your machine. The secret label means the value is sensitive, not that the server mishandles it.
configMS_ADS_AUDIT_PATHJSONL audit log location
configMS_ADS_CREDENTIALS_PATH~/.mcp-microsoft-ads/credentials.yaml, override with ):
// quality suggestions

Tool annotations

No tools have read-only/destructive annotations

Add readOnlyHint or destructiveHint annotations to every tool so hosts can warn users before invoking.

All four hints declared on every tool

47/47 tools missing one or more hints — update_ad_group (missing: readOnlyHint, destructiveHint, idempotentHint, openWorldHint); draft_responsive_search_ad (missing: readOnlyHint, destructiveHint, idempotentHint, openWorldHint); create_custom_audience (missing: readOnlyHint, destructiveHint, idempotentHint, openWorldHint), +44 more. OpenAI's directory rejects tools where any of the four hints are missing or non-boolean.

For every tool, set all four hints (readOnlyHint, destructiveHint, idempotentHint, openWorldHint) to explicit true/false values that match the handler’s actual behaviour.

No access to sensitive paths

Reads sensitive paths: ~/.mcp-microsoft-ads/credentials.yaml

Remove reads of sensitive system paths. If you genuinely need them, document why in the README.

Claim the listing to review these findings one by one and send us a correction where you disagree, straight to the team. Claiming also means we tell you when the grade moves, and reach you first if we find anything urgent.

// full audit trail
The findings above are the summary. The full trail, every check we ran, each deduction, the network hosts observed and the dependency advisories, goes to verified publishers, along with an alert whenever a new one lands. Verified publishers can also review each finding and dispute it in one click. Publisher corrections have sharpened several of our checks this month, because the maintainer knows the codebase better than any scanner.
// improvement guidance — verified publishers only
We have 3 concrete improvements we can share with the publisher of this MCP. Each comes with specific guidance to raise the trust score.
// embed badge in your README
[![M8ven Verified](https://m8ven.ai/badge/mcp/wvuhskr/mcp-microsoft-ads?variant=verified)](https://m8ven.ai/mcp/wvuhskr/mcp-microsoft-ads)
Shows verification status without the grade. Want the grade badge instead? Remove ?variant=verified from the URL.
commit: 7963761163962b2cced6fe16a9e67037c3f01610
code hash: d62c7b6cae6849e79d934206887d427f985a162d880fbe904d8434399b755337
view raw JSON →
Check MCPs from inside your assistant
Tool Check · MCP

Vetting this one by hand? Tool Check is an MCP that scores other MCPs. Add it once and ask Claude, ChatGPT, or any MCP client to grade a server, surface CVEs, check the publisher, and suggest safer alternatives — before you install.

https://m8ven.ai/api/mcp/tool-check
check_toolsearch_toolscompare_toolsrecommend_alternativescheck_publisherreport_concern
How to add it →Free · no account needed · works in any MCP client