MCP Security in Claude Code (as of 29 Jul 2026)

Grading note. A dated snapshot — accurate as of 29 Jul 2026, frozen here and kept as a permanent archive entry. This is a refresh of the 02 Jul 2026 snapshot, updated now that the MCP 2026-07-28 specification has published as final. Corrections applied inline; unverifiable gaps marked ⚠ PENDING — never guessed.

⚠️ PROTOCOL UPDATE — the 2026-07-28 MCP specification is now FINAL. It was a release candidate at the time of the previous snapshot; it published as final on 28 Jul 2026. If and when your Claude Code build supports 2026-07-28 (this session could not confirm which Claude Code version added support — check your changelog), its MCP client is designed to absorb the transport-level changes (the initialize/Mcp-Session-Id removal, new required routing headers) for you — you should not need to change your own configuration for servers you merely connect to. What matters practically: the spec provides no automatic fallback from a legacy client to a server that speaks only 2026-07-28, so if your Claude Code build and a server you depend on are on mismatched protocol eras, that connection can fail outright rather than degrade gracefully. On authorization: RFC 9728 (Protected Resource Metadata — how a client discovers which authorization server protects a given remote MCP server) is unchanged from the prior spec, not new; RFC 9207 issuer validation is genuinely new but is an authorization-server-side/client-side plumbing detail your MCP client library handles, not something you configure directly. 🕒 verify live: confirm your Claude Code version’s MCP client supports 2026-07-28 before assuming compatibility with an upgraded server. — modelcontextprotocol.io — Versioning 2026-07-28 (fetched 2026-07-29) · modelcontextprotocol.io — Authorization 2026-07-28 (fetched 2026-07-29)

How to read the labels


Background: MCP in Claude Code

Claude Code can connect to external tools — databases, GitHub, Slack, internal APIs — through a system called MCP (Model Context Protocol). Each MCP “server” is a small program that gives Claude new capabilities. stdio servers (pronounced “standard eye-oh”) run as child processes directly on your computer, launched by Claude Code, with data flowing through the program’s input/output streams. Remote servers run over HTTPS and communicate via HTTP.

As of the 2026-07-28 MCP spec, the underlying protocol is stateless at the transport level: there is no more initialize handshake or Mcp-Session-Id, and every request is self-contained (modelcontextprotocol.io — Changelog 2026-07-28, fetched 2026-07-29). This is an implementation detail Claude Code’s MCP client is designed to handle for you — it should not change how you configure or use MCP servers day to day, but it does mean the server you connect to must speak a compatible protocol revision, or the connection fails outright rather than degrading gracefully.

That power carries risk: a malicious or misconfigured MCP server can read your files, exfiltrate credentials, or inject hidden instructions that make Claude do things you did not ask for. The eight practices below are the most important safeguards.


Practice 1: Never connect an MCP server you do not explicitly trust — treat every server as untrusted code

Do: Before running claude mcp add, verify you know who maintains the server, where its source lives, and whether it has had security issues. You may prefer servers from the Anthropic Directory (claude.ai/directory — requires sign-in; returns 403 to automated checks) — but note that Directory listing is a bar for inclusion, not a security certification or audit. Anything you connect inherits the trust you give it.

Why: An MCP server runs as a program on your machine. It can read files, make network requests, and feed Claude instructions through tool responses. Anthropic reviews connectors for its Directory listing criteria but does not security-audit or manage any MCP server. Independent research (cyberdesserts.com, relaying Trend Micro and BlueRock Security findings) documented over 492 MCP servers publicly reachable with zero authentication and zero encryption; BlueRock Security found 36.7% of more than 7,000 analyzed servers vulnerable to server-side request forgery.

Caveat: The Anthropic Directory listing review is a bar for inclusion, not a security certification. Do not conflate “listed in the Directory” with “audited and safe.” See the security page: “We encourage either writing your own MCP servers or using MCP servers from providers that you trust.”

Sources:

Confidence: ✅ independently-corroborated (Anthropic docs + independent security research)


Practice 2: Keep the default permission mode; understand exactly what bypassPermissions removes before using it

Do: Leave Claude Code in default permission mode for normal work. Only switch to bypassPermissions (also invoked with --dangerously-skip-permissions) inside an isolated container or VM where Claude cannot reach your host filesystem, credentials, or the internet.

Claude Code permission modes (six total): 🕒 verify live — mode lineup may change across versions.

⚠️ WARNING — dangerous default: bypassPermissions skips all permission prompts and protected-path checks. Protected paths include .git, .config/git, .vscode, .idea, .husky, .cargo, .devcontainer, .yarn, .mvn, .claude (except worktrees), shell RC files (.bashrc, .zshrc, etc.), .npmrc, .mcp.json, .claude.json, and others. It does NOT protect ~/.ssh or ~/.aws directories — those are protected by the separate sandboxing credential feature (see Practice 5). If a malicious MCP tool result injects instructions while bypassPermissions is active, Claude will execute them without asking. Anthropic’s docs state: “bypassPermissions offers no protection against prompt injection or unintended actions.”

Why: The default mode asks you before Claude edits files or runs commands. That pause is the moment where you, as the human, catch something wrong. Removing it turns a slow-moving mistake into an instant one. For CI pipelines that need unattended operation, dontAsk mode (only pre-approved tools run) is safer than bypassPermissions. plan mode is the safest option when you only need read access. Administrators can block bypassPermissions org-wide with permissions.disableBypassPermissionsMode: "disable" in managed settings.

Sources:

Confidence: 📄 vendor-documented


Practice 3: Use mcp__* deny rules and --disallowedTools to limit which MCP tools Claude can call

Do: In .claude/settings.json (project scope) or ~/.claude/settings.json (user scope — applies to all your projects), add deny rules for MCP servers or tools you want to block.

If these files do not exist yet, create them: on Linux/Mac, run mkdir -p ~/.claude && touch ~/.claude/settings.json in your terminal, then open the file in any text editor. For project-level rules, create .claude/settings.json at the root of your project directory.

Use the pattern mcp__<servername>__<toolname> to target specific tools, or mcp__<servername> to deny all tools from a server:

{
  "permissions": {
    "deny": [
      "mcp__filesystem",
      "mcp__github__create_repository"
    ]
  }
}

To deny all MCP tools entirely:

{
  "permissions": {
    "deny": ["mcp__*"]
  }
}

The --disallowedTools CLI flag achieves the same effect for a single session:

claude --disallowedTools "mcp__filesystem__write_file"

Why: You may connect an MCP server for a read-only capability (e.g., checking a Jira ticket) but not want Claude to use its write tools (e.g., closing that ticket). Deny rules let you take exactly the tools you need and block the rest.

Caveat: Deny rules are evaluated before allow rules. A broad mcp__* deny cannot be overridden by a narrower allow rule — it blocks everything. Rule precedence is: deny → ask → allow. A serverName entry in an allowlist is NOT a security control — users can name any server anything; use serverUrl or serverCommand entries for enforcement. Cross-reference Practice 4 for scope decisions (project vs. user settings).

Sources:

Confidence: 📄 vendor-documented


Practice 4: Scope MCP servers to the narrowest config level possible — prefer local or user scope over project scope for sensitive credentials

Do: When adding an MCP server, choose your scope deliberately:

For servers that require credentials (API keys, tokens), use local or user scope — never embed secrets in .mcp.json. Use ${VAR} environment variable expansion so the file contains only the variable name, not the value. To set the variable, add it to your shell profile before starting Claude Code — for example, export GITHUB_TOKEN=your-actual-token in ~/.bashrc or ~/.zshrc, or use a .env file loaded by a tool like direnv.

⚠️ WARNING: .mcp.json is committed to git by default. Any secret placed in its env block will be in version control history.

Why: A .mcp.json in a public repository teaches every person who forks it exactly which MCP servers you trust — and attackers can craft servers at those same names or URLs to intercept connections. Keeping secrets out of committed files is a baseline for any software project.

Caveat: Project-scoped servers in .mcp.json require a workspace trust dialog before Claude Code activates them. The exact version of Claude Code that enforced this behavior most recently is available in the changelog. 🕒 verify live — specific version-pinned behavior references change frequently; check the current changelog rather than relying on a pinned version for behavior verification.

Sources:

Confidence: 📄 vendor-documented


Practice 5: Enable sandbox mode to contain the blast radius of a compromised MCP chain

Do: Enable Claude Code’s built-in Bash sandbox with /sandbox or by setting sandbox.enabled: true in your settings. On Linux and Mac, add this to ~/.claude/settings.json (user-wide) or .claude/settings.json in your project root. The sandbox does not run on native Windows — use WSL2.

In the sandbox configuration, explicitly deny reads of credential files and unset secret environment variables:

{
  "sandbox": {
    "enabled": true,
    "failIfUnavailable": true,
    "allowUnsandboxedCommands": false,
    "credentials": {
      "files": [
        { "path": "~/.aws/credentials", "mode": "deny" },
        { "path": "~/.ssh", "mode": "deny" }
      ],
      "envVars": [
        { "name": "GITHUB_TOKEN", "mode": "deny" },
        { "name": "NPM_TOKEN", "mode": "deny" }
      ]
    }
  }
}

On Linux and Mac, ~ means your home directory. On Windows with WSL2, use the WSL path (e.g., /home/yourname/) rather than a Windows C:\ path.

Why: MCP tool results can contain hidden instructions (prompt injection). If Claude is tricked into running a malicious shell command, the sandbox restricts what that command can read or write. Without it, a single poisoned tool response could exfiltrate your SSH private key or AWS credentials — because the docs explicitly warn: “the default read behavior allows reading credential files such as ~/.aws/credentials and ~/.ssh/.”

⚠️ WARNING — dangerous default: Sandboxing is OFF by default. The sandbox also does not apply to Claude’s built-in Read/Edit/Write file tools, only to Bash commands. Without the credentials block, sandboxed commands can still read ~/.aws/credentials. Set failIfUnavailable: true to make missing sandbox dependencies a hard failure rather than a silent fallback to unsandboxed execution. Note: the sandbox does not run on native Windows — on native Windows this config block will silently do nothing unless failIfUnavailable: true is set, which will cause Claude Code to refuse to run Bash commands entirely until WSL2 is configured.

Caveat: The sandbox network proxy does not terminate TLS, so it cannot inspect encrypted traffic. A command with permission to reach github.com could use domain fronting to reach other hosts. For higher-assurance environments, configure a custom proxy with TLS inspection.

Sources:

Confidence: 📄 vendor-documented


Practice 6: Treat MCP tool results as untrusted content — never disable prompt-injection protections

Do: Follow the documented prompt-injection mitigations:

  1. Review suggested commands before approval.
  2. Do not pipe untrusted external content directly to Claude.
  3. Be extra cautious with MCP servers that fetch content from the web (README files, GitHub issues, external APIs) — each fetch is a potential injection vector.
  4. Keep curl, wget, and network-fetching commands in the deny list unless explicitly needed; if needed, use WebFetch(domain:...) rules to constrain to specific domains.
  5. Do not use bypassPermissions or auto mode when connected to MCP servers that read external content you do not control.

Why: Prompt injection means an attacker plants instructions inside content that Claude reads — a GitHub issue, a README, a database row, a ticket description — and Claude follows those instructions as if they were yours. In January 2026, Cyata researchers found three CVEs in Anthropic’s own mcp-server-git that enabled remote code execution through this attack: malicious content in a repository triggered Git operations that executed arbitrary scripts. The three CVEs: CVE-2025-68145 (path validation bypass), CVE-2025-68143 (unrestricted git_init), CVE-2025-68144 (argument injection in git_diff).

Caveat: Claude Code runs some mitigations already: an isolated context window for web fetches, trust verification dialogs for new MCP servers, and a separate server-side probe in auto mode that scans tool results before Claude reads them. But the security page explicitly states: “no system is completely immune to all attacks.” Independent researchers (TrueFoundry) confirm that model-level detection alone is insufficient; infrastructure-level controls are required. The 2026-07-28 spec’s own text carries the core tool-safety principle (“descriptions of tool behavior… should be considered untrusted, unless obtained from a trusted server”) forward verbatim — it is accurate to say the revision adds no new tool-poisoning/prompt-injection countermeasures, not accurate to say the topic goes unaddressed.

Sources:

Confidence: ✅ independently-corroborated (Anthropic docs + The Register CVE reporting + independent security researchers)


Practice 7: For teams, enforce an MCP server allowlist through managed settings — do not rely on per-developer discipline alone

Do: Organizations using Claude Code on Team or Enterprise plans should configure allowedMcpServers + allowManagedMcpServersOnly: true through server-managed settings or MDM (Mobile Device Management — software like Jamf, Intune, or Mosyle that your IT team uses to push settings to all company computers). If you do not have an IT team, this practice is out of scope for your personal setup — focus on Practices 1–5 instead.

To disable MCP entirely for a team:

{ "mcpServers": {} }

To restrict to an allowlist of approved remote servers:

{
  "allowManagedMcpServersOnly": true,
  "allowedMcpServers": [
    { "serverUrl": "https://api.githubcopilot.com/*" },
    { "serverUrl": "https://mcp.sentry.dev/*" }
  ]
}

Use serverUrl or serverCommand entries — not serverName — for enforcement. The server name is user-assignable and not a security control.

Why: CVE-2026-21852 covers ANTHROPIC_BASE_URL environment variable manipulation — an attacker overrides this variable to redirect authenticated API traffic to attacker-controlled infrastructure before any consent prompt appears. Correction from the previous snapshot: CVE-2026-21852 is fully patched (v2.0.65+); it is not contested or partially resolved. A separate, distinct vulnerability — disclosed by Mitiga Labs, with no CVE number assigned — involves malicious npm postinstall hooks rewriting ~/.claude.json; Anthropic’s response to that disclosure was that it is “out of scope,” reasoning that the attack requires prior code execution through a package installation the user already consented to. As of the CSO Online article’s publication, no patch exists for that separate, unnamed issue. A managed allowlist protects against both: even if a developer’s config is manipulated by either attack, illegitimate servers are blocked before they can connect.

⚠️ WARNING — a separate, unpatched npm-postinstall attack exists (not CVE-2026-21852): Do not conflate the two. CVE-2026-21852 (ANTHROPIC_BASE_URL override) is fully patched — treat it as resolved. The Mitiga-disclosed npm-postinstall/~/.claude.json-rewrite attack has no CVE number and, per Anthropic’s own stated position, no patch is planned. Do not install untrusted npm packages in a project you open with Claude Code, since package installation is exactly the prerequisite Anthropic’s “out of scope” reasoning depends on. See the “Held pending” section below.

Caveat: deniedMcpServers always merges from all settings sources, including user settings — so users can always block servers for themselves. A previously allowed server that is later blocked disappears silently from /mcp with no warning to the user — communicate policy changes proactively. Also: managed-mcp.json cannot be delivered through server-managed settings; it requires a system-level file deployed by MDM, GPO, or fleet management.

Sources:

Confidence: ✅ independently-corroborated (Anthropic docs + CSO Online incident reporting + independent security research)


Practice 8: Enable OpenTelemetry audit logging for MCP tool calls — do not fly blind in production

Do: Export MCP tool-call telemetry to a SIEM (Security Information and Event Management — a tool like Splunk, Datadog, or Elastic that stores and searches logs from many systems in one place; for personal use, a simpler alternative is redirecting OTLP output to a local log file or a hosted log service like Grafana Cloud). Set the following environment variables — replace ALL placeholder values before using:

CLAUDE_CODE_ENABLE_TELEMETRY=1
OTEL_LOGS_EXPORTER=otlp
OTEL_LOG_TOOL_DETAILS=1
OTEL_EXPORTER_OTLP_LOGS_PROTOCOL=http/protobuf
OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=https://<YOUR-SIEM-HOSTNAME>:4318/v1/logs
OTEL_EXPORTER_OTLP_HEADERS="Authorization=Bearer <YOUR-BEARER-TOKEN>"

Replace <YOUR-SIEM-HOSTNAME> with your actual log endpoint and <YOUR-BEARER-TOKEN> with your actual bearer token. Using these placeholder values literally will result in silent monitoring failure — logs will appear to send but arrive nowhere, and you will believe you have audit coverage when you do not.

With OTEL_LOG_TOOL_DETAILS=1, every MCP tool call emits a tool_result event including mcp_server_name, mcp_tool_name, and tool_input (truncated at approximately 4 KB). tool_decision events record whether each call was allowed or denied and why.

Why: If an MCP server is hijacked or a developer accidentally connects a malicious one, you need a record of what it did. The Anthropic security page explicitly lists “Monitor Claude Code usage through OpenTelemetry metrics” as a team security practice. Without this, the CSO Online researchers noted that “the IP address in the provider’s logs resolves to Anthropic’s egress range. The user is real. The session is valid” — the attack looks identical to legitimate use from the provider’s side.

Caveat: Telemetry is opt-in and off by default. Prompt content and tool arguments are redacted by default even when telemetry is enabled — you must set OTEL_LOG_TOOL_DETAILS=1 explicitly to get MCP call arguments. Telemetry goes only to your configured OTLP endpoint; it is not sent to Anthropic. 🕒 verify live: metric names, attribute names, and the truncation limit may change across Claude Code versions. Check code.claude.com/docs/en/monitoring-usage before deploying.

Sources:

Confidence: ✅ independently-corroborated (Anthropic docs + independent security reporting on the forensic gap)


Held pending fixes (not publish-ready)

CHANGELOG (grading → this entry)

Carried forward from 2026-07-02 snapshot (unchanged content, items 1–17 — see prior snapshot’s CHANGELOG for full detail). New items for this 2026-07-29 refresh:

  1. Refresh trigger: MCP 2026-07-28 spec confirmed published as FINAL (was RC at time of prior snapshot). Banner rewritten to reflect final status and to clarify the client-side impact on Claude Code users is limited (transport details are SDK-internal) but connection compatibility with upgraded servers needs verification.
  2. Background section: added note that the protocol is now stateless at the transport level and that this is transparent to day-to-day Claude Code usage.
  3. Practice 6: caveat updated to flag tool-poisoning-vs-2026-07-28 as unresearched rather than silently carrying forward old text.
  4. Added new pending item: Claude Code’s own MCP-client support timeline for 2026-07-28 could not be confirmed this session.
  5. Skeptic FIX-10 — corrected (had been missed in the first correction pass): Practice 6’s caveat wrongly said the 2026-07-28 spec’s effect on tool-poisoning/prompt-injection guidance was “unresearched.” Corrected: the core tool-safety principle is confirmed carried forward verbatim; the revision adds no new countermeasures, but the topic is not unaddressed.