Zed MCP Security: Scanning with Pipelock

Wrap Zed context_servers with bidirectional scanning.

Ready to protect your own setup?

Zed MCP security starts with inspecting what flows between Zed and every context_server. Pipelock wraps each entry in your settings.json so every tool call and response runs through its MCP proxy. Works on Zed stable, Zed Preview, and Flatpak builds of either channel.

What’s new in recent releases

Zed integration is pure MCP proxy wrapping. That brings the current signed-evidence and class-preserving redaction surface into the Zed MCP path as soon as the wrap is in place:

  • Mediator-signed action receipts for MCP decisions (v2.2.0). With flight_recorder.signing_key_path set in the pipelock config, each proxied Zed MCP decision emits a chained Ed25519 receipt on the mcp_stdio transport.
  • Cross-implementation verifier (v2.2.0). Receipts verify byte-for-byte against the published Python verifier using a conformance suite. The receipt format is open, not a vendor artifact.
  • Class-preserving redaction on tools/call arguments (v2.3.0). Matched secrets in params.arguments are rewritten in place with typed placeholders like pl:aws-access-key:1 before forwarding to the MCP server.
  • Header sidecar carrier for credential-bearing remote servers (v2.4.0). Remote context_servers with Authorization or X-API-Key headers get their values stashed in a 0o600 sidecar file referenced via –header-file. Header values never appear in /proc//cmdline.

See the action receipt spec for the receipt format and the AI agent data redaction guide for redaction rollout.

Quick Start

# Install pipelock
brew install luckyPipewrench/tap/pipelock

# Wrap every Zed MCP context_server (default discovery; no args needed)
pipelock zed install

# Restart Zed

Verify with pipelock discover: the report should show every Zed channel with all servers tagged as protected.

What Gets Scanned

Once installed, pipelock sits between Zed and every MCP server:

Zed agent  <-->  pipelock mcp proxy  <-->  MCP Server
                 (scan both directions)    (subprocess or HTTP upstream)

Every layer applies: DLP pattern matching on tool arguments, prompt injection detection on tool results, tool poisoning checks on tool definitions, tool policy with shell-obfuscation detection, chain detection across tool call sequences, and session binding pinning the tool inventory per session. From Pipelock v2.3.0, request-side redaction also rewrites matched secrets in tools/call params.arguments before forwarding. When receipt signing is configured, every decision emits a signed action receipt.

Install Discovers Every Standard Path

Default discovery scans all five standard Zed settings.json locations:

PathChannel
<cwd>/.zed/settings.jsonProject-local
$XDG_CONFIG_HOME/zed/settings.json (or ~/.config/zed/settings.json)Native stable
$XDG_CONFIG_HOME/zed-preview/settings.jsonNative Preview
~/.var/app/dev.zed.Zed/config/zed/settings.jsonFlatpak stable
~/.var/app/dev.zed.Zed.Preview/config/zed-preview/settings.jsonFlatpak Preview

Each file that exists is wrapped independently with its own .bak backup. Use –path to target a single explicit file.

# Default: wrap every existing Zed settings.json
pipelock zed install

# Preview without writing
pipelock zed install --dry-run

# Single explicit file
pipelock zed install --path ~/some/custom/settings.json

# Specific pipelock config
pipelock zed install --config ~/.config/pipelock/pipelock.yaml

How It Works

zed install reads each settings.json, wraps every context_servers entry through pipelock mcp proxy, and atomically writes the modified file back. The original command, args, and env are preserved in a _pipelock metadata block. Non-server top-level fields (theme, ui_font_size, agent settings, key bindings) are preserved across the rewrite.

Stdio servers get their command wrapped:

// Before
{"command": "npx", "args": ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"]}

// After
{
  "type": "stdio",
  "command": "pipelock",
  "args": ["mcp", "proxy", "--config", "...", "--", "npx", "-y", "@modelcontextprotocol/server-filesystem", "/tmp"]
}

Remote (URL) servers get rewritten to spawn pipelock as a stdio-to-HTTP bridge:

// Before
{"url": "https://api.example.com/mcp"}

// After
{"command": "pipelock", "args": ["mcp", "proxy", "--config", "...", "--upstream", "https://api.example.com/mcp"]}

Credential-bearing headers land in a 0o600 sidecar file referenced via –header-file. The sidecar path is hashed from the absolute settings.json path, so a same-named context_server at project and user scope can never clobber the other scope’s credential carrier.

Remove

# Restore original configs across every wrapped settings.json
pipelock zed remove

# Single file
pipelock zed remove --path ~/.config/zed/settings.json

# Preview without writing
pipelock zed remove --dry-run

Remove restores the original server entries from the _pipelock metadata field and strips that field. Non-wrapped entries and non-server top-level fields are left untouched.

Proof: a real MCP-level DLP block

With the wrap in place against the official @modelcontextprotocol/server-filesystem MCP server, an attempted tools/call write_file carrying an AWS-style key gets blocked at the MCP input boundary:

pipelock: proxying MCP server [npx -y @modelcontextprotocol/server-filesystem /tmp]
          (response=warn, input=block, tools=block, policy=warn)
pipelock: input line 3: blocked tools/call request (AWS Access ID)

{"jsonrpc":"2.0","id":2,"error":{"code":-32001,
  "message":"pipelock: request blocked by MCP input scanning"}}

$ ls /tmp/mcp-leak.txt
ls: cannot access '/tmp/mcp-leak.txt': No such file or directory

The credential never reaches the filesystem MCP server and the file is never written. The block is at the protocol layer, not a model-side refusal. Whatever model you have configured in Zed sees the JSON-RPC error and the tool call fails.

Discovering Wrap Status Across Channels

pipelock discover reports MCP servers across every IDE it knows about, including all four Zed channels:

$ pipelock discover
zed                  1 server,  1 protected
zed-preview          1 server,  0 protected   <-- channel missed during install
zed-flatpak          0 servers
zed-preview-flatpak  0 servers

Use pipelock discover --json for a machine-readable report.

Limitations

  • Header passthrough on tools/call responses is request-side only in v1: the wrap rewrites secrets in arguments before forwarding to the MCP server, but tool responses are not rewritten. Use prompt injection and tool poisoning detection on the response path for response-side coverage.
  • agent_servers (Zed’s separate block for built-in agent integrations like the claude-acp registry) is not an MCP surface and is intentionally left alone.
  • IDE restart required after install or remove.

See also: Claude Code · Cursor · JetBrains · Full documentation

Frequently asked questions

What does Pipelock's Zed integration do?
Pipelock wraps every entry under context_servers in Zed’s settings.json so that the spawned command is pipelock instead of the original MCP server. Every tool call, tool response, tool description, and tool-list payload is scanned bidirectionally for credential leaks (full default DLP pattern set), prompt injection (6-pass normalization), and tool poisoning. The original command, args, and env are stashed in a _pipelock metadata block for clean removal.
How do I install Pipelock for Zed?
Run ‘pipelock zed install’ after installing the pipelock binary via Homebrew (brew install luckyPipewrench/tap/pipelock) or Go (go install github.com/luckyPipewrench/pipelock/cmd/pipelock@latest). Default discovery scans every standard Zed settings.json path (project-local, native stable, native Preview, Flatpak stable, Flatpak Preview). Each file that exists is wrapped independently with its own .bak backup. Restart Zed to activate.
Does Pipelock support Flatpak-installed Zed?
Yes. Default discovery includes ~/.var/app/dev.zed.Zed/config/zed/settings.json for Flatpak stable and ~/.var/app/dev.zed.Zed.Preview/config/zed-preview/settings.json for Flatpak Preview. Both are wrapped automatically alongside any native install on the same machine.
Does Pipelock redact secrets in Zed MCP tool arguments?
Yes, in Pipelock v2.3.0 and later. With the redaction section enabled in the pipelock config, matched secrets inside tools/call params.arguments are rewritten in place with typed placeholders such as pl:aws-access-key:1 before forwarding to the MCP server. Redaction runs on the same MCP proxy transports the wrap uses (mcp_stdio for command-based servers, mcp_http_upstream for url-based servers). Request-side only in v1; tool responses are not rewritten and the redactor fails closed on parse errors.

Ready to protect your own setup?