filesystem
Filesystem
All file and directory operations use Claude Code's built-in tools. No MCP server needed — native tools are faster, more capable, and cost zero context tokens when idle.
Quick Reference
| Filesystem MCP Tool | Replacement | Notes |
|---|---|---|
read_file(path) |
Read tool |
Supports line offset and limit |
read_multiple_files(paths) |
Multiple parallel Read calls |
Faster than sequential MCP calls |
write_file(path, content) |
Write tool |
Overwrites entire file |
edit_file(path, edits) |
Edit tool |
Exact string replacement; surgical edits |
list_directory(path) |
Glob or Bash ls |
Glob for patterns, ls for simple listing |
directory_tree(path) |
Bash fd or Glob **/* |
fd is fastest; Glob for pattern filtering |
search_files(pattern, path) |
Grep tool |
Full regex, file type filters, context lines |
create_directory(path) |
Bash mkdir -p |
-p creates intermediate directories |
move_file(src, dst) |
Bash mv |
Also handles renames |
get_file_info(path) |
Bash stat or Bash ls -la |
Size, permissions, timestamps |
list_allowed_directories |
N/A | Claude Code operates in the working directory; no sandbox restrictions |
Reading Files
Read a Single File
Use the Read tool with an absolute path:
Read: /path/to/file.py
For large files, use offset and limit to read specific sections:
Read: /path/to/file.py (offset: 100, limit: 50)
This reads 50 lines starting from line 100. Use this for files with thousands of lines to avoid flooding context.
Read Multiple Files in Parallel
Issue multiple Read calls in a single response. Claude Code executes them concurrently:
Read: /path/to/file1.py
Read: /path/to/file2.py
Read: /path/to/file3.py
Parallel reads are faster than the MCP's read_multiple_files which serialized internally.
Read Images and PDFs
The Read tool handles binary formats:
- Images (PNG, JPG, SVG): displayed visually
- PDFs: extracted text; use
pages: "1-5"for large documents (max 20 pages per call)
Writing and Editing Files
Write a New File
Use the Write tool to create a file or overwrite an existing one:
Write: /path/to/new-file.py
Content: <full file content>
The Write tool requires reading the file first if it already exists. For new files,
write directly.
Edit an Existing File
Use the Edit tool for surgical modifications — replace exact string matches:
Edit: /path/to/file.py
old_string: "def old_function():"
new_string: "def new_function():"
The Edit tool fails if old_string is not unique in the file. Provide enough
surrounding context to make the match unique, or use replace_all: true for
find-and-replace across the entire file.
Prefer Edit over Write for existing files. Edit preserves everything outside the changed region and shows a clear diff. Write replaces the entire file.
Finding Files
By Name Pattern (Glob)
Glob: **/*.py → all Python files recursively
Glob: src/**/*.ts → TypeScript files under src/
Glob: *.md → Markdown files in current directory
Glob: **/test_*.py → test files anywhere in the tree
Results are sorted by modification time (most recent first).
By Content (Grep)
Grep: pattern="def process_data" type="py"
Grep: pattern="TODO|FIXME" glob="*.py"
Grep: pattern="class.*Controller" output_mode="content" -C=2
| Grep Parameter | Purpose |
|---|---|
pattern |
Regex pattern to match |
type |
File type filter (py, js, ts, rust, go, etc.) |
glob |
Glob pattern filter (*.tsx, src/**/*.py) |
output_mode |
files_with_matches (default), content, count |
-C, -A, -B |
Context lines: around, after, before matches |
-i |
Case-insensitive search |
Directory Listing
Simple listing:
ls -la /path/to/directory
Recursive tree with fd:
fd . /path/to/directory --type f
Tree with depth limit:
fd . /path/to/directory --type f --max-depth 2
Filter by extension:
fd -e py /path/to/directory
File Operations
Create Directory
mkdir -p /path/to/new/directory
The -p flag creates all intermediate directories. Always verify the parent path
exists first with ls.
Move / Rename
mv /path/to/source.py /path/to/destination.py
Rename a file (same directory):
mv /path/to/old-name.py /path/to/new-name.py
Move a directory:
mv /path/to/source-dir /path/to/destination-dir
Copy
cp /path/to/source.py /path/to/destination.py
cp -r /path/to/source-dir /path/to/destination-dir
Delete
rm /path/to/file.py
rm -r /path/to/directory
Always confirm with the user before deleting files or directories.
File Metadata
stat /path/to/file.py
ls -la /path/to/file.py
wc -l /path/to/file.py
| Command | Returns |
|---|---|
stat |
Size, permissions, timestamps, inode |
ls -la |
Permissions, owner, size, modification date |
wc -l |
Line count |
file |
MIME type detection |
Common Workflows
Find and Replace Across Files
# Find all files containing the old string
Grep: pattern="old_function_name" type="py" output_mode="files_with_matches"
# Then Edit each file
Edit: /path/to/file1.py (old_string → new_string, replace_all: true)
Edit: /path/to/file2.py (old_string → new_string, replace_all: true)
Explore an Unfamiliar Codebase
- Check project structure:
fd . --type f --max-depth 2 - Read configuration:
Read: package.jsonorRead: pyproject.toml - Find entry points:
Grep: pattern="def main|if __name__" type="py" - Read key files identified above
Find Large Files
fd --type f --exec stat -f '%z %N' {} \; | sort -rn | head -20
Error Handling
| Error | Cause | Resolution |
|---|---|---|
| Read: file not found | Path incorrect or file deleted | Verify with ls or Glob |
| Edit: old_string not unique | Multiple matches in the file | Add more surrounding context to make it unique |
| Edit: old_string not found | Content changed since last read | Re-read the file, then retry with current content |
| Write: file not read first | Attempting to overwrite without reading | Read the file first, then Write |
| Permission denied | Insufficient OS permissions | Check with ls -la; use chmod if appropriate |
| Glob: no files found | Pattern too restrictive | Broaden the pattern; check path spelling |
Limitations
- Read returns up to 2000 lines by default. Use offset/limit for larger files.
- Read truncates lines longer than 2000 characters.
- Edit requires exact string matching — whitespace and indentation must match precisely.
- Write overwrites the entire file. No append mode. To append, read first, then write the combined content.
- Glob only matches files, not directories. Use
Bash lsorfdto list directories. - PDF reading is limited to 20 pages per call. Specify page ranges for large documents.
Calibration Rules
- Read before Edit. Always read a file before editing it. The Edit tool enforces this.
- Edit over Write for existing files. Edit is surgical and shows diffs. Write is a full replacement — use it only for new files or complete rewrites.
- Glob over Bash for file search. Glob is optimized for pattern matching. Only fall
back to
fdorfindfor queries Glob cannot express (size filters, date filters). - Grep over Bash for content search. Grep is optimized for ripgrep-based search with
proper permissions. Never use
greporrgvia Bash. - Parallel reads for multiple files. Issue all Read calls in a single response for concurrent execution.
- Always use absolute paths. Claude Code tools require absolute paths. Never pass relative paths to Read, Write, or Edit.