# Vendor notes

Security-review facts per marketing MCP server: identity model, the layer that enforces read-only, personal data controls, kill switch and revocation, logs, region and traps. Write surfaces, change proposals and rollback belong to agent-write-safety; use it once a write is in scope.

Facts were checked on 2026-11-01 (Google Ads, GA4, BigQuery, Amplitude, PostHog, and HubSpot's tools, on 2026-11-06), except those marked "carried", which come from agent-write-safety's 2026-10-20 review and were not re-fetched. Verify every one live before quoting it. Vendor pages are in `sources.yaml`.

## Read-only routes at a glance

Each route still needs its step 4 proof: the identity check, and a denied harmless write wherever write tools stay listed.

- Google Ads: the official server with `labels: false` and `assets: false` in its tools config, plus a dedicated identity at the Read-only access level.
- GA4: the official server without `--allow-write` or `ANALYTICS_MCP_ALLOW_WRITE`, with Viewer on the approved properties only.
- Salesforce: the `sobject-reads` endpoint only.
- PostHog: `?readonly=true` or the `x-posthog-read-only` header, with `mode=tools` so the capture lists the real tools.
- Klaviyo: `read-only=true` with user-generated-content tools off on the remote server, or the local server with a read-scoped private key.
- Customer.io: the `read` scope only.
- Amplitude: Viewer, or a role with `USE_MCP_READ` and without `USE_MCP_WRITE`, proven by a denied taxonomy write and a denied content write.
- HubSpot: a View-only user with Create off, plus a client allowlist of the read tools, because View users can still create notes and tasks.
- Braze: a dashboard user without edit permissions, limited to the approved workspace.
- BigQuery: `execute_sql_readonly` with an IAM deny on tools not marked read-only, which covers `execute_sql` and `cancel_job`.
- Snowflake: `read_only` SQL with a SELECT-only role.
- Fivetran: `FIVETRAN_SCOPE=read`.
- Meta Ads: a token with `ads_read` and no `ads_management`.
- GTM: container permission Read, or an exported container audited offline.

## Google Ads (official, googleads/google-ads-mcp, Apache-2.0)

- Runs locally or self-hosted. It is not read-only by default. Version 0.0.6 (2026-11-02) lists `customers_list_accessible_customers`, `search_search` and `metadata_get_resource_metadata` plus four write tools, `assets_create_asset`, `assets_upload_video_asset`, `labels_manage_labels` and `labels_manage_label_associations`, all on in the bundled tools_config.yaml. Its categories set the prefixes; the README's tool list shows the unprefixed names. Google's developer page still says strictly read-only, so trust the README and a capture. Confirm the names and annotations in a capture before writing allowlists or permission rules.
- Vendor switch: `labels: false` and `assets: false` under `namespaces` in a tools_config.yaml. Point `GOOGLE_ADS_MCP_TOOLS_CONFIG` at it: a missing named file stops the server, while a file left in the working directory is simply not found when the server starts elsewhere, and the bundled default then turns every tool on.
- The write tools use a validate-then-confirm checksum, and the checksum comes back to the agent. That is a workflow step, not an enforcing layer.
- Trap: the README's credential setup requests the Google Ads API scope, which also allows writes at the API, plus cloud-platform in Application Default Credentials. Any script on the machine that uses those credentials inherits the authority.
- Enforcing layer: a dedicated identity (service account impersonation is documented) with the Google Ads Read-only access level. The levels are Email-only, Billing, Read-only, Standard and Admin.
- Evidence: `customers_list_accessible_customers` against the approved customer list (extra client accounts are B8). `change_event` shows writes, not reads, so it cannot prove read-only use.
- Usual tier: Tier 1 for aggregate reports with the write categories off and a Read-only user; Tier 3 with them on. Pin the version (`google-ads-mcp==<version>` on PyPI, or a commit) and keep credential paths out of shared configs. Google sunset developer tokens on 2026-09-09, so a config that still holds one is out of date.

## Google Analytics 4 (official, googleanalytics/google-analytics-mcp, Apache-2.0)

- Read tools by default. Version 1.0.0 (2026-11-03, Production/Stable on PyPI) has three write tools, `create_property_annotation`, `create_custom_dimension` and `create_key_event`, behind `--allow-write` or `ANALYTICS_MCP_ALLOW_WRITE` plus the analytics.edit scope. Google's developer guide (updated 2026-10-26) still says read-only, so trust the repository and a capture.
- 1.0.0 can also run as an HTTP service (`--transport http`, with a built-in OAuth server behind `--oauth`). A shared deployment is a server your team operates, not a local process: record who runs it and how it authenticates, at Tier 2 or higher.
- The README's credential requests analytics.readonly plus cloud-platform.
- Read-only route: neither the flag nor the variable, a dedicated identity with Viewer on the approved properties only.
- Reviews approved before 1.0.0 need a drift check; a capture with a write tool present is D01.

## Google Tag Manager (Stape, third party, Apache-2.0)

- Google publishes no Tag Manager MCP server. Stape's hosted endpoint requests all seven Tag Manager scopes plus email and profile (scopes.ts, last changed 2026-08-14).
- Its tools are multiplexed by an action argument (one tool both reads and removes a tag), which is C4.
- The GTM container permission is the only server-side boundary on the hosted route: Read on one container for audits.
- For a read-only grant, export the container and use the gtm-container-audit skill, or run the local server with its scope setting limited to the readonly scope and confirm with its auth status tool.
- Third-party hosted: Tier 2 at least; Tier 3 when the identity can publish.

## Meta Ads (Meta-hosted)

- No read-only mode documented. Enforcing layer: a token with `ads_mcp_management` and `ads_read` but not `ads_management`, from a system user with the Employee role (carried).
- Which tools an `ads_read` token rejects is not documented. Keep the denied harmless write in a test ad account as the proof.
- `ads_library_search` returns competitor ad copy, and creative and Instagram tools return captions: outsider text (leg U).
- The activity log tool is the evidence for what changed. Agency apps that serve other businesses have extra access requirements.

## HubSpot (vendor-hosted remote server)

- OAuth with PKCE is required. Scopes follow the tools available at install plus the user's grant; new tools can need new scopes, and users must re-install to grant them. A re-install prompt is a re-review trigger.
- All actions are limited to what the connecting user can do. View-only users can still create notes and tasks (carried), so block those tools in the client as well.
- `get_user_details` returns the user, the account and read and write access per object. Run it first; it is step 4 evidence.
- Sensitive Data on blocks activity data (calls, emails, meetings, notes, tasks) and conversation data from the MCP server.
- One connection can hold all three trifecta legs: read access includes conversation messages and threads from live chat, team email, WhatsApp, SMS, Messenger and custom channels (outsider text), and write access includes creating, editing and publishing landing pages, website pages and blog posts (outward). HubSpot says writes and publishing require user confirmation; that is a prompt, not an enforcing layer. Remove a leg with Sensitive Data and a role without publish permission.
- Help desk conversations are visible to all users, per the developer page.
- The website page, blog post and asset tools are available only to select AI clients (Claude, ChatGPT and Gemini; page read 2026-11-06), so an Inspector capture can miss them. Compare it with the client's tool list (client-controls.md).
- Enterprise admins of some AI chat apps can restrict the HubSpot connector to company-provisioned accounts.
- Where an admin uninstalls the connector and whether MCP actions reach the account audit log are not on the developer page. Verify live; keep C10 open until a test call is found in a log.

## Salesforce (hosted per org)

- `sobject-reads` cannot change data. Mutation, delete and all-in-one endpoints are separate. Per-user OAuth; field-level security, object permissions and sharing rules apply (read in a browser 2026-11-06).
- Read-only route: the `sobject-reads` endpoint only.
- developer.salesforce.com and help.openai.com refuse automated fetches. help.salesforce.com answers, but some pages return an error shell with no article, so read those in a browser.

## Braze

- US and EU endpoints. Either one reaches any Braze cluster, so a working connection does not show which endpoint the config uses; record it.
- Read and write tools; the Canvas tools are read-only. Writes follow the dashboard user's permissions, so the connection is Tier 3 unless that user cannot edit. Its MCP tools return no user-profile data or user-level personal data.
- The agent inherits the user's dashboard permissions. One connection covers every workspace the user can access, so an agency user reaches every client workspace they can see (B8 risk). Use a user scoped to the approved workspace.
- Accounts that use IP allowlisting cannot use the remote server. Braze lists which clients are supported.
- Kill switch: company OAuth settings can turn off MCP OAuth and revoke every MCP OAuth token at once. Revocation cannot be undone; every user reconnects.
- Logging: campaign edits made through MCP appear in campaign edit history, attributed to the signed-in user. Other actions are not covered on the page, so keep C10 open until a test call is seen in a log.

## Klaviyo (remote and local)

- The remote server needs the Owner, Admin or Manager role, so there is no low-permission identity on that route.
- URL parameters: `read-only=true`, `disable-tools-with-user-generated-content=true`, `toolsets=`, `core-tools-only` (about 30 tools).
- Listed directory connectors cannot take URL parameters. Use a custom connector URL that carries them, and prove it by comparing the tool list.
- The vendor's local example uses `@latest` and a private API key in plaintext env: pin it (C1) and move the key (C8).
- Strongest read route: the local server with a read-scoped private key, `READ_ONLY=true` and `ALLOW_USER_GENERATED_CONTENT=false`.

## Customer.io

- An account admin enables MCP under Settings, AI.
- Scopes are independent and capped by the user's own permissions:
  - `read`: the default; automations, segments, people, content and delivery metrics, excluding sensitive personal data.
  - `read:sensitive`: profile attributes classed as sensitive; needs the admin setting that allows MCP sensitive data access and a role allowed to view it.
  - `write`: create, edit and delete drafts.
  - `write:live`: send messages, manage subscriptions and suppressions; needs the admin setting that allows MCP to edit live data.
  - `configure`: integrations, webhooks, channel settings.
- Read-only route: `read` only.
- The admin toggle stops MCP requests at once, but turning it back on restores the same sessions because tokens are kept. It is a pause, not a revocation.
- Only the user who created a session can revoke it (personal settings, Connected clients, View sessions). Admins cannot view or revoke other users' sessions.
- `https://mcp.customer.io/mcp` routes to the account's region at sign-in; `https://mcp-eu.customer.io/mcp` is the EU fallback.

## Intercom

- US and EU endpoints: `https://mcp.intercom.com/mcp` and `https://mcp.eu.intercom.com/mcp`. Use the one that matches the workspace's region (C13).
- Conversations and tickets are written by customers: outsider text (leg U). Run the support-ticket canary before any reply tool is reachable.

## Mixpanel (carried)

- US, EU and India hosts. No read-only mode: the project role or service account governs.
- Lexicon writes include PII classification, a data governance change. 600 requests per hour per user. An audit log tool is in beta.

## Amplitude

- US and EU endpoints: `https://mcp.amplitude.com/mcp` and `https://mcp.eu.amplitude.com/mcp`.
- MCP is on for every user by default; an admin restricts it under Settings, Content Access, MCP.
- Per-project role actions `USE_MCP_READ` and `USE_MCP_WRITE` apply to users, groups and service accounts. Every role grants read, and the Member, Manager and Admin roles also grant write until an admin edits them.
- Tools stay listed for every client; a call the role does not permit fails at call time. The page ties `USE_MCP_WRITE` by name to tracking plan calls and does not say it covers dashboards, notebooks, cohorts, experiments or flags. The read-only route therefore needs a role without it, proven by a denied taxonomy write and a denied content write (a notebook or dashboard).
- Tracking plan writes need the write action plus the Update Tracking Plan data permission.
- `?discovery=progressive` replaces the list with discovery tools, so capture without it. `get_amp_user_data` returns user profiles, so it is personal data. Tool names moved in 2026: take them from the capture.

## PostHog

- `?readonly=true` or the `x-posthog-read-only` header removes write tools. Use a personal API key with the MCP Server preset, scoped to one project.
- Claude clients, Cowork and Codex default to CLI mode, which lists one `exec` tool. Add `mode=tools` or the `x-posthog-mcp-mode: tools` header before capturing, or the capture classifies one tool and the real list stays hidden.
- Some AI tools spend PostHog AI credits (carried).

## Snowflake managed MCP server (carried)

- The SQL tool's `read_only` defaults to true. Each tool needs its own grant plus the underlying privilege.
- Generic tools run procedures with owner's or caller's rights; an owner's-rights procedure is a privilege escalation path, so review each one.
- Responses are truncated at 250 KB: a partial result, not a complete one. Which account usage views record MCP calls: verify live.

## BigQuery remote MCP server (Google Cloud)

- `execute_sql_readonly` and `execute_sql` are separate tools. `cancel_job` is not read-only either: Google's tool pages mark `execute_sql` and `cancel_job` Read Only Hint false and Destructive Hint true, though the setup page still names only `execute_sql`. IAM deny policies can match `tool.isReadOnly`, `tool.name` or the OAuth client ID.
- `tools/list` still lists denied tools, so the tool list cannot prove the deny. A denied test call can.
- MCP Data Access audit logs are off by default. Enable them and filter on a `protoPayload.serviceName` ending in `/mcp`.

## Fivetran (self-hosted fivetran-mcp, carried)

- `FIVETRAN_SCOPE=read` by default, plus the README's denylist for operations an API key can still reach. The HTTP mode example binds 0.0.0.0 (CF07).

## Aggregators and automation platforms

- Supermetrics: campaign write access is granted per account, with approval levels No human approval, Going live, Budget + going live, and All live changes. For a reporting use case, grant no write access at all.
- Windsor.ai: OAuth with an API-key fallback; write actions on Meta and Google Ads. `include_actions=False` only skips listing them. Use source permissions and a client allowlist, then test a denied operation.
- Funnel: OAuth, with global and EU endpoints. The default query returns up to 500 rows, so a long table can be partial.
- Zapier, Make and n8n expose whatever actions are enabled in the account; classify each one as a tool. Make's docs say a client timeout does not necessarily stop the scenario, so after a timeout the outcome is unknown until you check the run.

## GTM engineering servers

- Apollo: model training must be off in the client. Per-user OAuth for interactive work; the headless route needs a master key that reaches new tools as they ship, and key-based requests act as the workspace's longest-standing active admin. Credit-consuming and sending actions make it Tier 3.
- Instantly: API key in the Authorization header, with a URL-path fallback for clients that cannot set headers. Use the header (CF02 if the path route is used).
- Smartlead: documents a legacy SSE endpoint with the key in the query string, bridged through mcp-remote: C14, CF02 FAIL and CF03 WARN, and mcp-remote pinned at 0.1.16 or later.
- Clay: admins restrict which clients may connect and set per-rep credit caps. A rep showing no limit has no cap.

## Servers not listed here

Run the same review. Look up read-only switches live; never assume a mode exists because a similar vendor has one.
