pub struct FileSystem { /* private fields */ }Expand description
An in-memory virtual filesystem for MCP tool definitions.
FileSystem provides a read-only filesystem structure that stores generated
TypeScript files in memory. Files are organized in a hierarchical structure
like /mcp-tools/servers/<server-id>/....
§Thread Safety
This type is Send and Sync, making it safe to use across threads.
§Examples
use mcp_execution_files::FileSystem;
let mut vfs = FileSystem::new();
vfs.add_file("/mcp-tools/manifest.json", "{}").unwrap();
assert!(vfs.exists("/mcp-tools/manifest.json"));
assert_eq!(vfs.file_count(), 1);Implementations§
Source§impl FileSystem
impl FileSystem
Sourcepub fn new() -> Self
pub fn new() -> Self
Creates a new empty virtual filesystem.
§Examples
use mcp_execution_files::FileSystem;
let vfs = FileSystem::new();
assert_eq!(vfs.file_count(), 0);Sourcepub fn add_file(
&mut self,
path: impl AsRef<Path>,
content: impl Into<String>,
) -> Result<()>
pub fn add_file( &mut self, path: impl AsRef<Path>, content: impl Into<String>, ) -> Result<()>
Adds a file to the virtual filesystem.
If a file already exists at the path, it will be replaced.
§Errors
Returns an error if the path is invalid (not absolute, contains ‘..’, etc.).
§Examples
use mcp_execution_files::FileSystem;
let mut vfs = FileSystem::new();
vfs.add_file("/mcp-tools/test.ts", "console.log('hello');").unwrap();
assert!(vfs.exists("/mcp-tools/test.ts"));Sourcepub fn read_file(&self, path: impl AsRef<Path>) -> Result<&str>
pub fn read_file(&self, path: impl AsRef<Path>) -> Result<&str>
Reads the content of a file.
§Errors
Returns FilesError::FileNotFound if the file does not exist.
Returns FilesError::InvalidPath if the path is invalid.
§Examples
use mcp_execution_files::FileSystem;
let mut vfs = FileSystem::new();
vfs.add_file("/test.ts", "export {}").unwrap();
let content = vfs.read_file("/test.ts").unwrap();
assert_eq!(content, "export {}");Sourcepub fn exists(&self, path: impl AsRef<Path>) -> bool
pub fn exists(&self, path: impl AsRef<Path>) -> bool
Checks if a file exists at the given path.
Returns false if the path is invalid.
§Examples
use mcp_execution_files::FileSystem;
let mut vfs = FileSystem::new();
vfs.add_file("/exists.ts", "").unwrap();
assert!(vfs.exists("/exists.ts"));
assert!(!vfs.exists("/missing.ts"));Sourcepub fn list_dir(&self, path: impl AsRef<Path>) -> Result<Vec<FilePath>>
pub fn list_dir(&self, path: impl AsRef<Path>) -> Result<Vec<FilePath>>
Lists all files and directories in a directory.
Returns an empty vector if the directory is empty or does not exist.
§Errors
Returns FilesError::InvalidPath if the path is invalid.
Returns FilesError::NotADirectory if the path points to a file.
§Examples
use mcp_execution_files::FileSystem;
let mut vfs = FileSystem::new();
vfs.add_file("/mcp-tools/servers/test1.ts", "").unwrap();
vfs.add_file("/mcp-tools/servers/test2.ts", "").unwrap();
let entries = vfs.list_dir("/mcp-tools/servers").unwrap();
assert_eq!(entries.len(), 2);Sourcepub fn file_count(&self) -> usize
pub fn file_count(&self) -> usize
Returns the total number of files in the VFS.
§Examples
use mcp_execution_files::FileSystem;
let mut vfs = FileSystem::new();
assert_eq!(vfs.file_count(), 0);
vfs.add_file("/test1.ts", "").unwrap();
vfs.add_file("/test2.ts", "").unwrap();
assert_eq!(vfs.file_count(), 2);Sourcepub fn all_paths(&self) -> Vec<&FilePath>
pub fn all_paths(&self) -> Vec<&FilePath>
Returns all file paths in the VFS.
The paths are returned in sorted order.
§Examples
use mcp_execution_files::FileSystem;
let mut vfs = FileSystem::new();
vfs.add_file("/a.ts", "").unwrap();
vfs.add_file("/b.ts", "").unwrap();
let paths = vfs.all_paths();
assert_eq!(paths.len(), 2);Sourcepub fn files(&self) -> impl Iterator<Item = (&FilePath, &FileEntry)>
pub fn files(&self) -> impl Iterator<Item = (&FilePath, &FileEntry)>
Returns an iterator over all files in the VFS.
Each item is a tuple of (&FilePath, &FileEntry).
§Examples
use mcp_execution_files::FileSystem;
let mut vfs = FileSystem::new();
vfs.add_file("/a.ts", "content a").unwrap();
vfs.add_file("/b.ts", "content b").unwrap();
let files: Vec<_> = vfs.files().collect();
assert_eq!(files.len(), 2);Sourcepub fn clear(&mut self)
pub fn clear(&mut self)
Removes all files from the VFS.
§Examples
use mcp_execution_files::FileSystem;
let mut vfs = FileSystem::new();
vfs.add_file("/test.ts", "").unwrap();
assert_eq!(vfs.file_count(), 1);
vfs.clear();
assert_eq!(vfs.file_count(), 0);Sourcepub fn export_to_filesystem(&self, base_path: impl AsRef<Path>) -> Result<()>
pub fn export_to_filesystem(&self, base_path: impl AsRef<Path>) -> Result<()>
Exports VFS contents to real filesystem.
This is a high-performance implementation optimized for the progressive loading pattern. It pre-creates all directories and writes files sequentially.
§Performance
Target: <50ms for 30 files (GitHub server typical case)
Optimizations:
- Single pass directory creation
- Cached canonicalized base path
- Minimal allocations
§Errors
Returns error if:
- Base path doesn’t exist or isn’t a directory
- Permission denied
- I/O error during write
§Examples
use mcp_execution_files::FilesBuilder;
let vfs = FilesBuilder::new()
.add_file("/manifest.json", "{}")
.build()
.unwrap();
vfs.export_to_filesystem(base).unwrap();
assert!(base.join("manifest.json").exists());Sourcepub fn export_to_filesystem_with_options(
&self,
base_path: impl AsRef<Path>,
options: &ExportOptions,
) -> Result<()>
pub fn export_to_filesystem_with_options( &self, base_path: impl AsRef<Path>, options: &ExportOptions, ) -> Result<()>
Exports VFS contents with custom options.
The export is staged in a temporary sibling directory next to
base_path and published atomically: only once every file has been
written to the staging directory is it renamed into place. If the
process is interrupted at any point before publishing, base_path is
left exactly as it was — either untouched or, if it did not exist yet,
still absent. See the module-level docs for details.
Concurrent exports of the same base_path from different processes
are not locked against each other and can still race on the final
swap — one export’s result may be silently overwritten by another’s
(a lost update). The age-gated sweep of orphaned staging/displaced
directories (sweep_stale_artifacts) guarantees neither export’s
staging/displaced directories can be deleted out from under it before
its own rollback path runs, so this can no longer result in the
target, its staging directory, and its displaced backup all being
lost at once. Callers that need stronger-than-last-write-wins
semantics for the same target should serialize writes themselves
(e.g. a per-target lock) — see mcp-execution-server’s
introspector_for for the pattern this project already uses for a
similar problem. Concurrent exports of different targets sharing a
parent directory are safe.
§Errors
Returns an error if:
- The parent directory of
base_pathdoes not exist - The staging directory cannot be created or canonicalized
- I/O operations fail during directory creation, file writing, or the final publish step
§Examples
use mcp_execution_files::{FilesBuilder, ExportOptions};
let vfs = FilesBuilder::new()
.add_file("/test.ts", "export {}")
.build()
.unwrap();
let options = ExportOptions::default().with_atomic_writes(false);
vfs.export_to_filesystem_with_options(base, &options).unwrap();Trait Implementations§
Source§impl Clone for FileSystem
impl Clone for FileSystem
Source§fn clone(&self) -> FileSystem
fn clone(&self) -> FileSystem
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read more