Connects an AI client to the marketing stack one MCP server at a time, read-only first, proves each connection with six tests and ends in a stack inventory a colleague can audit. It never writes to a production vendor system or handles credentials; its only write attempts are the harmless T4 tests in a sandbox the user names.
When to use
Use this skill when:
- Someone wants a CRM, analytics, ads, lifecycle, SEO or warehouse tool connected to an AI client over MCP, or is choosing between a vendor server, a community server, a bridge or an export.
- A connection must become read-only, nobody knows what it can change, it shows the wrong account, region, no projects or no tools, or a vendor update, scope reinstall or new client changed what it exposes.
- Someone asks which MCP servers are configured on a machine, in a repository or in a team workspace, or an employee or agency leaves.
Use something else when:
- The agent will change anything through the connection (pause, edit, send, publish, merge, delete): agent-write-safety.
- Judging a server's code and publisher: mcp-security-review if installed; until then the publisher review in references/choosing-servers.md is the gate.
- Auditing a GTM container: gtm-container-audit. Building an MCP server over warehouse models: warehouse-and-internal-mcp if installed.
- Creating
martech-context/from scratch: marketing-context-kit. This skill only proposes the martech-context updates listed in step 9.
Inputs
Read these first if they exist (assets/example-acme-stack.md shows the fields): martech-context/stack.md (tools, account IDs, regions, owners, current Agent access lines), decisions.md (clients approved for customer data, standing restrictions) and metrics.md (definitions behind each known answer).
Then gather:
- One to five jobs, each with its system of record and one known answer readable in the vendor UI (a closed-period delivery value or one record).
- Who uses which client, on which plan or workspace, whether an org admin controls connectors, and the admin per tool who can enable MCP, change roles or create OAuth apps.
- A sandbox or test account per tool for the denied-write test, or "none".
Never ask for, accept or repeat tokens, API keys, client secrets or service account files; if one is pasted, tell the user its owner should rotate it.
Procedure
1. Fix the jobs before the tools
- No job, no connection. Each job names the question, the system of record and a known answer.
- First pilot: at most three servers, each with every write tool absent, Blocked or denied at the source by step 6 before first use; a credential recorded as write-capable is fine when no write tool is reachable.
- Each person connects and tests one server at a time and starts the next only after T1 to T4 pass. Connections found in step 2 are remediation: keep, fix or remove them one server per person at a time.
2. Inventory what is already connected
python3 -I scripts/mcp_inventory.py --discover --project ~/work/acme-marketing --expect-region mixpanel=eu
- Run from the skill folder. It reads each client's config and settings files and any paths you pass, matches servers against assets/server-registry.json and prints a redacted inventory with findings S01 to S15 (references/failure-modes.md); exit 1 means a FAIL, exit 2 an unreadable file. Always pass
--project <repository>: the default is the current directory.--all-projectsadds every repository listed in the terminal agent's user config. - Never open or paste client config files into the conversation; they can hold tokens. Without Python, record "scanner not run, because ...".
- Chat-app connectors, ChatGPT plugins, plugin-provided servers and desktop extensions are not in config files: list them from the terminal agent's
/mcpand each app's settings.
3. Choose the route per tool
Take the first rung that covers the job:
- Vendor-hosted remote server.
- Vendor-published local server.
- Export or warehouse path: GTM container export, Search Console bulk export to BigQuery, GA4 BigQuery export.
- A reporting bridge the team already licenses, with its write tools off.
- A community server that passes the publisher review: not archived, a release or commit in the last 90 days, an OSI licence, a pinned install, a read-only option, documented token storage.
- Never connect production credentials to an unreviewed community server, or to a third-party host using the name of a vendor that publishes its own server.
- With mcp-security-review installed, run it before step 7 for rungs 4 and 5 and any failed publisher review; NO-GO stops the connection.
- Routes and traps per tool: CRM, analytics, ads, lifecycle, SEO and warehouse; retired servers: references/choosing-servers.md.
4. Place it in the right client
- Remote is required when any user works in a web, mobile or cloud-hosted client. Self-host a local server (Google documents Cloud Run for Google Ads and GA4) only when two or more such users need it and someone owns the deployment.
- Chat-app connectors call vendors from the provider's cloud, so IP allowlists (Braze) and network policies (Snowflake) block them.
- CRM, lifecycle and support servers go only into a client or workspace that
decisions.mdapproves for customer data; otherwise draft the request for the privacy owner and stop for that tool. - Personal connections stay in personal scope; a shared project file holds only servers read-only by an enforced layer, with secrets as environment references (non-interactive runs load project servers without a prompt).
- OAuth that accepts only registered web callbacks (Google Cloud remote MCP, some Salesforce setups): add the connector in the chat app; references/clients.md says which terminal agent can inherit it and when.
- Agencies: one project folder or profile per client account. Name servers
<vendor>-<account>-<env>-<mode>, for exampleklaviyo-acme-prod-ro.
5. Choose the identity and scopes
- Connect as the person who does the job, with the lowest role that passes T3; never an admin: add the one missing permission instead.
- Request read scopes where the vendor offers them (Customer.io
read, Google OAuth scopes, a Search Console--read-onlylogin). Where scopes are fixed (HubSpot, Google Adsadwords, BigQuerybigquery, Stape's hosted GTM endpoint), enforce through role, IAM or client blocks and record the credential as write-capable. - Record granted scopes from the auth-status tool or consent screen, not the request. Unattended jobs get their own read-only identity with a named owner. Vendor detail, Google token expiry and custody: references/identity-and-scopes.md.
6. Enforce read-only below the prompt
Strongest layer per tool, checked 2026-11-06:
- HubSpot: View-only user with Create off, plus a client allowlist of read tools (View users can still create notes and tasks); with no allowlist, block
manage_*andsubmit_feedback. - Salesforce: the sobject-reads endpoint only.
- GA4: never
--allow-writeorANALYTICS_MCP_ALLOW_WRITE; mint the credential withanalytics.readonly. - Mixpanel: a project role without write, plus client blocks.
- Amplitude: Viewer (or an Enterprise custom role with Use MCP (read) only) plus a client allowlist; Member, Manager and Admin write by default.
- PostHog:
readonly=true&project_id=<id>&mode=toolson the URL. - Google Ads:
labels: falseandassets: falsein a tools config named byGOOGLE_ADS_MCP_TOOLS_CONFIG(the default lists four write tools); a dedicated or unattended identity gets Read-only account access, so itsadwordstoken cannot edit that account; otherwise record the credential as write-capable. - Meta Ads:
ads_mcp_managementplusads_read, neverads_management; for a dedicated identity, also a reporting-only ad account role. - GTM: the export JSON, or Read permission with
tagmanager.readonly(gtm-container-audit). - Braze: a dashboard user without edit rights, plus Use MCP Server.
- Klaviyo:
read-only=true&disable-tools-with-user-generated-content=trueon a custom connector (directory connectors ignore it), or the local server with a read-scoped key andREAD_ONLY=true. - Intercom: block
add_internal_note,create_article,update_articleand the Fin Operator tools. - Customer.io: the default read scope only; live-data and sensitive-data toggles off.
- Search Console: the bulk export to BigQuery; a community server only with a
--read-onlylogin andGSC_ENABLE_WRITES=0. - BigQuery: an IAM deny on tools not marked read-only (
execute_sql,cancel_job); Data Viewer on approved datasets only. - Snowflake: the
read_onlySQL tool and a SELECT-onlyMCP_READERset as the user's default role, alone inALLOWED_ROLES_LIST.
Then in the client:
- Prefer controls that deny new tools by default (a read-tool allowlist, a glob deny on write verbs, the setting for tools added later, a Blocked write-and-delete category): a list of today's write tools misses tomorrow's.
- Write tools are Needs approval or Blocked, never always allowed; never remember an approval for a write tool.
- Mark each tool U (reads outsider text: CRM notes, reviews, conversations, ad copy), P (private data) or S (sends data out); if one profile holds all three, split the job into two sessions with a human hand-off.
- If only the client layer exists, tell the user the read-only pass depends on the agent not calling write tools, and record the date.
7. Connect
- Prepare the change from assets/read-only-snippets.md; apply it only after the user approves, through the client's own command or settings screen where one exists (the terminal agents'
mcp addandmcp remove,/permissions, connector settings). For a file with no command (Cursor, desktop app or VS Code JSON, Codex keys such asenabled_tools), give the user the block and file path to paste; never read the file into the conversation. Re-run the scanner on every changed file. - Admin changes (org MCP switches, roles, OAuth apps, IAM deny policies, Snowflake users and integrations) go to the admin as a draft.
- The user completes every sign-in and consent screen, after checking the account and company shown.
8. Test every server in every client
Run T1 to T6 per server and client and log each in assets/connection-test-log.csv; per-vendor calls, caps and evidence sources: references/connection-tests.md.
- T1 identity: the identity call returns the account ID in
stack.md; a mismatch is FAIL. More accounts than the job needs is WARN; another client's production account is FAIL. - T2 tool surface: the tool list matches the expected read-only surface; save it as the drift baseline. A list of only an exec or discovery tool hides the tools: switch to tools mode first.
- T3 known answer: a delivery metric (spend, impressions, clicks, sends, sessions) or a record field for a closed period ending at least three full days ago, in the account's time zone and currency, matching exactly; an analytics difference passes only when traced to a named definition difference. Never use conversions or attributed revenue.
- T4 denied operation: an out-of-scope read fails without substitution, and a harmless write in the named sandbox is denied or the tool is absent. Get the user's go-ahead for the exact call, record and sandbox; match production's role and block rules, or record the layer as not proved. A write that succeeds is FAIL: stop and hand the object's removal to the user. Never test with a delete, send, launch, publish or spend change; a refusal without a tool call proves nothing. No sandbox: UNPROVEN, an open risk.
- T5 completeness: a request larger than one page states pagination or truncation.
- T6 revocation: who revokes, how, and one disconnect and reconnect during the pilot.
- For a client you are not running in, give the user a numbered test script (exact prompt, expected value, what to copy back) and log their answers with
tester_role; a test they cannot run is UNPROVEN.
A server counts as connected only when T1 is PASS (or WARN with a dated narrowing request), T2 and T3 are PASS, and T4 is PASS or UNPROVEN with a reason. Results expire after 30 days.
9. Hand over the inventory
python3 -I scripts/mcp_inventory_check.py ~/scratch/mcp-inventory.md
- Fill assets/stack-inventory-template.md in a scratch file outside
martech-context/, one block per server, environment and client, and run the check (omit--as-ofon live runs). Exit 1 lists missing labels, placeholders and stale or failed tests. - Propose: the inventory as
martech-context/mcp-inventory.md, one Agent access line per tool instack.md, adecisions.mdentry per approved connection, tool snapshots inmartech-context/mcp-tools/and a README line under Optional files present naming both. Write nothing until the owner approves.
10. Keep it current
python3 -I scripts/mcp_tools_diff.py current.json --baseline baseline.json --mode ro
- Build
current.jsonlike assets/example-acme-tools-current.json: tool names only, never results. Mark tools the client blocks"blocked": trueand tools a source layer denied in T4"denied_by"(role,iam,grant,scopeorserver). - Re-test on any trigger in references/connection-tests.md. Offboarding someone triggers every T6 revoke step for their identities.
Common failure modes
- Write tools on by default or a read-only setting that does nothing (the HubSpot connector, a Meta grant with
ads_management, Amplitude Member and above, Klaviyo parameters on a directory connector, Google Ads on its bundled config). Detect: T2. - Tools hidden behind one exec or discovery tool (PostHog CLI mode, Amplitude progressive discovery). Detect: the T2 list.
- Wrong account or region; lookalike, retired or shadowed servers; truncated results read as totals. Detect: T1; scanner S01, S02, S07, S10; T5.
Full list with fixes: references/failure-modes.md.
Worked example
Acme Co is fictional: its stack.md and six configs from three laptops in assets/example-acme-client-configs.json.
python3 -I scripts/mcp_inventory.py --fixture assets/example-acme-client-configs.json \
--expect-region mixpanel=eu --as-of 2026-11-01
It ends Summary: 12 FAIL, 9 WARN, 3 INFO, 8 PASS: a HubSpot lookalike bridge (S01), a shared Klaviyo entry without read-only=true shadowed for one person (S06, S10, S11). The fixed configs scan 0 FAIL, 0 WARN, 2 INFO, 6 PASS, and assets/example-acme-inventory.md passes the check. Decisions, tests, drift: references/worked-example.md.
Acceptance checks
- Jobs: every connected server maps to a job with a recorded known answer. Pass: no server without a job.
- Existing configs: the scanner ran, or the inventory says why not; every finding has keep, fix or remove. Pass: no unresolved FAIL.
- Route: each server records its route and reason; community servers carry a dated publisher review. Pass: no unreviewed community server, lookalike host or retired endpoint.
- Identity: role, reachable accounts and granted scopes come from the auth-status tool or consent screen. Pass: no unexplained admin identity; no other client's production account reachable.
- Read-only: each server names its enforcing layer, the exact setting and the proof (tool list compared, or a denied test). Pass: nothing relies on prompt text; client-only layers are labelled, with the date the user was told.
- Tests: every server and client pair meets the T1 to T4 rule, T5 is PASS or its limits are recorded, T6 is documented, all within 30 days. Pass:
scripts/mcp_inventory_check.pyexits 0. - Secrets: no token, key or secret in chat, config, inventory or a committed file. Pass: S03, S04 and S12 clean on the final configs.
- Client approvals: write tools are Blocked or Needs approval, new tools denied by default where the client allows, and CRM, lifecycle and support servers sit only in clients approved in
decisions.md. Pass: no write tool always allowed or allowlisted; each of those servers cites its approval date. - Drift baseline: a tool snapshot per server and client is proposed for
martech-context/mcp-tools/. Pass:scripts/mcp_tools_diff.py <snapshot> --mode roexits 0. - Safety: no write, send, publish, delete or spend call ran outside the T4 sandbox tests, and the agent changed no admin setting. Pass: the call log shows reads, the user's sign-ins and only T4 attempts in named sandboxes, each denied or absent, confirmed in the source's own records where they exist;
martech-context/changes have a recorded approval.
Boundaries
- Read-only, apart from the T4 denied-write tests in a named sandbox; never a delete, send, launch, publish or spend change. Roles, org connector settings, OAuth apps, IAM and warehouse grants leave as drafts for the admin.
- Never asks for, prints or stores credentials.
- A publisher review is a gate, not a security audit. AI provider data terms and customer-data approval belong to the privacy or security owner.
- Hand-offs: writes to agent-write-safety; server trust to mcp-security-review when installed; GTM reads to gtm-container-audit; context files to marketing-context-kit; custom servers to warehouse-and-internal-mcp when installed.
- Official read-only modes per tool: step 6.
- Vendor setup skills: Mixpanel's install skill (
mixpanel/ai-plugins), dbt's configuring-dbt-mcp-server (dbt-labs/dbt-agent-skills), the PostHog wizard, Customer.io plugins, HubSpot's connectors. Skip the developer token in Google's google-ads-api-mcp-setup (sunset 2026-09-09).
Live docs
Platform settings, limits and menu paths change. Before stating any parameter name, limit, quota or UI path:
- Fetch the current page from the vendor docs MCP server or llms.txt listed in
sources.yaml, or open the canonical URL. - If the live page disagrees with this skill, follow the live page and tell the user what changed.
- Cite the URL you used.
Most used: the HubSpot, Klaviyo, Amplitude, PostHog and Meta Ads MCP pages, the Google Ads and GA4 repositories, the terminal agent's MCP and permissions pages, Google Cloud's MCP deny page and Salesforce hosted servers. Checked 2026-11-01, changed servers and clients 2026-11-06. developer.salesforce.com and help.openai.com refuse automated fetches; some help.salesforce.com pages return an error shell, so read those in a browser.