Skip to main content

FileSystem

Struct FileSystem 

Source
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

Source

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);
Source

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"));
Source

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 {}");
Source

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"));
Source

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);
Source

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);
Source

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);
Source

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);
Source

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);
Source

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());
Source

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_path does 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

Source§

fn clone(&self) -> FileSystem

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for FileSystem

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for FileSystem

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> DynClone for T
where T: Clone,

Source§

fn __clone_box(&self, _: Private) -> *mut ()

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more