File System MCP Server
A secure MCP server for file operations with directory access controls
The File System MCP Server is a FastMCP-based server that provides secure file system operations for CUGA. It enforces directory-level access controls to ensure agents can only access authorized paths.
Overview
The File System MCP Server provides:
- Read Operations: Read files (text and media), list directories
- Write Operations: Create, edit, and move files and directories
- Search: Find files by pattern with glob support
- Security: Directory allowlisting with path validation
- Read-Only Mode: Option to expose only read operations
Security Model
The server implements a strict security model:
- Allowlisted Directories: Only explicitly specified directories are accessible
- Path Validation: All paths are resolved and validated before operations
- No Escape: Symlinks and path traversal attempts are blocked
- Read-Only Option: Can restrict to read operations only
Quick Start
Install Dependencies
cd docs/examples/demo_apps/file_system
uv syncStart the Server
# Allow access to specific directories
uv run python main.py ./workspace /tmp/cuga-data
# Read-only mode
uv run python main.py --read-only ./workspaceDefault Port
| Component | Default Port | Environment Variable |
|---|---|---|
| File System MCP | 8112 | DYNACONF_SERVER_PORTS__FILESYSTEM_MCP |
MCP Tools
Read Operations
read_text_file
Read a text file's contents.
Parameters:
path(string, required): Path to the filehead(int, optional): Read only first N linestail(int, optional): Read only last N lines
Examples:
# Read entire file
read_text_file(path="./workspace/data.txt")
# Read first 10 lines
read_text_file(path="./workspace/logs.txt", head=10)
# Read last 50 lines
read_text_file(path="./workspace/logs.txt", tail=50)read_media_file
Read an image or audio file as base64.
Parameters:
path(string, required): Path to the media file
Response:
{
"mimeType": "image/png",
"data": "base64-encoded-content",
"type": "image"
}read_multiple_files
Read multiple files in one operation.
Parameters:
paths(array, required): List of file paths
Example:
read_multiple_files(paths=["./config.yaml", "./settings.json"])Directory Operations
list_directory
Get a simple listing of directory contents.
Parameters:
path(string, required): Directory path
Response:
[DIR] src
[DIR] tests
[FILE] README.md
[FILE] pyproject.tomllist_directory_with_sizes
Get directory listing with file sizes.
Parameters:
path(string, required): Directory pathsortBy(string, optional): "name" or "size" (default: "name")
Response:
[DIR] src
[FILE] README.md 2.5KB
[FILE] data.json 15.3MB
Total: 2 files, 1 directories
Combined size: 15.3MBdirectory_tree
Get recursive directory structure as JSON.
Parameters:
path(string, required): Root directoryexcludePatterns(array, optional): Patterns to exclude
Example:
directory_tree(
path="./project",
excludePatterns=["node_modules", "*.pyc", "__pycache__"]
)Write Operations
write_file
Create or overwrite a file.
Parameters:
path(string, required): File pathcontent(string, required): File content
Example:
write_file(
path="./workspace/output.txt",
content="Report generated by CUGA"
)edit_file
Make targeted edits to a file.
Parameters:
path(string, required): File pathedits(array, required): List of edits witholdTextandnewTextdryRun(boolean, optional): Preview changes without applying
Example:
edit_file(
path="./config.yaml",
edits=[
{"oldText": "debug: false", "newText": "debug: true"},
{"oldText": "port: 8080", "newText": "port: 9000"}
],
dryRun=False
)Response (diff format):
Changes applied successfully
--- ./config.yaml
+++ ./config.yaml
- debug: false
+ debug: true
- port: 8080
+ port: 9000create_directory
Create a directory (including nested paths).
Parameters:
path(string, required): Directory path to create
move_file
Move or rename a file/directory.
Parameters:
source(string, required): Source pathdestination(string, required): Destination path
Search Operations
search_files
Find files matching a pattern.
Parameters:
path(string, required): Root path to searchpattern(string, required): Glob patternexcludePatterns(array, optional): Patterns to exclude
Examples:
# Find all Python files
search_files(path="./project", pattern="**/*.py")
# Find configs, excluding backups
search_files(
path="./project",
pattern="**/*.yaml",
excludePatterns=["backup/*", "*.bak"]
)Information Operations
get_file_info
Get detailed file metadata.
Parameters:
path(string, required): File path
Response:
size: 1234567
created: 2024-01-15T10:30:00
modified: 2024-01-20T14:45:00
accessed: 2024-01-21T09:00:00
isDirectory: false
isFile: true
permissions: 644list_allowed_directories
Show which directories are accessible.
Response:
Allowed directories:
/Users/user/workspace
/tmp/cuga-dataUsing with CUGA
Configure as MCP Server
Add the File System MCP to your configuration:
# mcp_servers.yaml
servers:
- name: filesystem
type: mcp
url: http://localhost:8112
transport: sseExample Tasks to Try
Test CUGA with these natural language queries:
File Reading:
Read the contents of workspace/contacts.txtShow me the last 20 lines of the log fileRead the README and config.yaml files
Directory Navigation:
List all files in the workspace directoryShow me the directory structure of the projectFind all .py files in the src folder
File Creation:
Create a new file called report.md with a summary of today's workSave the contact list to workspace/contacts.txt
File Editing:
Update the config file to enable debug modeChange the port from 8080 to 9000 in settings.yaml
Multi-Tool Workflows: Combine with other tools:
Read contacts.txt, find those contacts in the CRM, and save a reportGet the top accounts from the API and write them to accounts.csvFind all emails about the project and save them to a summary file
Read-Only Mode
For safer deployments, enable read-only mode:
uv run python main.py --read-only ./workspaceIn read-only mode, only read_text_file is exposed. All write operations are hidden.
Configuration
Environment Variables
# Custom port
export DYNACONF_SERVER_PORTS__FILESYSTEM_MCP=8112Allowing Multiple Directories
# Multiple directories
uv run python main.py ./workspace /data /config ~/Documents
# Home directory expansion works
uv run python main.py ~/workspace ~/.configSecurity Best Practices
- Principle of Least Privilege: Only allow directories that CUGA needs
- Use Read-Only Mode: When write access isn't required
- Avoid Root Paths: Never allow
/or overly broad directories - Review Paths: Ensure symlinks don't escape allowed directories
Safe Configurations
# Good - specific workspace only
uv run python main.py ./workspace
# Good - read-only for browsing
uv run python main.py --read-only /data/reports
# Dangerous - too broad
# uv run python main.py / # DON'T DO THISTroubleshooting
Access Denied Errors
Problem: "Access denied: path is outside allowed directories"
Solutions:
- Verify the path is within an allowed directory
- Check for symlinks that may resolve outside allowed paths
- Use
list_allowed_directoriesto see what's accessible
File Not Found
Problem: File operations fail with "not found"
Solutions:
- Use absolute paths or paths relative to allowed directories
- Check file permissions at the OS level
- Verify the file exists with
list_directory
Server Won't Start
Problem: Server fails to start
Solutions:
- Ensure at least one directory is specified
- Verify all specified directories exist
- Check port availability
Large Directory Listings
Problem: directory_tree is slow or returns too much data
Solutions:
- Use
excludePatternsto skip large directories:directory_tree( path="./project", excludePatterns=["node_modules", ".git", "__pycache__", "*.pyc"] )
Next Steps
- Review MCP Server Integration for configuration
- Check Email MCP Demo for email operations
- Explore CRM Demo for combining with API tools
