Connecting Local Tools via MCP
Connect local files, scripts, and services while keeping the host machine protected.
Why local access is sensitive
A local MCP server can often reach files, environment variables, processes, network services, and credentials that a hosted model cannot see directly. That convenience changes the threat model: a confused model, malicious document, or compromised dependency may turn a harmless-looking request into local compromise. Treat every local capability as a privileged API. Begin with a written inventory of directories, commands, sockets, and network destinations, then remove access that the workflow does not require.
Sandbox the process
Run the server with a dedicated user, restricted filesystem permissions, and an isolated working directory. Containers, macOS sandboxing, or operating-system policy tools can reduce blast radius, but configuration must be tested rather than assumed. Keep credentials out of the process environment when possible, and never mount an entire home directory for convenience. If a tool needs network access, allowlist destinations and protocols. Isolation is valuable because validation bugs and dependency vulnerabilities are inevitable possibilities.
from pathlib import Path
ALLOWED_ROOT = Path("/srv/project-docs").resolve()
def read_document(requested: str) -> str:
path = (ALLOWED_ROOT / requested).resolve()
if ALLOWED_ROOT not in path.parents:
raise ValueError("path is outside the approved directory")
if not path.is_file():
raise FileNotFoundError(path.name)
return path.read_text(encoding="utf-8")[:20_000]Expose files safely
For a file tool, define approved roots and resolve every requested path to a canonical absolute path before access. Reject traversal, symbolic-link escapes, device files, hidden credential directories, and paths outside the allowlist. Decide whether reads may include binary data, how large a response can be, and whether the user must approve each file. Use stable resource identifiers instead of letting a model construct arbitrary paths. Return metadata and bounded content, with pagination for larger documents.
Expose scripts carefully
A generic execute command tool is usually too powerful because it turns model output into arbitrary code execution. Replace it with named operations that accept typed arguments and map to fixed commands or library functions. Validate arguments, environment, working directory, runtime, output size, and time limit. Drop privileges and disable shell interpretation where possible. If arbitrary execution is unavoidable for a controlled development environment, isolate it, require confirmation, record the exact command, and make the risk visible to the user.
Protect local services
Localhost is not a security boundary by itself. A tool that forwards requests to a local database, Docker socket, browser profile, or administrative endpoint may expose powerful capabilities. Use explicit host and port allowlists, authenticated connections, safe HTTP methods, and response limits. Prevent server-side request forgery by rejecting user-controlled URLs or resolving them against a fixed destination map. Separate read and write tools so approval and authorization can differ. Review local service logs as well.
Approval and user experience
The host should show users what local action is proposed, which resource it targets, and what arguments will be used before a mutation or process launch. Approval should bind to the exact operation and expire quickly; a broad “allow everything” switch defeats the point. Make read-only actions visible too when they involve sensitive directories. Explain failures without leaking paths or secrets. Good approval UX reduces accidental consent by making the consequence understandable rather than hiding it behind protocol details.
Audit and recover
Record a request identifier, authenticated principal, tool name, normalized target, approval result, duration, exit status, and affected object when available. Do not store complete file contents, tokens, or private command output by default. Keep backups and recovery procedures for tools that change local data, and test whether cancellation actually stops child processes. Review logs for repeated denied paths, unusual volume, and unexpected destinations. Local integrations are maintainable when you can reconstruct an incident without collecting more sensitive data than necessary.