HOW-TO · SUP

How to create custom MCP servers for file access

advanced30 minBy Fredoline Eruo
Target environment
Ubuntu 24.04 · Ollama 0.4.x
PREREQUISITES

MCP SDK, Python 3.10+

What this does

Creating a custom Model Context Protocol (MCP) server for file access enables AI agents to read, write, list, and search files on the host system through a standardized protocol. The MCP server exposes file system operations as tools that agents invoke via the MCP client interface. This provides controlled, sandboxed file access with configurable path restrictions, preventing agents from accessing sensitive directories while enabling productive file-based workflows.

Steps

Initialize the MCP server project: mkdir file-access-mcp && cd file-access-mcp && python -m venv .venv && source .venv/bin/activate && pip install mcp. Create server.py and import the MCP server class: from mcp.server import Server, stdio_server. Define allowed paths: ALLOWED_ROOTS = [Path.home() / "workspace", Path.home() / "documents"]. Implement a path validation helper: def is_allowed(path: Path) -> bool: return any(path.resolve().is_relative_to(root.resolve()) for root in ALLOWED_ROOTS). Register tools using the @server.tool() decorator. Create read_file that takes a path string, validates it, and returns file contents. Create write_file with path and content parameters. Create list_directory that returns files and subdirectories for a given path. Create search_files that uses glob pattern matching within allowed roots. For each tool, wrap the implementation in try/except and return structured error responses with {"error": str(e)}. Set up the stdio transport for running as a subprocess: async def main(): async with stdio_server() as (read, write): await Server("file-access").run(read, write, tools=[read_file, write_file, list_directory, search_files]). Register the server in the MCP client configuration file (e.g., claude_mcp.json or mcp.json) with the command ["python", "server.py"] and the working directory.

  • Record the local run evidence. Save the exact command, runtime or package version, model name if applicable, and observed output so the result can be reproduced later.

  • Confirm the local starting state. Print the active binary, package version, model name, or configuration path before changing the workflow.

  • Run the smallest complete path. Execute the minimum command or script that proves the guide works end to end on the local machine.

  • Compare against expected output. Check the final line, status code, generated artifact, or model response against the verification section before expanding the setup.

  • Record the local run evidence. Save the exact command, runtime or package version, model name if applicable, and observed output so the result can be reproduced later.

Verification

Start the MCP server manually: python server.py and verify no startup errors. From the agent interface, invoke the list_directory tool with path ~/workspace and confirm it returns the correct file listing. Test the path restriction: attempt to read /etc/passwd and verify the tool returns a permission error. Write a file, read it back, and confirm the content matches. Use search_files with pattern "*.py" and verify it finds Python files in the allowed roots.

Common failures

Path resolution bypass: An attacker-crafted path like ~/workspace/../../etc/passwd could escape—always call .resolve() before validation and reject if the resolved path contains .. after resolution. MCP server not connecting: Check the client configuration for correct command path and working directory; run python server.py directly to see raw output. Encoding errors on binary files: Detect binary content with try/except UnicodeDecodeError and return base64-encoded data or a clear "binary file" message. Concurrent access race conditions: Use file locking via fcntl.flock or msvcrt.locking for write operations. Large file memory issues: Stream read operations in chunks of 8192 bytes and set a maximum file size guard of 10 MB.

  • Version mismatch - The installed package or runtime differs from the command shown; check the version first and rerun the smallest verification command.
  • Local environment drift - Another service, virtual environment, model, or path is being used; print the active binary path and configuration before changing the guide steps.

Related guides

  • setup-agent-tool-use-function-calling
  • build-multi-agent-supervisor-workflow
  • setup-authentication-local-ai-endpoints