Skip to content

File Operations

Read the contents of a file. Supports reading specific line ranges.

ParameterTypeRequiredDescription
pathstringYesPath to the file (relative to working directory)
offsetintegerNoLine number to start reading from (0-based)
limitintegerNoMaximum number of lines to read

Reading a file with a line range:

{
"path": "src/main.rs",
"offset": 10,
"limit": 20
}

This reads lines 11-30 of src/main.rs.


Create or overwrite a file. Automatically creates parent directories if they do not exist.

ParameterTypeRequiredDescription
pathstringYesPath to the file
contentstringYesContent to write
{
"path": "src/utils.rs",
"content": "pub fn add(a: i32, b: i32) -> i32 {\n a + b\n}\n"
}

Edit a file by replacing an exact string match. The old_string must match exactly once in the file.

ParameterTypeRequiredDescription
pathstringYesPath to the file
old_stringstringYesExact text to find (must be unique in the file)
new_stringstringYesReplacement text
{
"path": "src/main.rs",
"old_string": "fn main() {\n println!(\"Hello\");\n}",
"new_string": "fn main() {\n println!(\"Hello, world!\");\n}"
}

If old_string matches multiple locations or is not found, the edit fails with an error.


Apply a unified diff patch. Supports Claude Code-style patch format with fuzzy matching for context lines.

*** Begin Patch
*** Add File: path/to/new_file.rs
+line 1
+line 2
*** Update File: path/to/existing.rs
context line
-old line
+new line
context line
*** Delete File: path/to/old_file.rs
*** End Patch
SectionDescription
*** Add FileCreate a new file with the specified content
*** Update FileModify an existing file using diff hunks
*** Delete FileRemove a file

When applying updates, the patch tool uses fuzzy matching for context lines. If the exact context is not found, it searches within a 3-line window to find the best match. This makes patches more resilient to minor whitespace or formatting differences.

*** Begin Patch
*** Update File: src/lib.rs
use std::io;
-pub fn read_input() -> String {
+pub fn read_input() -> Result<String, io::Error> {
let mut input = String::new();
- std::io::stdin().read_line(&mut input).unwrap();
- input
+ std::io::stdin().read_line(&mut input)?;
+ Ok(input)
}
*** End Patch

All file tools use resolve_path() to enforce path sandboxing:

  • Paths are canonicalized, resolving symlinks and .. components.
  • Any path that escapes the working directory is rejected.
  • TOCTOU hardening: The implementation avoids checking path.exists() before canonicalize() to prevent symlink race conditions. Pre-write verification (verify_not_escaping_symlink()) runs before file creation, and post-write re-verification (verify_no_symlink_escape()) runs after writes to guard against symlink attacks.