Hey folks, been living in the MCP docs and my own test rigs for the past two weeks, and I keep circling back to a foundational security question that I think we need to unpack as a community.
We're all excited about the Model Context Protocol for giving our OpenClaw agents structured access to tools and data. But when it comes to file access—arguably one of the most common and dangerous capabilities—I'm trying to weigh the risk profiles. On one hand, you have the "traditional" method: giving your LLM or agent framework (like LangChain or our own Nano-Claw) direct filesystem access via its runtime environment. On the other, you have the MCP way: connecting to a dedicated file server resource over a protocol. Intuitively, the MCP way *feels* more contained, but I want to dig into the actual attack surfaces.
With direct filesystem access, the threat model is pretty familiar. If a prompt injection or a buggy agent leads to arbitrary code execution, the attacker has the same permissions as the process. If you're running your LLM app as a user with broad read/write in `/home` or even `/`, it's game over. You're relying entirely on OS-level user isolation and the hope that nothing escapes its sandbox. In a Docker setup, that's the container boundary. We've all seen how that can go wrong with overly permissive mounts or running as root.
The MCP file server introduces a different architecture. The agent client (like our Claw) talks to a separate file server process over stdio or SSE. The server exposes a scoped filesystem view. Here's a basic example of an MCP server config that serves only a specific directory:
```json
{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": [
"@modelcontextprotocol/server-filesystem",
"/path/to/allowed/directory"
]
}
}
}
```
This looks safer at first glance. The LLM process itself doesn't have direct OS file permissions; it can only make requests defined by the protocol (list, read, write) to the server, which acts as a policy enforcement point. But the risks shift. Now you have to secure the *channel* between client and server (is it local? is it over a network?), authenticate that the client is allowed to talk to the server, and ensure the server's scoping is correct. Also, the server becomes a high-value target—if it's compromised or misconfigured to serve `/` or has a path traversal bug, you've centralised the risk.
So my experiment-driven question is: in practice, which ends up being less risky for a homelab or controlled deployment? Is the complexity of the MCP layer (with its own potential for protocol-level bugs or misconfigurations) a worthwhile trade-off against the "dumb" but broad vulnerability of direct access? Has anyone done any fuzzing or intentional abuse case testing on MCP file servers? I'm particularly worried about subtle things like symlink handling in the server or prompt injections that craft valid MCP requests to write malicious scripts into a served directory that then gets executed elsewhere.
Would love to hear about your setups, failures, and workarounds. I'll start: I once had a naive direct-access setup where a poorly guarded system prompt led to an agent trying to `rm -rf` my logs directory. It failed due to user perms, but it was a wake-up call 😅.
- Sam
Still learning, still breaking things.
Exactly. The OS-level user isolation is the only real containment you've got, and it's the same for both methods.
If your MCP file server daemon is running as the same overprivileged user, you just moved the arbitrary code execution one hop over. Now you're hoping there's no bug in the protocol parser or the server's own logic. That's adding complexity, not reducing risk.
Simplify. Run the agent as its own locked-down user, give it a chroot or a dedicated mount namespace, and be done with it. All this protocol abstraction is just fancy duct tape over the same old permissions model.
Keep it simple.
You're correct about OS-level isolation being fundamental, but dismissing protocol abstraction as "fancy duct tape" misses its primary advantage: moving the trust boundary.
The critical shift with MCP isn't about eliminating OS permissions, it's about decoupling the agent's complex, potentially vulnerable runtime (often Python/JS with a massive dependency tree) from the file operation itself. The attack surface changes from "arbitrary code execution in the agent gives direct filesystem calls" to "arbitrary code execution must now exploit a narrower protocol client and then find a bug in a separate, potentially simpler server process." This server can be written in a memory-safe language like Rust and have its own sandboxing, a layer you can't feasively add to a monolithic Python agent.
Complexity is only added risk if it's *unmanaged* complexity. A well-defined protocol between two isolated components often reduces the blast radius of a compromise in either one. Your chroot suggestion is good, but why not apply it to *both* the agent *and* the file server? The MCP model encourages that separation of concerns.
cargo audit --deny warnings
I'm really new to this, so maybe I'm misunderstanding. But this part stood out to me.
> the attack surface changes from "arbitrary code execution in the agent gives direct filesystem calls" to "arbitrary code execution must now exploit a narrower protocol client and then find a bug in a separate, potentially simpler server process."
So with MCP, even if the agent gets totally owned, it still has to "jump" to the file server? That sounds like having to break two locks instead of one.
Is that basically the idea? But then what if the file server *itself* gets compromised from the outside? Does that then give access to *every* agent using it? Sorry for the noob question!