CUGA LogoCUGA AGENT
Guides & Examples

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:

  1. Allowlisted Directories: Only explicitly specified directories are accessible
  2. Path Validation: All paths are resolved and validated before operations
  3. No Escape: Symlinks and path traversal attempts are blocked
  4. Read-Only Option: Can restrict to read operations only

Quick Start

Install Dependencies

cd docs/examples/demo_apps/file_system
uv sync

Start 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 ./workspace

Default Port

ComponentDefault PortEnvironment Variable
File System MCP8112DYNACONF_SERVER_PORTS__FILESYSTEM_MCP

MCP Tools

Read Operations

read_text_file

Read a text file's contents.

Parameters:

  • path (string, required): Path to the file
  • head (int, optional): Read only first N lines
  • tail (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.toml

list_directory_with_sizes

Get directory listing with file sizes.

Parameters:

  • path (string, required): Directory path
  • sortBy (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.3MB

directory_tree

Get recursive directory structure as JSON.

Parameters:

  • path (string, required): Root directory
  • excludePatterns (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 path
  • content (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 path
  • edits (array, required): List of edits with oldText and newText
  • dryRun (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: 9000

create_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 path
  • destination (string, required): Destination path

Search Operations

search_files

Find files matching a pattern.

Parameters:

  • path (string, required): Root path to search
  • pattern (string, required): Glob pattern
  • excludePatterns (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: 644

list_allowed_directories

Show which directories are accessible.

Response:

Allowed directories:
/Users/user/workspace
/tmp/cuga-data

Using 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: sse

Example Tasks to Try

Test CUGA with these natural language queries:

File Reading:

  • Read the contents of workspace/contacts.txt
  • Show me the last 20 lines of the log file
  • Read the README and config.yaml files

Directory Navigation:

  • List all files in the workspace directory
  • Show me the directory structure of the project
  • Find all .py files in the src folder

File Creation:

  • Create a new file called report.md with a summary of today's work
  • Save the contact list to workspace/contacts.txt

File Editing:

  • Update the config file to enable debug mode
  • Change 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 report
  • Get the top accounts from the API and write them to accounts.csv
  • Find 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 ./workspace

In 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=8112

Allowing Multiple Directories

# Multiple directories
uv run python main.py ./workspace /data /config ~/Documents

# Home directory expansion works
uv run python main.py ~/workspace ~/.config

Security Best Practices

  1. Principle of Least Privilege: Only allow directories that CUGA needs
  2. Use Read-Only Mode: When write access isn't required
  3. Avoid Root Paths: Never allow / or overly broad directories
  4. 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 THIS

Troubleshooting

Access Denied Errors

Problem: "Access denied: path is outside allowed directories"

Solutions:

  1. Verify the path is within an allowed directory
  2. Check for symlinks that may resolve outside allowed paths
  3. Use list_allowed_directories to see what's accessible

File Not Found

Problem: File operations fail with "not found"

Solutions:

  1. Use absolute paths or paths relative to allowed directories
  2. Check file permissions at the OS level
  3. Verify the file exists with list_directory

Server Won't Start

Problem: Server fails to start

Solutions:

  1. Ensure at least one directory is specified
  2. Verify all specified directories exist
  3. Check port availability

Large Directory Listings

Problem: directory_tree is slow or returns too much data

Solutions:

  • Use excludePatterns to skip large directories:
    directory_tree(
        path="./project",
        excludePatterns=["node_modules", ".git", "__pycache__", "*.pyc"]
    )

Next Steps

Resources