# Filesystem Server

> Authors: Matheus Cafalchio, Jonathan Springer

A secure MCP (Model Context Protocol) server written in Rust that provides comprehensive filesystem operations with sandboxing, atomic writes, and pattern-matching edits. Uses the official [Rust MCP SDK](https://github.com/modelcontextprotocol/rust-sdk).

## Features

- **Memory-safe**: Zero unsafe code, fully clippy-clean, MUSL-compatible static binaries (~4 MB)
- **Sandboxed**: All operations confined to configured root directories; symlink traversal blocked
- **Atomic writes**: Safe file modifications via atomic operations with dry-run support
- **10 filesystem tools**: read, write, edit, search, move, list, info, and more
- **Production-ready**: Docker images <10 MB, Kubernetes-deployable, comprehensive test coverage
- **High-performance**: Async tokio-based with streaming support

## Tools

All tools operate within sandboxed root directories. Operations outside configured roots return errors.

| Tool | Purpose | Key Inputs | Notes / Best Practice |
|------|---------|-----------|----------------------|
| `read_file` | Return full UTF-8 text of a file | `path: string` | Fails if file not readable; size cap 1 MiB. |
| `read_multiple_files` | Get several files at once | `paths: string[]` | Streams results; failed paths are reported but do not abort the batch. |
| `write_file` | Create or overwrite a file | `path: string, content: string` | Performs atomic write via temp-file + rename. |
| `edit_file` | Targeted edits with diff preview | `path: string, edits: [{ oldText, newText }], dryRun: bool` | Supports multi-line & pattern matching, keeps indentation style; returns git-style diff in dry-run mode. Always dry-run first. |
| `create_directory` | Ensure directory exists | `path: string` | Creates parents (mkdir -p behaviour). |
| `list_directory` | List items with [FILE] / [DIR] tags | `path: string` | Sorted alphabetically. |
| `move_file` | Move / rename files or dirs | `source: string, destination: string` | Overwrites destination if exists. |
| `search_files` | Recursive glob search | `path, pattern, excludePatterns[]` | Case-insensitive; returns full paths. |
| `get_file_info` | Stat + metadata | `path: string` | Size, times, perms, type. |
| `list_allowed_directories` | Reveal sandbox roots | (none) | Returns array of allowed roots. |

## Quick Start

### Requirements

- Rust ≥ 1.77
- `make` (optional, for convenience)
- Docker (optional, for containerized deployment)

### Using Make

```bash
# Show available targets
make help

# Run with custom roots (space-separated)
make run ROOTS="/tmp /var/www"

# Or release build
make run-release ROOTS="/tmp /var/www"

# Run tests
make test
make test-lib
make test-integration

# Build
make build          # Debug
make release        # Optimized
make install        # Install to ~/.cargo/bin
```

### Using Cargo Directly

```bash
# Run with roots
cargo run -- --roots /tmp /var/www /home/user/projects

# Test
cargo test
```

### Using docker

```bash
# Single root
docker run \
  -p 8084:8084 \
  -v /tmp:/tmp \
  filesystem-server --roots /tmp

# Multiple roots - mount and pass as arguments
docker run \
  -p 8084:8084 \
  -v /var/www:/www \
  -v /tmp:/tmp \
  filesystem-server --roots "/www /tmp"
```
Image size: ~10 MB (binary: 3.2 MB + Debian slim base)


## Make Targets

```bash
filesystem-server - Makefile targets:
  build              - Build debug binary
  release            - Build optimized release binary
  debug              - Build and run debug binary
  test               - Run all tests
  test-lib           - Run library tests only
  test-integration   - Run integration tests
  coverage           - Generate coverage report
  fmt                - Format code with rustfmt
  clippy             - Run clippy linter
  check              - Run cargo check
  clean              - Remove build artifacts
  install            - Install binary to ~/.cargo/bin
  run                - Run debug binary (ROOTS=/folder1 /folder2 ...)
  run-release        - Run release binary (ROOTS=/folder1 /folder2 ...)
  container-build    - Build container image
  container-run      - Run container
  container-stop     - Stop container
```

## Testing

### Run Tests

```bash
make test           # All tests
make test-lib       # Library tests
make test-integration  # Integration tests
make coverage       # Coverage report (HTML)
```
### Test coverage

| Filename       | Function Coverage | Line Coverage | Region Coverage | Branch Coverage |
|----------------|-----------------|---------------|----------------|----------------|
| lib.rs         | 60.00% (3/5)    | 46.88% (15/32) | 67.44% (29/43) | - (0/0)        |
| main.rs        | 0.00% (0/3)     | 0.00% (0/17)   | 0.00% (0/27)   | - (0/0)        |
| sandbox.rs     | 97.06% (33/34)  | 99.04% (206/208) | 98.89% (357/361) | - (0/0)    |
| server.rs      | 72.09% (31/43)  | 78.65% (350/445) | 83.03% (494/595) | - (0/0)    |
| tools/edit.rs  | 87.10% (27/31)  | 98.34% (237/241) | 95.50% (446/467) | - (0/0)    |
| tools/info.rs  | 92.86% (13/14)  | 98.80% (82/83)   | 96.45% (163/169) | - (0/0)    |
| tools/read.rs  | 87.50% (21/24)  | 98.22% (166/169) | 95.93% (283/295) | - (0/0)    |
| tools/search.rs| 95.12% (39/41)  | 98.52% (267/271) | 97.48% (581/596) | - (0/0)    |
| tools/write.rs | 93.75% (45/48)  | 94.17% (323/343) | 92.74% (626/675) | - (0/0)    |
| **Totals**     | 87.24% (212/243)| 90.99% (1646/1809)| 92.29% (2979/3228)| - (0/0)   |


## Architecture

```
src/
├── main.rs         # Axum server, CLI parsing, shutdown
├── lib.rs          # Module exports, constants
├── server.rs       # Tool handlers, MCP trait impl
├── sandbox.rs      # Path resolution and security
└── tools/
    ├── mod.rs      # Module exports
    ├── read.rs     # read_file, read_multiple_files
    ├── write.rs    # write_file, create_directory
    ├── edit.rs     # edit_file, move_file
    ├── search.rs   # search_files, list_directory
    └── info.rs     # get_file_info
tests/
└── integration_test.rs  # Comprehensive test suite
Dockerfile         # Multi-stage build
Makefile           # Build & test automation
```

## Security

- **Sandbox**: All paths resolved against configured roots only
- **Symlink blocking**: Traversal across symlinks blocked
- **Atomic writes**: File modifications are atomic via temporary files
- **Dry-run support**: `edit_file` with `dry_run=true` previews changes without modifying


## Binary Sizes

| Profile | Size |
|---------|------|
| Release | ~3.3 MB |
| Release MUSL | ~3.3 MB |

## License

Apache 2.0
