# Decision rules

The review decides one use case at one server version: task, data categories, identity, AI client and plan, and server version or digest. The same server can be GO for an aggregate ads report and NO-GO for a contact-level CRM export.

## Severity

- Blocker: a finding that makes the connection unsafe for this use case. Only an enforcing fix removes it, with evidence in the record.
- Condition: a gap that can be closed by a named owner. It carries a due label ("before connecting" or "within 30 days") and the evidence that will close it.
- Note: recorded for context. It does not change the decision.
- Enforcing control: something below the prompt that the agent cannot talk past. A vendor read-only server or switch that removes or rejects tools, a source permission or role, an IAM deny, a scope the token does not hold, network isolation, a different identity.
- Not enforcing: a client prompt, a hidden or disabled tool, an annotation, server instructions, a system prompt, a written policy, a promise in a vendor's marketing page.

## Tiers

Take the higher tier when in doubt, and write down the criterion that set it.

- Tier 1, light review, when all of these hold:
  - The vendor's own docs name this endpoint or package.
  - The identity can only read, proven by a vendor read-only switch or a read-only source permission.
  - Returned data is aggregate or non-personal: campaign metrics, GA4 reports, SEO data, a product catalog without customers.
  - Attended use in one client.
  - The task's queries exclude visitor-controlled dimensions: page title, page path with query string, UTM-derived campaign, source, medium, term and content, site search term, Google Ads search term, and form or event text. A server that can return them does not stop Tier 1; a task that asks for them makes it Tier 2, with the utm-or-page-title and search-term canaries.
  - Examples: GA4 sessions and conversions by date, device or default channel group through the official GA4 server with a Viewer identity and analytics.readonly; Google Ads campaign-level metrics, no search terms, through the official server with `labels: false` and `assets: false` in its tools config and a Read-only Google Ads user.
  - Required steps: 1, 2, 3, 4 (identity and enforcing layer; no write test when the layer removes write tools), 5 (AI provider handling only), 7 (config scan and a named revocation owner), 8.
- Tier 2, full review, when any of these hold:
  - Personal data is readable: contacts, profiles, audiences, orders, employee names, free text.
  - Third-party, community or agency publisher, or a local stdio server its vendor does not publish.
  - A hosted aggregator or proxy holds or receives upstream credentials.
  - The identity reaches several brands, workspaces or client accounts.
  - The task reads outsider-written text: CRM notes, tickets, chat, reviews, form answers, inbound email, ad library copy, social captions, or a visitor-controlled dimension (UTM values, referrers, page titles, site search terms, Search Console queries, Google Ads search terms).
  - Examples: a CRM pipeline summary that returns owner and company names; a community Search Console server.
  - Required: all eight steps, permission tests in a test account or sandbox, and a canary case for every outsider-text source the session reads, chosen from the step 6 matrix (the script's T08 list is a starting point, not the whole list).
- Tier 3, full review plus write controls, when any of these hold:
  - The identity can reach any write, send, spend, publish, delete, merge, suppression or consent, permission, audience upload, webhook or export tool, whether or not the use case plans to use it.
  - Unattended, scheduled, headless or research-mode runs.
  - Two or more servers in one session where any tool can communicate outward.
  - Examples: a HubSpot connection whose user can publish pages; a weekly report that runs on a schedule.
  - Required: Tier 2, plus an enforcing layer below the prompt for every hard-to-reverse tool the use case does not need, the client approval setting recorded per write tool, agent-write-safety for any write in scope, and a full re-review every 6 months.

## Blockers

Each blocker lists the rule, how to detect it, what changes the decision and whether a pilot is allowed while it is fixed.

- B1 Unverified publisher or artifact.
  - Rule: the vendor's docs do not name this exact endpoint or package and no repository ties it to an identifiable maintainer; or the name differs from the one the docs name (lookalike); or the repository is archived and the server can write.
  - Detect: step 2. Config scan CF06 FAIL (a download piped into a shell) also lands here, because nobody can say what runs.
  - Changes it: the vendor's own server, a pinned version of the package the docs name, or a fork the team reviews and owns.
  - Pilot: none.
- B2 Poisoned definition.
  - Rule: a tool name, description, schema text, annotation title or the server instructions carry a directive unrelated to the tool's job (refers to other tools, asks to read files or credentials, hides behaviour from the user, asks to send data somewhere) or invisible Unicode, confirmed by a person reading it.
  - Detect: review script T06 and T07 FAIL or WARN, S02, then a full read.
  - Changes it: nothing on this version. Report it to the publisher; a later clean version needs a new review from step 2.
  - Pilot: none.
- B3 Unenforced hard-to-reverse capability.
  - Rule: the identity can send, start or raise spend, publish, delete, merge, change suppression or consent, change permissions, upload audiences or create webhooks or exports; the use case does not need it; and the only control is a client prompt, a hidden tool, an annotation or an instruction.
  - Detect: T01 hard-to-reverse list, T04 WARN, then step 4.
  - Changes it: a vendor switch or source permission that removes or rejects the tool, proven by a denied test call where the tool stays listed.
  - Pilot: in a sandbox only.
- B4 Lethal trifecta in one session.
  - Rule: tools in the planned session read private data, read outsider-written text and can communicate outward, and no leg is removed by an enforcing layer. Writing to anything an outsider can read counts as outward: email, ticket replies, form confirmations, public pages, ad copy, a published container.
  - Detect: S01 FAIL, then the matrix in step 6.
  - Changes it: an enforcing control that removes one leg, or separate sessions for reading and writing.
  - Pilot: in a sandbox only.
- B5 Credential exposure by design.
  - Rule: the setup needs a long-lived credential committed to a repository, shared between people outside a managed connector, pasted into a prompt, chat or memory file, or stored where the team cannot restrict access.
  - Detect: config scan CF01 and CF02 FAIL, plus how the team plans to share the config; T14 when the task needs a tool that returns credentials.
  - Changes it: per-user OAuth, a managed connector, or a secret-manager reference with one credential per person or service.
  - Pilot: in a sandbox only, with a throwaway key.
- B6 Transport or token handling defect.
  - Rule: a remote endpoint over plain HTTP on a non-loopback host; a local HTTP server on a non-loopback interface without authentication; for custom servers, tokens accepted without an audience check, client tokens passed to upstream APIs, or one client's messages delivered to another through a shared transport.
  - Detect: CF03 FAIL, CF07 WARN, and the custom server checks.
  - Changes it: HTTPS, loopback binding plus authentication with Origin and Host checks, audience validation.
  - Pilot: none.
- B7 Known unpatched vulnerability.
  - Rule: a published advisory affects the exact version of the server, bridge or dev tool in use and a fixed version exists.
  - Detect: CF05 FAIL and a live advisory search for the exact package and version.
  - Changes it: the fixed version, pinned.
  - Pilot: none. Upgrade first.
- B8 Account boundary breach.
  - Rule: the identity reaches another client's, legal entity's or brand's data that the use case must not touch, and the connection cannot be narrowed.
  - Detect: the identity tool or admin screen in step 4; the out-of-scope read of a record an admin confirms exists (record ID from the admin view), denied or empty; and a read-only check that the production identities hold the role the test used, because a sandbox copied before a role change proves nothing about production.
  - Changes it: a dedicated identity scoped to the approved accounts.
  - Pilot: in a sandbox only.
- B9 Processing boundary not approved.
  - Rule: personal data would reach an AI provider plan, region, server operator or retention setting the privacy owner has not approved, or the vendor's terms prohibit the planned use (Apollo prohibits model training with its MCP integrations).
  - Detect: step 5.
  - Changes it: the privacy owner's dated sign-off, or narrowing the data until no approval is needed.
  - Pilot: synthetic data only.
- B10 No owner.
  - Rule: nobody accepts ownership of updates, incidents and revocation for the connection.
  - Detect: the owners answer in the intake (question 9) and the revocation owner in step 7. "The team" or "IT" is not an owner; a role is.
  - Changes it: a named role in the record and in stack.md.
  - Pilot: synthetic data only.

## Conditions

Each condition lists its trigger, the mitigation, the proof that closes it and its default due label.

- C1 Mutable version. Trigger: bare package name, @latest, a range, a git reference without a commit, an image tag without a digest (CF04 WARN). Mitigation: pin the reviewed version; a container digest freezes the whole tree, an npx or uvx pin fixes only the top-level package. Proof: a clean rescan. Due: before connecting.
- C2 Local server not isolated. Trigger: a stdio server running as a bare process with the user's files, keychain and network (CF03 INFO, CF06, CF08). Mitigation: a container with no home mounts, only the env vars it needs, network off unless needed and otherwise limited to the vendor's hosts; or the vendor's remote server. Proof: the container command and a rescan. Due: before connecting for Tier 2 and 3; within 30 days for Tier 1.
- C3 Missing or untrusted annotations. Trigger: T02 WARN or FAIL, D04, CF09. Mitigation: treat every unannotated tool as destructive, set the client to prompt on each call for those tools, and do not use approval modes that skip prompts for tools marked read-only. Proof: the client setting per tool. Due: before connecting.
- C4 Multiplexed tools. Trigger: T03, or T04 on a tool the task needs. Mitigation: enforce at the source permission, or with an argument-level rule or pre-call hook; otherwise use a read-only identity. Proof: a denied write through the multiplexed tool. Due: before connecting.
- C5 Reversible writes reachable but not needed. Trigger: create or update tools the use case does not need, with no hard-to-reverse effect. Mitigation: the vendor read-only switch or a read-only identity where one exists; otherwise block the tools in the client and record that the boundary is client-side. Proof: the tool list or client setting. Due: before connecting.
- C6 Personal data beyond the task. Trigger: T09, T10, T14 (credentials in results), a personal-data T13 (a mirrored header), or contact-level fields, free text or identifiers the task does not need. Mitigation: narrow at the source (objects, fields, views, sensitive-data settings, a read scope without sensitive data), prefer aggregate tools. Proof: a test query that shows the narrowed fields. Due: before connecting.
- C7 Outsider text without an outbound leg. Trigger: T08 in a session with no outward tool. Mitigation: keep outbound and write tools out of that session, use vendor switches that disable user-generated-content tools, run and save the canary cases. Proof: canary records. Due: before connecting.
- C8 Token stored in plaintext. Trigger: CF01, CF02 user information in a URL or connection string, a 0600 credentials file, a plaintext fallback store or a shell profile export. Mitigation: OS keychain, the client's managed store or a secret-manager reference; one credential per server; a rotation owner. Proof: a clean rescan and the rotation record. Due: within 30 days; before connecting if the file is shared, synced or backed up.
- C9 Shared identity. Trigger: one credential acts for several people, so vendor logs show one actor and access survives offboarding. Mitigation: per-user OAuth where supported; otherwise a dedicated limited credential and an actor log kept outside the agent. Proof: the connector auth type or the log. Due: before connecting.
- C10 Logging gap. Trigger: no log outside the agent records who called which tool, when, on which account, with what result. Mitigation: the vendor audit log (Google Cloud MCP Data Access audit logs are off by default), client telemetry with server and tool names, transcript retention that matches policy. Proof: a test call found in the named log. Due: within 30 days.
- C11 Revocation untested. Trigger: nobody has revoked the grant and seen the next call fail. Mitigation: revoke at the vendor and in the client, confirm the next call fails, record the time. Proof: the test record. Due: before connecting for Tier 3; within 30 days otherwise.
- C12 Maintenance risk. Trigger: no release or commit in 12 months, a single maintainer on a write-capable server, or a new maintainer or large version jump since the last review. Mitigation: pin, name an owner who watches releases and advisories, plan an exit route. Proof: the owner line in the record. Due: within 30 days.
- C13 Region mismatch. Trigger: the endpoint's region differs from the account's data region. Mitigation: the vendor's matching regional endpoint. Proof: the config. Due: before connecting.
- C14 Legacy transport or credential in URL with no alternative. Trigger: the vendor documents only an SSE endpoint or a key in the URL (CF02, CF03 WARN). Mitigation: treat the whole URL as a secret, keep it in per-user config only, rotate on any exposure, move when header auth over Streamable HTTP ships. Proof: per-user config location. Due: before connecting.
- C15 Attended use only. Trigger: Tier 3 controls are not proven for unattended runs. Mitigation: no scheduled, headless or research-mode runs, and no automatic or reviewer-model approval modes, until a Tier 3 review passes. Proof: client settings, the permission mode each client's sessions actually start in (Claude Code starts interactive sessions in auto mode from v2.1.283 unless settings say otherwise) and the absence of scheduled tasks. Due: before connecting.
- C16 Tests pending. Trigger: a planned setup reviewed on paper, or any step 4, 6 or 7 test not yet run. Mitigation: run the named tests in a test account. Proof: the test records. Due: before connecting. Owner: the connection owner.

Notes, recorded without changing the decision: directory listing status (a listing review checks listing criteria, not security); MCP Registry namespace type; provenance (signed releases, build attestations, SBOM); more than 40 tools (S03).

## Script rule to decision ID

- review-mcp-tools.mjs: T01 hard-to-reverse feeds B3 and the Tier 3 trigger; T02 and D04 feed C3; T03 feeds C4, for multiplexed tools and compound names alike; T04 feeds B3 or C4; T06 and T07 feed B2 (a T07 WARN on unread parameters means a read by hand); T08 and S01 feed B4 or C7 (every read tool counts as private data unless --public names it); T09, T10 and a personal-data T13 feed C6; T14 feeds C6, or B5 when the task needs the tool; T11 means the app's CSP origins and tool calls join the step 6 matrix once tools/list --app-info is read; T12 means step 3 is not done and the capture is no baseline; S02 feeds B2 when deliberate; D01 to D05 are re-review triggers.
- scan-mcp-config.mjs: CF01 feeds C8, or B5 when sharing is by design; CF02 feeds C8 or B5 for user information in URLs and connection strings, and B5 or C14 for query or path credentials; CF03 FAIL is B6 and WARN is C14; CF04 feeds C1, including a non-default package index; CF05 is B7; CF06 FAIL is B1 and WARN feeds C2; CF07 feeds B6; CF08 feeds C2; CF09 feeds C3, and C15 for an automatic permission mode; CF10 means the record may describe a different target than the one that runs.

## OWASP MCP Top 10 coverage

The OWASP MCP Top 10 (beta, 2025 IDs) is licensed CC BY-NC-SA, so only its IDs and short paraphrased labels appear here. Check the live list before citing it.

- MCP01 tokens and secrets: B5, C8, C9, C14, T14.
- MCP02 scope creep: B3, B8, C5, drift checks.
- MCP03 tool poisoning: B2, T06, T07, D03, D04, D05.
- MCP04 supply chain: B1, B7, C1, C12.
- MCP05 command injection: B7, CF06, T04.
- MCP06 prompt injection: B4, C7, canary cases.
- MCP07 authentication and authorization: B6 and the custom server checks.
- MCP08 audit and telemetry: C10.
- MCP09 shadow servers: CF10, the intake inventory, managed allowlists.
- MCP10 context over-sharing: B9, C6, the data path.

## Decision rules

- Any open blocker: NO-GO. The record states exactly what would change it: a fix, a different identity, or the vendor's official server.
- No blocker and any open condition: GO WITH CONDITIONS. Connect only after every "before connecting" condition has its evidence. "Within 30 days" conditions carry an owner and a date.
- No blocker and no open condition: GO.
- Paper review, when no test account exists yet: mark the record provisional. A blocker whose removal needs an untested control stays open, so the outcome is NO-GO and "What would change it" lists those tests. With no such blocker the outcome is at most GO WITH CONDITIONS: C16 lists every untested check as a before-connecting condition owned by the connection owner. Steps 3, 4, 6 and 7 run live before connecting.
- A blocker becomes a condition only when an enforcing control removes its cause and the evidence is in the record. A written instruction, a hidden tool or an annotation never downgrades a blocker.
- Pilot rule: B3, B4, B5, B8, B9 and B10 allow a sandbox or synthetic-data pilot while they are fixed. B1, B2, B6 and B7 allow none.
- The decision belongs to the system owner, with the privacy owner where B9 or C6 applies. The agent proposes it.

## Expiry, drift and re-review

- A decision is valid until its first re-review trigger or the cadence date, whichever comes first.
- Re-review triggers: a version change of a local server, bridge or image; a fresh capture whose list or instructions fingerprint differs from the baseline (D01 to D05); new scopes, a re-consent prompt or a vendor request to re-install a connector; an identity role change, a new client or plan, a new data category, new users outside the reviewed group; a publisher, maintainer or repository ownership change; a vendor security advisory or incident.
- Drift check: re-capture the tool list and run the script with --baseline every 30 days for remote servers you cannot pin at Tier 2 and 3, every 90 days at Tier 1, and on every version bump for pinned local servers. A D01, D04 or D05 FAIL suspends the decision until a re-review; a D05 WARN means reading the new instructions in full before the next use.
- Full re-review: every 6 months for Tier 3, every 12 months for Tier 1 and 2.
- Team overrides: the thresholds here (12 months, 30 and 90 days, 40 tools, 6 and 12 month cadences, 90-day key rotation) are defaults. A team may change them in martech-context/decisions.md; the record cites that entry.
