Model Context Protocol – Advanced Patterns for Production By the end of this lesson, students should be able to: The file system access risk. An MCP server with file system access can read and write files on the host system. Without path restrictions, a server that accepts a path parameter from Claude's tool call can be used (via prompt injection) to read or write any file the server process can access – including credentials, configuration files, and sensitive data. Path restriction implementation. Every file system tool must validate that the requested path is within the allowed root: import os ALLOWED_ROOT = Path("/allowed/directory").resolve() def validate_path(requested_path: str) -> Path: @app.call_tool() The Path traversal attacks. Path traversal: a tool argument of Principle of least privilege for file system access. Configure the server's allowed root to be the minimum necessary: Do not give a documentation server write access. Do not give a read-only server access to the entire file system. Each server's permissions should match exactly what its tools need. Process-level permissions. Beyond path validation in code, run the MCP server process as a user with limited file system permissions. A server that needs read access to Enroll to continue this lesson. The preview above shows the lesson objectives and opening lesson content. Enroll to view the full lesson, complete the practice work, and take the lesson quiz.
Lesson 3: File System Access and Security Boundaries
Lesson Objectives
Lesson Content
from pathlib import Path
resolved = (ALLOWED_ROOT / requested_path).resolve()
if not str(resolved).startswith(str(ALLOWED_ROOT)):
raise ValueError(f"Path {requested_path} is outside allowed root")
return resolved
async def call_tool(name: str, arguments: dict):
if name == "read_file":
path = validate_path(arguments["path"]) # validates before any file access
return [types.TextContent(type="text", text=path.read_text())].resolve() call on both paths normalizes ../ traversal sequences before the comparison – preventing path traversal attacks.../../etc/passwd – without path validation, this resolves to /etc/passwd, outside the intended directory. The .resolve() approach prevents this by resolving the final path and checking it starts with the allowed root./docs/ should run as a user that only has read access to /docs/. This provides defense in depth – even if the path validation has a bug, the OS-level permissions limit what the server can actually access.
