-
Notifications
You must be signed in to change notification settings - Fork 615
[Feature Request]: Sample MCP Server - Rust Implementation ("filesystem-server")Β #266
Description
π§ Epic
Title: Sample MCP Server β Rust Implementation (βfilesystem-serverβ)
Goal
Ship a self-contained, memory-safe Rust (Axum) MCP server that exposes a comprehensive file-system toolkit.
It illustrates:
- zero-unsafe Rust, fully clippy-clean
- MUSL-linked static binaries (~ 4 MB)
- scratch-based multi-arch Docker images (< 10 MB)
- pattern-matching edit engine with dry-run diffs
- a turnkey Helm chart for Kubernetes rollout
Repository root: mcp-servers/rust/filesystem-server
π§ Type of Feature
- Developer tooling / sample code
- Language-SDK showcase
π Tool Catalogue
| 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 |
Fails if destination 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. |
πββοΈ User Story 1 β Cargo Quick-Start
As a Rust developer
I want to run cargo run -- --roots /tmp,/var/www
So that I get an MCP endpoint on 0.0.0.0:8084 sandboxed to those roots.
β Acceptance Criteria
Scenario: Start filesystem-server via cargo run
Given Rust β₯1.77 and target x86_64-unknown-linux-musl installed
When I execute "cargo run -- --roots /tmp,/var/www"
Then GET /version returns JSON containing "filesystem-server"
And tools/list includes read_file, edit_file, list_directoryπββοΈ User Story 2 β Static Scratch Docker Image
As a platform engineer
I want docker build . to produce an image β€ 10 MB
So that deployments start fast and have minimal CVE surface.
β Acceptance Criteria
Scenario: Build static image
When I run "docker build -t filesystem-server:dev ."
Then image size β€ 10 MB
And "docker run -p 8080:8080 filesystem-server:dev --roots /tmp --transport=http"
responds 200 to POST tools/listπββοΈ User Story 3 β Helm Deployment
As a Kubernetes operator
I want a Helm chart with probes, resource limits, and configurable roots
So that I can roll out the server via helm install.
β Acceptance Criteria
Scenario: Install via Helm
Given a KinD cluster is running
When I execute "helm install fs mcp-servers/rust/filesystem-server/charts/filesystem-server \
--set roots={/workspaces,/data}"
Then Deployment "fs-filesystem-server" becomes Ready
And GET /health on the service returns {"status":"healthy"}πββοΈ User Story 4 β Safe Edit with Dry-Run
As a cautious LLM agent
I want to call edit_file with dryRun=true first
So that I can inspect the git-style diff before applying changes.
β Acceptance Criteria
Scenario: Dry-run edit returns diff
Given file /tmp/demo.txt contains "hello world"
When I POST tools/call edit_file {path:"/tmp/demo.txt", edits:[{oldText:"world",newText:"MCP"}], dryRun:true}
Then result.diff contains "-hello world" and "+hello MCP"
And the underlying file is unchanged
When I repeat the call with dryRun:false
Then /tmp/demo.txt now contains "hello MCP"π Filesystem Layout
filesystem-server/
βββ Cargo.toml
βββ Dockerfile
βββ README.md
βββ src/
βββ main.rs # Axum setup, CLI flags
βββ rpc.rs # JSON-RPC dispatcher
βββ sandbox.rs # Path-safety & root confinement
βββ tools/
β βββ mod.rs
β βββ read.rs
β βββ write.rs
β βββ edit.rs
β βββ search.rs
β βββ info.rs
βββ middleware/
βββ auth.rs # Optional Bearer token
βββ logging.rs
π Component Matrix
| Component / Path | Status | Purpose |
|---|---|---|
src/main.rs |
NEW | Axum app, graceful shutdown, flag parsing (roots, transport, auth-token) |
src/sandbox.rs |
NEW | Resolves & validates paths against allowed roots |
src/tools/*.rs |
NEW | Implement each file tool with async tokio::fs APIs |
Dockerfile |
NEW | MUSL static build β scratch image |
.github/workflows/rust.yml |
NEW | clippy, tests, cargo audit |
charts/filesystem-server |
NEW | Helm chart |
Makefile / justfile |
NEW | build, test, docker helpers |
README.md |
NEW | Quick-start, curl samples, security notes |
π Global Acceptance Checklist
- All four user-story scenarios pass.
- CI green (
cargo clippy -D warnings, unit tests, coverage β₯ 90 %,cargo audit). - Docker image β€ 10 MB for amd64 & arm64.
- Helm chart deploys with custom
rootsand passes readiness / liveness probes. - Auth middleware blocks unauthenticated requests when enabled.
- Image published to
ghcr.io/mcp-gateway-labs; chart committed undercharts/.
π Roll-Out Plan
- Scaffold repo
mcp-servers/rust/filesystem-serverwith layout above. - Implement sandbox module +
read_file,list_directory, health/version. - Add remaining tools (
write,edit,search,info,move,create_directory). - Add optional Bearer-token middleware; integrate SSE transport if time permits.
- Wire CI, Docker, Helm; verify acceptance tests.
- Tag v0.1.0 and attach to Release 0.9.0 milestone.