Skip to content

Commit df715f1

Browse files
authored
feat: implement mcp roots protocol support (#41)
* roots support * feat: handle roots from client * chore: better messaging when allowed_directory list is empty * chore: better messaging * update tests and cleanup * update docs * typo * clippy
1 parent 4408b30 commit df715f1

31 files changed

+612
-358
lines changed

Cargo.lock

Lines changed: 145 additions & 128 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[package]
22
name = "rust-mcp-filesystem"
33
version = "0.2.3"
4-
edition = "2021"
4+
edition = "2024"
55
repository = "https://github.com/rust-mcp-stack/rust-mcp-filesystem"
66
authors = ["Ali Hashemi"]
77
description = "Blazing-fast, asynchronous MCP server for seamless filesystem operations."
@@ -15,17 +15,17 @@ license = false
1515
eula = false
1616

1717
[dependencies]
18-
rust-mcp-sdk = { version = "0.6", default-features = false, features = [
18+
rust-mcp-sdk = {version="0.7", default-features = false, features = [
1919
"server",
2020
"macros",
21+
"stdio",
2122
"2025_06_18",
2223
] }
2324

2425
thiserror = { version = "2.0" }
2526
dirs = "6.0"
2627
glob = "0.3"
2728
walkdir = "2.5"
28-
derive_more = { version = "2.0", features = ["display", "from_str"] }
2929
similar = "=2.7"
3030
chrono = "0.4"
3131
clap = { version = "4.5", features = ["derive"] }

README.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
# Rust MCP Filesystem
66

7-
Rust MCP Filesystem is a blazingly fast, asynchronous, and lightweight MCP (Model Context Protocol) server designed for efficient handling of various filesystem operations.
7+
Rust MCP Filesystem is a blazingly fast, asynchronous, and lightweight MCP (Model Context Protocol) server designed for efficient handling of various filesystem operations.
88
This project is a pure Rust rewrite of the JavaScript-based `@modelcontextprotocol/server-filesystem`, offering enhanced capabilities, improved performance, and a robust feature set tailored for modern filesystem interactions.
99

1010
🚀 Refer to the [project documentation](https://rust-mcp-stack.github.io/rust-mcp-filesystem) for installation and configuration instructions.
@@ -14,8 +14,9 @@ This project is a pure Rust rewrite of the JavaScript-based `@modelcontextprotoc
1414
- **⚡ High Performance**: Built in Rust for speed and efficiency, leveraging asynchronous I/O to handle filesystem operations seamlessly.
1515
- **🔒 Read-Only by Default**: Starts with no write access, ensuring safety until explicitly configured otherwise.
1616
- **🔍 Advanced Glob Search**: Supports full glob pattern matching allowing precise filtering of files and directories using standard glob syntax.For example, patterns like `*.rs`, `src/**/*.txt`, and `logs/error-???.log` are valid and can be used to match specific file types, recursive directory searches, or patterned filenames.
17-
- **📁 Nested Directories**: Improved directory creation, allowing the creation of nested directories.
18-
- **📦 Lightweight**: Standalone with no external dependencies (e.g., no Node.js, Python etc required), compiled to a single binary with a minimal resource footprint, ideal for both lightweight and extensive deployment scenarios.
17+
- **🔄 MCP Roots support**: enabling clients to dynamically modify the list of allowed directories (disabled by default).
18+
- **📦 ZIP Archive Support**: Tools to create ZIP archives from files or directories and extract ZIP files with ease.
19+
- **🪶 Lightweight**: Standalone with no external dependencies (e.g., no Node.js, Python etc required), compiled to a single binary with a minimal resource footprint, ideal for both lightweight and extensive deployment scenarios.
1920

2021
#### 👉 Refer to [capabilities](https://rust-mcp-stack.github.io/rust-mcp-filesystem/#/capabilities) for a full list of tools and other capabilities.
2122

docs/README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Rust MCP Filesystem
22

3-
Rust MCP Filesystem is a blazingly fast, asynchronous, and lightweight MCP (Model Context Protocol) server designed for efficient handling of various filesystem operations.
3+
Rust MCP Filesystem is a blazingly fast, asynchronous, and lightweight MCP (Model Context Protocol) server designed for efficient handling of various filesystem operations.
44
This project is a pure Rust rewrite of the JavaScript-based **@modelcontextprotocol/server-filesystem**, offering enhanced capabilities, improved performance, and a robust feature set tailored for modern filesystem interactions.
55

66
Refer to the [quickstart](quickstart.md) guide for installation and configuration instructions.
@@ -9,7 +9,8 @@ Refer to the [quickstart](quickstart.md) guide for installation and configuratio
99

1010
- **⚡ High Performance**: Built in Rust for speed and efficiency, leveraging asynchronous I/O to handle filesystem operations seamlessly.
1111
- **🔒 Read-Only by Default**: Starts with no write access, ensuring safety until explicitly configured otherwise.
12-
- **🔍 Advanced Glob Search**: Full glob pattern matching for precise file and directory filtering (e.g., `*.rs`, `src/**/*.txt`, `logs/error-???.log`).
12+
- **🔍 Advanced Glob Search**: Supports full glob pattern matching allowing precise filtering of files and directories using standard glob syntax.For example, patterns like `*.rs`, `src/**/*.txt`, and `logs/error-???.log` are valid and can be used to match specific file types, recursive directory searches, or patterned filenames.
13+
- **🔄 MCP Roots support**: enabling clients to dynamically modify the list of allowed directories (disabled by default).
1314
- **📦 ZIP Archive Support**: Tools to create ZIP archives from files or directories and extract ZIP files with ease.
1415
- **🪶 Lightweight**: Standalone with no external dependencies (e.g., no Node.js, Python etc required), compiled to a single binary with a minimal resource footprint, ideal for both lightweight and extensive deployment scenarios.
1516

docs/_coverpage.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@
1414
1515
- 🪶 Lightweight
1616
- ⚡ High Performance
17-
- 🔒 Read-Only by Default
17+
- 🔒 Secure by design
18+
- 🔧 Packed with powerful tools
1819

1920
[GitHub](https://github.com/rust-mcp-stack/rust-mcp-filesystem)
2021
[⚙️ Capabilities](capabilities.md)

docs/guide/cli-command-options.md

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,23 @@
11
## CLI Command Options
22

33
```sh
4-
Usage: rust-mcp-filesystem [OPTIONS] <ALLOWED_DIRECTORIES>...
4+
Usage: rust-mcp-filesystem [OPTIONS] [ALLOWED_DIRECTORIES]...
55

66
Arguments:
7-
<ALLOWED_DIRECTORIES>...
7+
[ALLOWED_DIRECTORIES]...
88
Provide a space-separated list of directories that are permitted for the operation.
99
This list allows multiple directories to be provided.
1010

1111
Example: rust-mcp-filesystem /path/to/dir1 /path/to/dir2 /path/to/dir3
1212

1313
Options:
1414
-w, --allow-write
15-
Enables read/write mode for the app, allowing both reading and writing.
15+
Enables read/write mode for the app, allowing both reading and writing. Defaults to disabled.
16+
17+
-t, --enable-roots
18+
Enables dynamic directory access control via Roots from the MCP client side. Defaults to disabled.
19+
When enabled, MCP clients that support Roots can dynamically update the allowed directories.
20+
Any directories provided by the client will completely replace the initially configured allowed directories on the server.
1621

1722
-h, --help
1823
Print help (see a summary with '-h')

src/cli.rs

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,40 @@
1-
use clap::{arg, command, Parser};
1+
use clap::{Parser, arg, command};
22

33
#[derive(Parser, Debug)]
44
#[command(name = env!("CARGO_PKG_NAME"))]
55
#[command(version = env!("CARGO_PKG_VERSION"))]
6-
#[command(about = "A lightning-fast, asynchronous, and lightweight MCP server designed for efficient handling of various filesystem operations",
6+
#[command(about = "A lightning-fast, asynchronous, and lightweight MCP server designed for efficient handling of various filesystem operations",
77
long_about = None)]
88
pub struct CommandArguments {
99
#[arg(
1010
short = 'w',
1111
long,
12-
help = "Enables read/write mode for the app, allowing both reading and writing."
12+
help = "Enables read/write mode for the app, allowing both reading and writing. Defaults to disabled."
1313
)]
1414
pub allow_write: bool,
1515
#[arg(
16-
help = "List of directories that are permitted for the operation.",
16+
help = "List of directories that are permitted for the operation. It is required when 'enable-roots' is not provided OR client does not support Roots.",
1717
long_help = concat!("Provide a space-separated list of directories that are permitted for the operation.\nThis list allows multiple directories to be provided.\n\nExample: ", env!("CARGO_PKG_NAME"), " /path/to/dir1 /path/to/dir2 /path/to/dir3"),
18-
required = true
18+
required = false
1919
)]
2020
pub allowed_directories: Vec<String>,
21+
22+
#[arg(
23+
short = 't',
24+
long,
25+
help = "Enables dynamic directory access control via Roots from the MCP client side. Defaults to disabled.\nWhen enabled, MCP clients that support Roots can dynamically update the allowed directories.\nAny directories provided by the client will completely replace the initially configured allowed directories on the server."
26+
)]
27+
pub enable_roots: bool,
28+
}
29+
30+
impl CommandArguments {
31+
pub fn validate(&self) -> Result<(), String> {
32+
if !self.enable_roots && self.allowed_directories.is_empty() {
33+
return Err(format!(
34+
" <ALLOWED_DIRECTORIES> is required when `--enable-roots` is not provided.\n Run `{} --help` to view the usage instructions.",
35+
env!("CARGO_PKG_NAME")
36+
));
37+
}
38+
Ok(())
39+
}
2140
}

src/error.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use async_zip::error::ZipError;
22
use glob::PatternError;
3-
use rust_mcp_sdk::schema::{schema_utils::SdkError, RpcError};
4-
use rust_mcp_sdk::{error::McpSdkError, TransportError};
3+
use rust_mcp_sdk::schema::{RpcError, schema_utils::SdkError};
4+
use rust_mcp_sdk::{TransportError, error::McpSdkError};
55

66
use thiserror::Error;
77
use tokio::io;
@@ -10,7 +10,9 @@ pub type ServiceResult<T> = core::result::Result<T, ServiceError>;
1010

1111
#[derive(Debug, Error)]
1212
pub enum ServiceError {
13-
#[error("Service is running in read-only mode. To enable write access, please run with the --allow-write flag.")]
13+
#[error(
14+
"Service is running in read-only mode. To enable write access, please run with the --allow-write flag."
15+
)]
1416
NoWriteAccess,
1517
#[error("{0}")]
1618
FromString(String),

0 commit comments

Comments
 (0)