filesystem-mcp
Filesystem MCP Server
Secure filesystem MCP server for reading, writing, searching, diffing, and patching files.
Table of Contents
MCP Surface — Tools · Resources · Prompts
Configuration — HTTP & Auth · File Size Limits · Access Control · Output & Inline Limits · Tasks · Logging & Diagnostics · Performance
Related MCP server: Filesys
Overview
A secure, production-ready Model Context Protocol server that gives AI assistants controlled access to the local filesystem. All operations are sandboxed to explicitly allowed directories with path traversal prevention, sensitive file blocking, and optional Bearer token authentication.
Supports stdio (default) and Node Streamable HTTP transport. HTTP sessions are implemented with isolated per-session server state. The HTTP transport is stateful by default and currently non-resumable; it does not persist an event store for Last-Event-ID replay.
Key Features
18 filesystem tools — read, write, search, diff, patch, hash, and bulk operations with structured output schemas
Security-first — path validation, symlink escape prevention, sensitive file denylist, localhost-only CORS, Host header validation for loopback HTTP binds, optional API key auth
Dual transport — stdio for local use, Node Streamable HTTP for networked/multi-session deployments
Structured output — all tools return typed
outputSchema/structuredContentfor reliable LLM parsingSelf-documenting — 6 built-in resources (
internal://instructions,internal://tool-catalog, etc.) and 4 built-in prompts (get-help,compare-files,analyze-path,get-tool-help)
Requirements
Node.js >= 24
Quick Start
{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": ["-y", "@j0hanz/filesystem-mcp@latest"]
}
}
}Docker
docker run -i --rm -v /path/to/project:/workspace:ro ghcr.io/j0hanz/filesystem-mcp /workspaceOr using Docker Compose:
services:
filesystem-mcp:
build: .
stdin_open: true
volumes:
- ./:/projects/workspace:ro
command: ['/projects/workspace']CLI Usage
filesystem-mcp [options] [allowedDirs...]
Arguments:
allowedDirs Directories the server can access
Options:
--allow-cwd Allow the current working directory as an additional root
--port <number> Enable HTTP transport on the given port
-v, --version Display server version
-h, --help Display help
Examples:
$ npx @j0hanz/filesystem-mcp@latest /path/to/project
$ npx @j0hanz/filesystem-mcp@latest --allow-cwd
$ npx @j0hanz/filesystem-mcp@latest --port 3000 /path/to/projectClient Configuration
Add to .vscode/mcp.json:
{
"servers": {
"filesystem": {
"command": "npx",
"args": ["-y", "@j0hanz/filesystem-mcp@latest"]
}
}
}Or install via CLI:
code --add-mcp '{"name":"filesystem","command":"npx","args":["-y","@j0hanz/filesystem-mcp@latest"]}'Add to .vscode/mcp.json:
{
"servers": {
"filesystem": {
"command": "npx",
"args": ["-y", "@j0hanz/filesystem-mcp@latest"]
}
}
}Or install via CLI:
code-insiders --add-mcp '{"name":"filesystem","command":"npx","args":["-y","@j0hanz/filesystem-mcp@latest"]}'Add to ~/.cursor/mcp.json:
{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": ["-y", "@j0hanz/filesystem-mcp@latest"]
}
}
}Add to <SOLUTIONDIR>.mcp.json or %USERPROFILE%\.mcp.json:
{
"servers": {
"filesystem": {
"command": "npx",
"args": ["-y", "@j0hanz/filesystem-mcp@latest"]
}
}
}Add to ~/.config/goose/config.yaml:
extensions:
filesystem:
name: Filesystem MCP
cmd: npx
args:
- -y
- '@j0hanz/filesystem-mcp@latest'
enabled: true
type: stdio{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": ["-y", "@j0hanz/filesystem-mcp@latest"]
}
}
}Add to claude_desktop_config.json:
{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": ["-y", "@j0hanz/filesystem-mcp@latest"]
}
}
}claude mcp add filesystem-mcp -- npx -y @j0hanz/filesystem-mcp@latestOr add a project-scoped .mcp.json:
{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": ["-y", "@j0hanz/filesystem-mcp@latest"]
}
}
}Add to ~/.codeium/windsurf/mcp_config.json:
{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": ["-y", "@j0hanz/filesystem-mcp@latest"]
}
}
}amp mcp add filesystem-mcp -- npx -y @j0hanz/filesystem-mcp@latestOr add to settings.json:
{
"amp.mcpServers": {
"filesystem": {
"command": "npx",
"args": ["-y", "@j0hanz/filesystem-mcp@latest"]
}
}
}Add to cline_mcp_settings.json:
{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": ["-y", "@j0hanz/filesystem-mcp@latest"]
}
}
}codex mcp add filesystem -- npx -y @j0hanz/filesystem-mcp@latestOr add to ~/.codex/config.toml (or .codex/config.toml in a trusted project):
[mcp_servers.filesystem]
command = "npx"
args = ["-y", "@j0hanz/filesystem-mcp@latest"]Add this JSON in your repository's GitHub Copilot coding agent MCP configuration:
{
"mcpServers": {
"filesystem": {
"type": "local",
"command": "npx",
"args": ["-y", "@j0hanz/filesystem-mcp@latest"],
"tools": ["*"]
}
}
}{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": ["-y", "@j0hanz/filesystem-mcp@latest"]
}
}
}Add to .kiro/settings/mcp.json:
{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": ["-y", "@j0hanz/filesystem-mcp@latest"]
}
}
}Add to ~/.gemini/settings.json:
{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": ["-y", "@j0hanz/filesystem-mcp@latest"]
}
}
}Add to ~/.config/zed/settings.json:
{
"context_servers": {
"filesystem": {
"command": "npx",
"args": ["-y", "@j0hanz/filesystem-mcp@latest"],
"env": {}
}
}
}Add to VS Code settings.json under augment.advanced:
{
"augment.advanced": {
"mcpServers": [
{
"id": "filesystem",
"command": "npx",
"args": ["-y", "@j0hanz/filesystem-mcp@latest"]
}
]
}
}{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": ["-y", "@j0hanz/filesystem-mcp@latest"]
}
}
}{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": ["-y", "@j0hanz/filesystem-mcp@latest"]
}
}
}Use Cases
Explore and Understand a Codebase
Discover project structure and navigate unfamiliar repositories. Start with roots to see allowed directories, use tree for an overview, find to locate files by pattern, and read or read_many to inspect contents.
Relevant tools: roots, ls, find, tree, read, read_many, stat
Search Across Files
Locate specific code patterns, function definitions, or configuration values across a project. Use grep for content search with regex support and find for file name matching.
Edit and Refactor Code
Make precise, targeted edits to source files. Use edit for surgical replacements with dry-run preview, or search_and_replace for bulk changes across multiple files matching a glob pattern.
Relevant tools: edit, search_and_replace, write
Diff and Patch Workflow
Compare file versions and apply patches. Generate a unified diff with diff_files, preview with apply_patch(dryRun: true), then apply. Supports both single-file and multi-file patches (best-effort per file with per-file results[]).
Relevant tools: diff_files, apply_patch
File Management
Create directories, move/rename files, delete files, and verify file integrity via SHA-256 hashing.
Relevant tools: mkdir, mv, rm, calculate_hash, write
Architecture
[MCP Client]
|
| Transport: stdio (default) or Node Streamable HTTP (--port)
v
[MCP Server: filesystem-mcp]
| Entry: src/index.ts -> src/server/bootstrap.ts
|
+-- initialize / initialized
|
+-- tools/call ──────────────────────────────────────────
| +-- [roots] — List allowed workspace roots
| +-- [ls] — List directory contents
| +-- [find] — Find files by glob
| +-- [tree] — Render directory tree
| +-- [read] — Read file contents
| +-- [read_many] — Read multiple files
| +-- [stat] — Get file metadata
| +-- [stat_many] — Get multiple file metadata
| +-- [grep] — Search file contents
| +-- [mkdir] — Create directory
| +-- [write] — Write file
| +-- [edit] — Edit file (string replacements)
| +-- [mv] — Move/rename file
| +-- [rm] — Delete file
| +-- [calculate_hash] — SHA-256 hash
| +-- [diff_files] — Unified diff
| +-- [apply_patch] — Apply unified patch
| +-- [search_and_replace]— Bulk search & replace
|
+-- resources/read ──────────────────────────────────────
| +-- internal://instructions
| +-- internal://tool-catalog
| +-- internal://workflows
| +-- internal://tool-info/{name}
| +-- filesystem-mcp://result/{id}
| +-- filesystem-mcp://metrics
|
+-- prompts/get ─────────────────────────────────────────
| +-- get-help (optional topic argument)
| +-- compare-files (original, modified)
| +-- analyze-path (path)
| +-- get-tool-help (name)
|
+-- Capabilities: logging, resources, tools, prompts, completions, tasksRequest Lifecycle
[Client] -- initialize {protocolVersion, capabilities} --> [Server]
[Server] -- {protocolVersion, capabilities, serverInfo} --> [Client]
[Client] -- notifications/initialized --> [Server]
[Client] -- tools/call {name, arguments} --> [Server]
[Server] -- validate(inputSchema) --> [Handler]
[Handler] -- {content: [{type, text}], structuredContent?, isError?} --> [Client]MCP Surface
Tools
roots · ls · find · tree · read · read_many · stat · stat_many · grep · mkdir · write · edit · mv · rm · calculate_hash · diff_files · apply_patch · search_and_replace
roots
List allowed workspace roots. Call first — all other tools are scoped to these directories.
No parameters.
ls
List immediate directory contents: name, path, type, size, modified date.
Parameter | Type | Required | Description |
| string | no | Base directory (default: root) |
| boolean | no | Include dotfiles. Default: |
| boolean | no | Include ignored items (node_modules, .git). Default: |
| integer | no | Max recursion depth (1-50) when pattern is provided |
| integer | no | Max entries before truncation. Default: 20000, Max: 20000 |
| enum | no |
|
| string | no | Relative glob filter (e.g. |
| boolean | no | Resolve symlink targets. Default: |
| string | no | Pagination cursor from a previous response |
find
Find files by glob pattern. Returns matching files with metadata.
Parameter | Type | Required | Description |
| string | no | Base directory (default: root) |
| string | yes | Relative glob pattern (e.g. |
| integer | no | Max results (1-10000). Default: 100 |
| boolean | no | Include ignored items. Default: |
| boolean | no | Include dotfiles. Default: |
| enum | no |
|
| integer | no | Max directory depth (0-100) |
| string | no | Pagination cursor |
tree
Render a directory tree with bounded recursion. Returns ASCII tree + structured JSON.
Parameter | Type | Required | Description |
| string | no | Base directory (default: root) |
| integer | no | Depth (0 = root node only). Default: 5, Max: 50 |
| integer | no | Max entries. Default: 1000, Max: 20000 |
| boolean | no | Include dotfiles. Default: |
| boolean | no | Include ignored items. Default: |
| boolean | no | Include file sizes in tree entries. Default: |
read
Read text file contents. Use head/tail to preview first/last N lines of large files.
Parameter | Type | Required | Description |
| string | yes | Absolute path to file |
| integer | no | Read first N lines (1-100000) |
| integer | no | Read last N lines (1-100000) |
| integer | no | Start line (1-based, inclusive) |
| integer | no | End line (1-based, inclusive). Requires |
| boolean | no | Include SHA-256 hash of full file content. Default: |
read_many
Read multiple text files in one request.
Parameter | Type | Required | Description |
| string[] | yes | Files to read (1-100 paths) |
| integer | no | Read first N lines of each file |
| integer | no | Read last N lines of each file |
| integer | no | Start line (1-based) per file |
| integer | no | End line (1-based) per file |
stat
Get file/directory metadata: size, modified, permissions, mime, tokenEstimate.
Parameter | Type | Required | Description |
| string | yes | Absolute path to file or directory |
stat_many
Get metadata for multiple files/directories in one request.
Parameter | Type | Required | Description |
| string[] | yes | File/directory paths (1-100) |
grep
Search file contents (grep-like). Returns matching lines with optional context.
Parameter | Type | Required | Description |
| string | no | Base directory (default: root) |
| string | yes | Search text or RE2 regex when |
| boolean | no | Treat pattern as RE2 regex. Default: |
| boolean | no | Case-sensitive matching. Default: |
| boolean | no | Match whole words only. Default: |
| integer | no | Lines of context before/after (0-50). Default: 0 |
| integer | no | Max match rows (0-10000). Default: 500 |
| string | no | Relative glob for candidate files (e.g. |
| boolean | no | Include dotfiles. Default: |
| boolean | no | Include ignored items. Default: |
mkdir
Create a new directory (recursive). Idempotent.
Parameter | Type | Required | Description |
| string | no | Absolute path to directory to create |
| string[] | no | Multiple directories to create. Either |
write
Write content to a file, overwriting all existing content. Creates parent directories if needed.
Parameter | Type | Required | Description |
| string | yes | Absolute path to file |
| string | yes | Content to write |
edit
Apply sequential literal string replacements (first occurrence per edit). Use dryRun to preview.
Parameter | Type | Required | Description |
| string | yes | Absolute path to file |
| array | yes | List of non-empty |
| boolean | no | Preview edits without writing. Default: |
| boolean | no | Treat whitespace sequences as equivalent. Default: |
mv
Move or rename a file or directory.
Parameter | Type | Required | Description |
| string | no | Single path to move (deprecated: use |
| string[] | no | Paths to move. Either |
| string | yes | Destination path |
rm
Permanently delete a file or directory. Irreversible.
Parameter | Type | Required | Description |
| string | yes | Absolute path to file or directory |
| boolean | no | Delete non-empty directories. Default: |
| boolean | no | No error if missing. Default: |
calculate_hash
Calculate SHA-256 hash of a file or directory.
Parameter | Type | Required | Description |
| string | yes | Absolute path to file or directory |
diff_files
Generate a unified diff between two files. Output feeds directly into apply_patch.
Parameter | Type | Required | Description |
| string | yes | Path to original file |
| string | yes | Path to modified file |
| integer | no | Lines of context in diff output |
| boolean | no | Ignore leading/trailing whitespace. Default: |
| boolean | no | Strip trailing carriage returns. Default: |
apply_patch
Apply a unified diff patch to one or more files. Single-file: throws on failure. Multi-file: best-effort per file with results[]. Workflow: diff_files -> apply_patch(dryRun) -> apply_patch.
Parameter | Type | Required | Description |
| string | yes | Path to file (single) or base directory (multi-file patch) |
| string | yes | Unified diff with |
| integer | no | Max fuzzy mismatches per hunk (0-20) |
| boolean | no | Auto-convert line endings. Default: |
| boolean | no | Validate without writing. Default: |
search_and_replace
Bulk search-and-replace across files matching a glob. Replaces all occurrences per file. Always dryRun: true first.
Parameter | Type | Required | Description |
| string | no | Base directory (default: root) |
| string | no | Relative glob pattern (e.g. |
| string | yes | Text to search. RE2 regex when |
| string | yes | Replacement text. Supports |
| boolean | no | Treat as RE2 regex. Default: |
| boolean | no | Preview matches with diff. Default: |
| boolean | no | Include dotfiles. Default: |
| boolean | no | Include ignored items. Default: |
| boolean | no | Return diff even when not dry-run. Default: |
| integer | no | Max files to process before stopping (1-10000) |
| boolean | no | Case-sensitive matching. Default: |
Resources
Resource | URI | MIME Type | Description |
Instructions |
| text/markdown | Comprehensive usage rules and guidelines |
Tool Catalog |
| text/markdown | Tool selection guide and data flow map |
Workflows |
| text/markdown | Standard operating procedures for exploration, search, edit, patch |
Tool Info |
| text/markdown | Per-tool contract details, nuances, gotchas |
Result Cache |
| text/plain | Ephemeral cached tool output (large results externalized here) |
Metrics |
| application/json | Live per-tool call/error/avgDurationMs snapshot |
Prompts
Prompt | Arguments | Description |
|
| Return usage instructions. Optionally filter by section heading prefix |
|
| Generate a workflow for comparing two files using |
|
| Generate a workflow for analyzing a file or directory |
|
| Return a prompt with the authoritative contract for a specific tool |
MCP Capabilities
Capability | Status | Evidence |
| confirmed |
|
| confirmed |
|
| confirmed |
|
| confirmed |
|
| confirmed |
|
| confirmed |
|
Tool Annotations
Annotation | Tools | Value |
|
| Read-only, idempotent, non-destructive |
|
| Destructive writes, not idempotent |
|
| Idempotent write, non-destructive |
Structured Output
All 18 tools define outputSchema (Zod -> JSON Schema) and return structuredContent alongside text content. Set FS_CONTEXT_STRIP_STRUCTURED=true to strip output schemas from tool definitions (reduces token usage for LLMs that don't use structured output).
Configuration
HTTP & Auth
Variable | Default | Description |
| (none) | Bearer token required when binding HTTP to a non-loopback host |
|
| Max concurrent HTTP sessions (1-10,000) |
|
| HTTP server bind address |
|
| Max HTTP request body size (1 KB - 256 MB) |
File Size Limits
Variable | Default | Description |
|
| Max file size for text read operations (1 MB - 100 MB) |
|
| Max file size for content search/grep (100 KB - 10 MB) |
|
| Max cumulative size for |
|
| Search operation timeout in ms (100 - 60,000) |
Access Control
Variable | Default | Description |
|
| Allow reading sensitive files (.env, .key, credentials, tokens) |
| (none) | CSV/newline-separated glob patterns to block (in addition to built-in denylist) |
| (none) | CSV/newline-separated glob patterns to permit (overrides denylist) |
Output & Inline Limits
Variable | Default | Description |
|
| Max inline result chars before externalizing to |
|
| Max inline search matches before truncation |
|
| Strip |
Tasks
Variable | Default | Description |
|
| Max task TTL before auto-eviction (1 s - 24 hr) |
|
| Max simultaneous task executions (1-10,000) |
Logging & Diagnostics
Variable | Default | Description |
|
| MCP log level: debug, info, notice, warning, error, critical, alert, emergency |
|
| Enable diagnostic logging |
|
| Enable detailed diagnostic output |
|
| Log tool errors to stderr |
|
| Debug logging for search worker pool |
Performance
Variable | Default | Description |
| CPU cores (≤ 8) | Concurrent search worker threads (1-16) |
|
| Cursor TTL for |
HTTP Endpoints
When started with --port <number>, the server exposes a single MCP endpoint:
Method | Path | Purpose |
|
| Initialize session or send requests (Streamable HTTP) |
|
| HTTP streaming session endpoint |
|
| Terminate a session |
Required headers:
mcp-protocol-version— use the negotiated MCP protocol version on post-initialize HTTP requestsmcp-session-id— required forGET/DELETE(returned byPOSTon initialize)
Authentication: Requests to non-loopback HTTP binds require FILESYSTEM_MCP_API_KEY; clients must then send Authorization: Bearer <key>. Loopback-only binds may omit auth for local use. Uses SHA-256 timing-safe comparison.
CORS: Only localhost origins allowed (127.0.0.1, ::1, localhost).
Host validation: Loopback HTTP binds validate the Host header (localhost, 127.0.0.1, [::1]) to reduce DNS rebinding risk. Non-loopback binds still require FILESYSTEM_MCP_API_KEY.
Security
Control | Status | Evidence |
Path sandboxing | confirmed |
|
Traversal prevention | confirmed |
|
Symlink escape prevention | confirmed |
|
Sensitive file denylist | confirmed |
|
Origin validation | confirmed |
|
Bearer auth | confirmed |
|
Input validation | confirmed |
|
Request body limit | confirmed |
|
Remote bind guard | confirmed |
|
Development
dev—tsc --watch --preserveWatchOutput— Watch mode TypeScript compilationdev:run—node --env-file=.env --watch dist/index.js— Run server with auto-reloadstart—node dist/index.js— Run production serverbuild—node scripts/tasks.mjs build— Clean buildtest—node scripts/tasks.mjs test— Build + run all teststest:fast—node --test --import tsx/esm src/__tests__/**/*.test.ts node-tests/**/*.test.ts— Run tests without buildlint—eslint .— Lint sourcetype-check—node scripts/tasks.mjs type-check— Type-check src + testsformat—prettier --write .— Format codeinspector—npm run build && npx -y @modelcontextprotocol/inspector node dist/index.js ${workspaceFolder}— Launch MCP Inspector
Build and Release
CI:
.github/workflows/release.yml— runs lint, type-check, test, build before tagging/publishing.Docker: Multi-stage build with
node:24-alpine. Builder compiles TypeScript + native modules (re2); release stage runs as non-rootmcpuser.npm:
npm run prepublishOnlyruns lint + type-check + build.
Troubleshooting
"No allowed directories" — Pass at least one directory argument or use
--allow-cwd.Sensitive file blocked — Files matching the denylist (
.env*,.git, SSH keys) are blocked by design. Checksrc/lib/constants.tsfor the full list.Large result externalized — When tool output exceeds inline limits, it's cached as a resource at
filesystem-mcp://result/{id}. Read the resource URI to get the full content.Stdio: logs on stdout — Keep logs on stderr only. The server uses
console.errorfor diagnostics.HTTP 413 — Request body exceeds
FS_CONTEXT_MAX_REQUEST_BYTES. Increase the limit or reduce payload size.HTTP 401 —
FILESYSTEM_MCP_API_KEYis set but the request is missing or has an incorrectAuthorization: Bearerheader.
Credits
Dependency | Description |
MCP server SDK package | |
MCP client SDK package | |
Node transport package for MCP runtime | |
CLI argument parsing | |
Unified diff generation and patch application | |
| |
Safe RE2 regex engine (no ReDoS) | |
Schema validation and JSON Schema generation |
License
MIT License. See LICENSE for details.
Available Tools
13 toolscreateCreate FilesADestructive
Write whole text files: create new ones, overwrite, or append. Missing parent directories are created. edit or patch changes part of an existing file.
| Name | Required | Description | Default |
|---|---|---|---|
| files | Yes | List of files to create (max 100); each entry requires path and content; combined content is capped at the file-size limit |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare destructiveHint=true and readOnlyHint=false; the description adds real value beyond them by disclosing that missing parent directories are created and by flagging the whole-file overwrite/append semantics. It does not cover the return value or the confirmation prompt behavior (that lives in the schema), keeping it below 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, zero filler, with the core verb-and-resource statement front-loaded and the sibling disambiguation immediately after. Every clause earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a write tool with no output schema, the description covers modes, side effects, and sibling routing adequately. It omits batching behavior and what the call returns (paths, confirmation results), which are minor but real gaps.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and the schema already documents path, content, append, and overwrite thoroughly, so the baseline is 3. The description echoes the create/overwrite/append modes but adds no syntax or format detail beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Write whole text files') and enumerates the modes (create, overwrite, append). It explicitly distinguishes itself from the edit and patch siblings, so an agent can route without opening schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly names the alternatives (edit, patch) and the boundary condition that selects them: those change part of an existing file, whereas this writes whole files. There is no explicit when-not guidance (e.g. for binary files or very large files), so it falls just short of 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
deleteDelete FileADestructive
Permanently delete files, directories, or symlinks, like rm or rm -r. Paths are exact; globs are not expanded.
| Name | Required | Description | Default |
|---|---|---|---|
| paths | Yes | Paths to delete (max 1000); accepts files, directories, or symlinks | |
| recursive | No | Delete directory contents recursively (required for non-empty directories) | |
| ignoreIfNotExists | No | Silently succeed if a path does not exist instead of returning an error |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already indicate destructiveHint=true and readOnlyHint=false. The description adds meaningful behavior beyond that: deletion is permanent, applies to files/directories/symlinks, and uses exact path matching. This enriches rather than contradicts the annotation profile.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two compact sentences with no filler. The core purpose is front-loaded, and the glob caveat is a single high-value clarification that prevents misuse.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a destructive tool, the description covers permanence, target types, recursion analogy, and path-matching behavior. Parameters and destructive nature are already handled by the schema and annotations, so nothing critical is missing for an agent to call it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the schema already documents all three parameters in detail. The description adds only a high-level rm/rm -r analogy and an exact-paths caveat, which is marginal but not required for parameter understanding.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource set: 'Permanently delete files, directories, or symlinks.' The rm/rm -r analogy clarifies expected semantics and distinguishes this destructive tool from sibling read/write/edit/move operations.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives clear context for when to use—permanent deletion of paths—and adds a useful constraint: paths are exact and globs are not expanded. It does not name explicit alternatives, but no sibling provides a delete operation, so the usage context is sufficient.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
diffDiffARead-only
Compare two text files and return a unified diff from a to b, like diff -u.
| Name | Required | Description | Default |
|---|---|---|---|
| a | Yes | First file to compare | |
| b | Yes | Second file to compare | |
| context | No | Number of context lines surrounding each change (default: 3) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already establish read-only behavior, so the description need not repeat that. It adds the important ordering behavior (from a to b) and the output format ('unified diff, like diff -u'), which are not in annotations or schema. It does not discuss edge cases such as identical files or how the context parameter is applied, so the disclosure is adequate but not rich.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single front-loaded sentence that states action, input, and output with no filler. Every phrase ('Compare', 'two text files', 'unified diff', 'from a to b', 'like diff -u') carries semantic weight.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a read-only comparison tool with a self-describing schema, the description covers the key agent-facing facts: inputs, direction, and output format. It leaves edge-case behavior to implementation, but no output schema exists and the phrase 'like diff -u' provides a known format. This is sufficient for correct invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema descriptions already cover all three parameters at 100%, so the default baseline is 3. The description adds meaning by clarifying that a is the source/original and b is the target ('from a to b'), which removes ambiguity in how arguments should be passed. It does not comment on the context parameter, but the schema already defines its default, minimum, and maximum.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb ('Compare') and names the resource ('two text files') plus the exact output form ('unified diff'), so the tool's core purpose is unmistakable. It does not explicitly name a sibling alternative, but 'compare' is distinct from the create/edit/delete/search siblings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies its use case: whenever two text files need to be diffed, rather than edited or searched. It gives no explicit 'when not to use' guidance or sibling routing, so an agent must infer the context from tool name and purpose.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
editEdit FilesADestructive
Edit text files in place by replacing exact oldText with newText, like str_replace. Each oldText must match exactly once, and a file is written only if all its edits match. replace_text replaces every occurrence across files.
| Name | Required | Description | Default |
|---|---|---|---|
| path | No | Single file path; mutually exclusive with files | |
| edits | No | Replacements applied to path; not allowed when using files | |
| files | No | Per-file entries (batch mode) | |
| dryRun | No | Preview diffs without writing to disk (default: false = apply edits) | |
| ignoreWhitespace | No | Ignore leading/trailing whitespace differences when matching oldText |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already indicate destructiveHint=true and readOnlyHint=false, so the description carries a lighter burden. It adds valuable behavioral context: the atomicity of writes ('a file is written only if all its edits match') and the uniqueness requirement for oldText. This goes beyond the annotations and is useful for the agent to predict outcomes.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, with the core purpose front-loaded and the key behavioral constraints stated economically. No fluff, and the alternative tool is mentioned in the same breath, making it highly scannable.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description covers the core semantics (exact match, uniqueness, atomicity) and the primary alternative. It does not mention dryRun or ignoreWhitespace, but these are fully documented in the schema with defaults and descriptions. The batch mode via files is also implied by the sibling contrast but not explicitly highlighted; still, the schema covers it. Overall adequate for a destructive edit tool with strong schema support.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema fully documents each parameter. The description adds the str_replace analogy and the uniqueness/atomicity constraints, which reinforce but do not substantially extend the schema. This meets the baseline for a well-documented schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific action (edit text files in place) with a clear verb-resource pair, and explicitly contrasts with the sibling replace_text tool, which replaces every occurrence across files. This distinguishes it from alternatives immediately.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives clear guidance on when to use this tool versus replace_text ('replace_text replaces every occurrence across files'), and states the exact-match-once constraint. However, it does not explicitly address other siblings like patch or create, leaving some inference to the agent. The guidance is clear for the most relevant alternative but not exhaustive.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
find_filesFind FilesARead-only
Find files by name or glob pattern; returns file paths relative to the searched directory. A pattern without / matches file names at any depth. search_text searches contents.
| Name | Required | Description | Default |
|---|---|---|---|
| path | No | Base directory to search under (default: first allowed root) | |
| cursor | No | Opaque pagination cursor; pass unchanged for the next page. Pages slice one snapshot taken on the first call; it expires after ~60s — re-request without a cursor if rejected. | |
| sortBy | No | Sort order: path = full path (default), name = basename only | path |
| pattern | Yes | Glob pattern to match file paths (e.g. **/*.ts, src/**/*.js) | |
| maxDepth | No | Max directory depth to scan; 0 = base directory only, omit for unlimited | |
| maxResults | No | Maximum number of matching files to return per page | |
| includeHidden | No | Include hidden items (starting with .) | |
| includeIgnored | No | Include ignored items (node_modules, .git, etc). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, so the read-only nature is covered. The description adds useful behavioral context: returns relative paths, pattern semantics at any depth, and implies it does not search file contents (by directing to search_text). No contradiction with annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences with zero waste. The purpose is front-loaded, the pattern rule is actionable, and the alternative is stated at the end. Every clause adds value, and the structure is ideal for quick scanning.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a read-only search tool with 8 params fully documented in the schema, the description is largely complete. It clarifies the output format and pattern behavior, and implicitly indicates content search is out of scope. It does not mention pagination cursor expiry, but that is in the schema, so no critical gap for a well-formed call.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so all parameters are documented. The description adds an extra semantic for 'pattern' (the no-slash rule) beyond the schema examples, which provides meaningful value. It does not repeat schema descriptions, so it earns above the baseline 3.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb ('Find') and resource ('files by name or glob pattern'), and clarifies the output is relative paths. It explicitly distinguishes from search_text by noting that tool searches contents, so an agent can tell them apart without opening schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It provides a clear rule for pattern matching ('pattern without / matches file names at any depth') and names the alternative for content search ('search_text searches contents'). It does not mention the 'list' sibling, which could be a common alternative for directory listing, but the guidance is sufficient for the primary distinction.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
listListARead-only
List a directory's files and subdirectories as a tree of names, like ls or tree. stat returns sizes and dates.
| Name | Required | Description | Default |
|---|---|---|---|
| path | No | Directory to list (default: first allowed root) | |
| cursor | No | Opaque pagination cursor; pass unchanged for the next page. Pages slice one snapshot taken on the first call; it expires after ~60s — re-request without a cursor if rejected. | |
| maxDepth | No | Max directory depth to traverse (default: 1 = top-level only; increase to recurse deeper) | |
| maxEntries | No | Page size (default: 1000). Continue with nextCursor; an incomplete first page also carries resourceUri for the whole list. | |
| includeHidden | No | Include hidden items (starting with .) | |
| includeIgnored | No | Include ignored items (node_modules, .git, etc). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, so the description correctly does not contradict this. However, the description adds no behavioral context beyond what annotations provide—it does not mention pagination, snapshot semantics, or any side effects (which would be none given read-only). The schema itself documents cursor behavior and expiration, but the description itself adds no extra value beyond the annotation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single, well-structured sentence that starts with the core function and ends with a helpful pointer to an alternative. It wastes no words and is appropriately front-loaded, fitting within the ideal length for a tool this simple.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The tool has 6 parameters and no output schema. The description is very brief, but the schema carries rich information (pagination, snapshot expiry, defaults, limits). For a listing tool, an agent can likely infer most behavior from the schema. However, the description does not mention that results are paginated or that deeper recursion is possible, which could be useful context. It is adequate but not comprehensive; a 3 reflects that it covers the essentials without being fully self-sufficient.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the baseline is 3. The description does not elaborate on any parameter (e.g., path, maxDepth, includeHidden), relying entirely on the schema. It adds no additional meaning beyond what the schema already provides, so a 3 is appropriate per the rubric.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb ('List') and resource ('directory's files and subdirectories') and clarifies the output format ('as a tree of names'). It also distinguishes itself from a sibling tool ('stat returns sizes and dates'), making it easy for an agent to know what this tool does and what it does not.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives an implicit usage guideline by noting that 'stat returns sizes and dates,' implying that stat is the tool for metadata. However, it does not explicitly state when to use this tool versus alternatives like find_files or list_roots, nor does it mention any exclusions or prerequisites. The guidance is minimal and mostly inferred.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_rootsWorkspace RootsARead-only
List the directories this server can access, as absolute paths, including any the user granted during this session. Other tools can ask the user to grant access to a path outside them.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, so the read-only nature is covered. The description adds useful context beyond that: results are absolute paths and include any directories granted during the current session. This helps the agent understand what the returned set represents.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences with no filler. The core behavior is stated first, and the companion behavior about other tools granting access is a useful one-line addition. Every sentence earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a zero-parameter listing tool, the description fully explains what is returned (absolute paths of accessible directories), the session-grant aspect, and how it relates to other tools. No output schema is present, but the return concept is simple and clearly stated.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool has zero parametersasi, so the schema cannot provide parameter detail. With no parameters to document, the baseline of 4 applies; the description fully clarifies what the tool returns without needing parameter semantics.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb ('List') with a clear resource ('directories this server can access, as absolute paths'). It distinguishes list_roots from the generic sibling 'list' by scoping it to server-accessible workspace roots, including session-granted paths.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description makes it clear this tool is for discovering accessible directories. It also notes that other tools can request access to paths outside these roots, giving the agent a hint about when this tool is not sufficient. It does not explicitly name alternatives, but the context is clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
moveMove or Copy FilesADestructive
Move, rename, or copy files and directories, like mv or cp -r. Each destination is the full new path, not a folder to move into; missing parent directories are created.
| Name | Required | Description | Default |
|---|---|---|---|
| copy | No | Copy instead of move; sources are left in place | |
| moves | Yes | Operations to perform (max 100) | |
| overwrite | No | Copy mode only: overwrite existing destinations without confirmation |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already mark destructiveHint=true, and the description adds useful context about path interpretation ('full new path, not a folder') and automatic parent directory creation. However, it does not disclose whether move mode overwrites existing destinations by default, a critical behavioral detail given the destructive hint and the copy-only scope of the overwrite parameter.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two sentences with no redundancy. It front-loads the primary purpose, then immediately adds a key behavioral caveat. Every phrase earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description covers purpose, path semantics, and parent creation, which are essential. However, it leaves overwrite behavior in move mode ambiguous—whether move overwrites without confirmation—especially since the schema states overwrite applies only to copy mode. This is a significant gap for a destructive tool and reduces completeness.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so parameters are fully documented in the schema. The description adds minor clarification for the destination parameter (full path semantics) but does not add value beyond the schema for copy or overwrite, which are already described in their property descriptions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's function: 'Move, rename, or copy files and directories, like mv or cp -r.' It names specific operations and the resource type, distinguishing it from siblings like create, delete, or edit. The additional note about destination being a full path further clarifies scope.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies usage for moving, renaming, or copying but does not explicitly state when to use this tool over alternatives like create or delete. It lacks exclusions or conditions that would help an agent choose between tools, leaving the decision to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
patchPatchADestructive
Apply a single-file unified diff to one existing text file, like git apply. Nothing is written unless every hunk applies in file order with exactly matching context; hunks are found by their context, so start line numbers may be off.
| Name | Required | Description | Default |
|---|---|---|---|
| diff | Yes | Single-file unified diff to apply (as produced by the diff tool or edit dry-run) | |
| path | Yes | File to apply the diff to | |
| dryRun | No | Preview the result without writing (default: false) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description goes well beyond the annotations (destructiveHint=true) by detailing the atomicity: 'Nothing is written unless every hunk applies in file order with exactly matching context.' It also discloses a critical quirk: hunks are located by context, so line numbers may be off. This is essential behavioral information that the annotations do not provide.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, front-loaded with purpose and behavioral nuance. Every clause earns its place; the critical atomicity rule and context-matching caveat are delivered without padding.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a tool with three well-documented parameters, no output schema, and annotations covering destructiveness, the description supplies everything an agent needs: the exact operation, the single-file constraint, the atomicity guarantee, and the context-matching behavior. Nothing critical is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema already provides complete descriptions for all three parameters (diff, path, dryRun) with 100% coverage. The tool description adds no additional parameter-level detail beyond what the schema states, so the baseline score of 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a precise verb and resource: 'Apply a single-file unified diff to one existing text file.' The analogy 'like git apply' anchors it firmly in a well-known operation, and the distinction of single-file vs. multi-file and the context-matching behavior clearly separate it from sibling tools like edit or replace_text.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description makes it obvious when to use this tool: whenever you have a unified diff for a single file. It does not explicitly enumerate alternatives or exclusions, but the context is clear enough that an agent can infer the correct use case. The mention of 'existing text file' also implicitly signals it is not for new files.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
readRead FileARead-only
Read text files, like cat: whole, or one slice via head, tail, or startLine/endLine. Images and audio return as media; other binary files are rejected.
| Name | Required | Description | Default |
|---|---|---|---|
| head | No | Return first N lines | |
| path | No | Single file path; mutually exclusive with paths | |
| tail | No | Return last N lines | |
| paths | No | Array of file paths for batch mode (max 1000); mutually exclusive with path | |
| endLine | No | End line (1-indexed) | |
| startLine | No | Start line (1-indexed) | |
| includeHash | No | Include SHA-256 hash of the returned content in the response |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the readOnlyHint annotation, the description discloses concrete behaviors: it can return the whole file or a slice via head/tail/startLine/endLine, images/audio return as media, and other binary files are rejected. This adds significant behavioral context about return types and error handling that the annotation does not cover.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two concise sentences. The first sentence front-loads the core purpose and the slicing mechanisms; the second covers media and binary handling. Every word earns its place with no redundancy or fluff.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description explains the key return behaviors (text vs media vs rejection) and the slicing mechanisms. It does not mention batch mode (paths array) or the includeHash parameter, but these are fully described in the schema. Since there is no output schema, the description adequately covers return expectations, though it could note directory handling if applicable. Overall, it is sufficiently complete for an agent to call the tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so all parameters are already documented. The description adds only a high-level mention of slicing options (head, tail, startLine/endLine) but does not elaborate on mutual exclusivity, batch mode, or includeHash. Since the schema already provides full parameter descriptions, the description adds marginal value, consistent with the baseline of 3.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states a specific verb ('read') and resource ('text files'), with the analogy 'like cat' making the purpose instantly recognizable. It also distinguishes itself from siblings like edit, delete, and diff by focusing on read-only content access, and explicitly covers slicing and binary handling.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides clear context: it reads text files and can return whole or sliced content. It also mentions that binary files are rejected, which implies when not to use it. However, it does not explicitly name alternative tools (e.g., list, stat) for other use cases, so it lacks explicit when-not-to-use or alternative routing, but the context is sufficient for an agent to decide.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
replace_textSearch and ReplaceADestructive
Find and replace every occurrence of literal text or an RE2 regex, like sed -i, in one file or all files under a directory, optionally filtered by glob. The pattern runs over the whole file: it can span lines, and ^ and $ anchor to file start and end. edit replaces one unique exact match.
| Name | Required | Description | Default |
|---|---|---|---|
| path | No | File to rewrite, or directory to rewrite under. Omitting it targets the ENTIRE first allowed root — scope it deliberately, and pair a wide scope with dryRun=true first | |
| dryRun | No | Preview replacements without writing to disk (default: false = apply changes) | |
| isRegex | No | Treat searchPattern as a RE2 regex (default: literal text match) | |
| pattern | No | Glob to restrict replacements to specific file types (e.g. **/*.ts); default: all text files | |
| maxDepth | No | Max directory depth to scan; 0 = base directory only, omit for unlimited | |
| maxFiles | No | Maximum number of files to process | |
| wholeWord | No | Match whole words only (word boundary anchoring) | |
| maxResults | No | Maximum total match count across all files before stopping | |
| returnDiff | No | Include a unified diff of all changes in the response | |
| replacement | Yes | Replacement text. Use capture group references ($1, $2, etc.) when isRegex=true. Use an empty string to delete all matches. | |
| caseSensitive | No | Enable case-sensitive matching (default: case-insensitive) | |
| includeHidden | No | Include hidden items (starting with .) | |
| searchPattern | Yes | Exact literal text or RE2 regex pattern to search for. When isRegex=true, uses RE2 syntax (no lookahead, lookbehind, or backreferences are supported). Cannot be empty or whitespace-only. | |
| includeIgnored | No | Include ignored items (node_modules, .git, etc). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description adds substantial behavior beyond the destructiveHint annotation: patterns run over the whole file, can span lines, and '^ and $ anchor to file start and end.' It also clarifies literal vs RE2 semantics and the sed -i in-place behavior. No contradiction with the annotations was found.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three tight sentences carry high-signal information with no filler. The core operation is front-loaded, the regex/anchor nuance earns its place, and the sibling distinction is a single useful closing clause.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 14-parameter destructive tool, the description covers the essential operational model and the key alternative. The schema already documents every parameter, including dryRun and returnDiff, so the description need not repeat those details. A small gap is not explicitly warning to pair wide scopes with dryRun, though the schema's path parameter does mention it.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description enriches meaning by explaining that searchPattern operates over the entire file and that anchors behave file-wide rather than line-wise. It also ties the glob option to directory scanning. This adds genuine semantics beyond the schema's field-level descriptions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: 'Find and replace every occurrence of literal text or an RE2 regex... in one file or all files under a directory.' It also differentiates itself from the sibling edit tool by noting 'edit replaces one unique exact match,' so an agent can immediately distinguish bulk replacement from single-match editing.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description clearly conveys when to use this tool: for every occurrence across one file or a directory. It also gives an explicit alternative by noting 'edit replaces one unique exact match,' which routes single-match use cases elsewhere. It does not mention read-only search alternatives like search_text, but the destructive context is otherwise clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_textSearch ContentARead-only
Search file contents for literal text or an RE2 regex, like grep; returns matching lines with line numbers and paths relative to the searched directory. Patterns match within one line. find_files matches file names.
| Name | Required | Description | Default |
|---|---|---|---|
| path | No | File to search, or directory to search under (default: the whole first allowed root). Naming a file searches that file alone: pattern is ignored and hidden/ignored filtering does not apply. | |
| cursor | No | Opaque pagination cursor; pass unchanged for the next page. Pages slice one snapshot taken on the first call; it expires after ~60s — re-request without a cursor if rejected. | |
| context | No | Lines of context to return either side of each match, like grep -C (default: 0, max: 10) | |
| isRegex | No | Treat searchPattern as a regex (default: literal text match) | |
| pattern | No | Glob to restrict search to specific file types (e.g. **/*.ts); default: all text files | |
| maxDepth | No | Max directory depth to scan; 0 = base directory only, omit for unlimited | |
| maxResults | No | Maximum number of matching lines to return per page | |
| caseSensitive | No | Enable case-sensitive matching (default: case-insensitive) | |
| includeHidden | No | Include hidden items (starting with .) | |
| searchPattern | Yes | Exact literal text or RE2 regex pattern to search for in file contents. When isRegex=true, uses RE2 syntax (no lookahead, lookbehind, or backreferences). Cannot be empty or whitespace-only. | |
| includeIgnored | No | Include ignored items (node_modules, .git, etc). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The annotations already declare readOnlyHint=true, so the read-only nature is covered. The description adds valuable behavioral detail: patterns match within one line and the return format includes line numbers and relative paths, which goes beyond the annotations without contradicting them.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is only two sentences long, front-loaded with the primary function and immediately followed by a clear contrast to the sibling tool. There is no filler or redundancy; every sentence earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description covers the essential behavior, including return format and the line-matching limitation. However, it omits explicit mention of pagination via the cursor parameter and the default handling of hidden/ignored files, though these are documented in the schema. Given the rich schema and read-only annotations, this is adequate but not exhaustive.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so all 11 parameters are well-documented in the schema. The description does not add meaningful parameter-level information beyond what the schema already provides, so it meets the baseline for high coverage.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool searches file contents for literal text or an RE2 regex, like grep, and returns matching lines with line numbers and paths. It also explicitly distinguishes itself from the sibling tool find_files, which matches file names, making the purpose unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explicitly names find_files and states that it matches file names, implying that search_text is for content search while find_files is for name search. This provides direct guidance on when to use this tool versus the alternative.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
statGet File InfoARead-only
Get metadata without reading contents, like ls -ld: type, size (a directory reports its own entry, not its contents), tokenEstimate, timestamps, permissions, MIME type guessed from the extension, and symlink target. Also checks whether paths exist.
| Name | Required | Description | Default |
|---|---|---|---|
| path | No | Single file path; mutually exclusive with paths | |
| paths | No | Array of file paths for batch mode (max 1000); mutually exclusive with path |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description adds meaningful behavioral details beyond the readOnlyHint annotation: directory size refers to the directory entry itself, MIME type is guessed from extension, and symlink target is included. This sets correct expectations for stat semantics that a generic read-only hint does not convey. There is no contradiction with annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is compact and front-loaded: the core purpose appears in the first few words, followed by a useful ls -ld analogy and a tight list of returned fields. The final existence-check sentence earns its place by clarifying behavior on missing paths. There is no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a two-parameter metadata tool with no output schema, the description covers the key return fields, directory behavior, and existence checking. It does not specify the exact output structure or error behavior, but the field list is sufficient for an agent to invoke stat correctly and interpret results.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Both parameters are fully described in the input schema, so the description does not need to add parameter-level semantics. The metadata list applies to both path and paths modes but does not enrich the schema's already clear descriptions. A baseline of 3 is appropriate given the high schema coverage.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific action ('Get metadata without reading contents') and names the exact resource (path(s)) plus the metadata fields returned. It clearly distinguishes itself from read/list siblings by emphasizing that it does not read file contents. This is unambiguous and immediately actionable.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description clearly indicates this tool is for metadata retrieval, not content access, and adds that it checks whether paths exist. It does not explicitly name sibling alternatives or state when not to use it, so the agent must infer the choice from the 'without reading contents' contrast. That is clear context but not an explicit exclusion.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
1 tool update
v2.7.0- Changed
create1 field changed- changed
Input schema / properties / files / descriptionPrevious value: -"List of files to create (max 100); each entry requires path and content"New value: +"List of files to create (max 100); each entry requires path and content; combined content is capped at the file-size limit"
3 tool updates
v2.5.0- Changed
find_files1 field changed- changed
Input schema / properties / pattern / examplesPrevious value: -[ - "**/*.ts", - "src/**/*.js", - "*.{ts,tsx}" -]New value: +[ + "**/*.ts", + "src/**/*.js", + "**/*.{ts,tsx}" +]
- Changed
replace_text1 field changed- changed
Input schema / properties / pattern / examplesPrevious value: -[ - "**/*.ts", - "src/**/*.js", - "*.{ts,tsx}" -]New value: +[ + "**/*.ts", + "src/**/*.js", + "**/*.{ts,tsx}" +]
- Changed
search_text1 field changed- changed
Input schema / properties / pattern / examplesPrevious value: -[ - "**/*.ts", - "src/**/*.js", - "*.{ts,tsx}" -]New value: +[ + "**/*.ts", + "src/**/*.js", + "**/*.{ts,tsx}" +]
13 tool updates
v2.4.1- Changed
create1 field changed- added
Input schema / $schemaAdded value: +"https://json-schema.org/draft/2020-12/schema"
- Changed
delete1 field changed- added
Input schema / $schemaAdded value: +"https://json-schema.org/draft/2020-12/schema"
- Changed
diff1 field changed- added
Input schema / $schemaAdded value: +"https://json-schema.org/draft/2020-12/schema"
- Changed
edit3 fields changed- added
Input schema / $defs / EditSpec / properties / newText / examplesAdded value: +[ + "const x = 2;", + "function newName(", + "" +] - added
Input schema / $defs / EditSpec / properties / oldText / examplesAdded value: +[ + "const x = 1;", + "function oldName(" +] - added
Input schema / $schemaAdded value: +"https://json-schema.org/draft/2020-12/schema"
- Changed
find_files2 fields changed- added
Input schema / $schemaAdded value: +"https://json-schema.org/draft/2020-12/schema" - added
Input schema / properties / pattern / examplesAdded value: +[ + "**/*.ts", + "src/**/*.js", + "*.{ts,tsx}" +]
- Changed
list1 field changed- added
Input schema / $schemaAdded value: +"https://json-schema.org/draft/2020-12/schema"
- Changed
list_roots1 field changed- added
Input schema / $schemaAdded value: +"https://json-schema.org/draft/2020-12/schema"
- Changed
move1 field changed- added
Input schema / $schemaAdded value: +"https://json-schema.org/draft/2020-12/schema"
- Changed
patch1 field changed- added
Input schema / $schemaAdded value: +"https://json-schema.org/draft/2020-12/schema"
- Changed
read1 field changed- added
Input schema / $schemaAdded value: +"https://json-schema.org/draft/2020-12/schema"
- Changed
replace_text4 fields changed- added
Input schema / $schemaAdded value: +"https://json-schema.org/draft/2020-12/schema" - added
Input schema / properties / pattern / examplesAdded value: +[ + "**/*.ts", + "src/**/*.js", + "*.{ts,tsx}" +] - added
Input schema / properties / replacement / examplesAdded value: +[ + "$1_renamed", + "", + "TODO: fix" +] - added
Input schema / properties / searchPattern / examplesAdded value: +[ + "TODO", + "function\\s+(\\w+)", + "import.*from" +]
- Changed
search_text3 fields changed- added
Input schema / $schemaAdded value: +"https://json-schema.org/draft/2020-12/schema" - added
Input schema / properties / pattern / examplesAdded value: +[ + "**/*.ts", + "src/**/*.js", + "*.{ts,tsx}" +] - added
Input schema / properties / searchPattern / examplesAdded value: +[ + "TODO", + "function\\s+(\\w+)", + "import.*from" +]
- Changed
stat1 field changed- added
Input schema / $schemaAdded value: +"https://json-schema.org/draft/2020-12/schema"
3 tool updates
v2.3.0- Changed
create2 fields changed- added
Input schema / properties / files / items / properties / appendAdded value: +{ + "description": "Append the content to the end of the file instead of overwriting; creates the file if it does not exist", + "type": "boolean" +} - added
Input schema / properties / files / items / properties / overwriteAdded value: +{ + "description": "Replace an existing file without asking the user; without it an existing file prompts for confirmation", + "type": "boolean" +}
- Changed
edit1 field changed- changed
Input schema / $defs / EditSpec / properties / oldText / descriptionPrevious value: -"Exact literal text to locate in the file. Must include 3-5 lines of context to ensure uniqueness and avoid matching the wrong block."New value: +"Exact literal text to locate in the file; it must match exactly once. Include 3-5 lines of context so it does — an oldText found in several places fails with their line numbers."
- Changed
search_text1 field changed- added
Input schema / properties / contextAdded value: +{ + "default": 0, + "description": "Lines of context to return either side of each match, like grep -C (default: 0, max: 10)", + "maximum": 10, + "minimum": 0, + "type": "integer" +}
5 tool updates
v2.1.5- Changed
delete1 field changed- changed
Output schema / (root)Previous value: -{ - "additionalProperties": false, - "properties": { - "results": { - "description": "Per-path results ordered to match the input paths", - "items": { - "additionalProperties": false, - "properties": { - "error": { - "additionalProperties": false, - "description": "Error details; present on failure", - "properties": { - "code": { - "type": "string" - }, - "message": { - "type": "string" - }, - "path": { - "type": "string" - }, - "suggestion": { - "type": "string" - } - }, - "required": [ - "code", - "message" - ], - "type": "object" - }, - "path": { - "description": "Requested path", - "type": "string" - }, - "value": { - "additionalProperties": false, - "description": "Delete outcome; present on success", - "properties": { - "deleted": { - "description": "True when the path was removed; false when the user chose Skip", - "type": "boolean" - } - }, - "required": [ - "deleted" - ], - "type": "object" - } - }, - "required": [ - "path" - ], - "type": "object" - }, - "type": "array" - }, - "summary": { - "additionalProperties": false, - "properties": { - "failed": { - "minimum": 0, - "type": "integer" - }, - "succeeded": { - "minimum": 0, - "type": "integer" - }, - "total": { - "minimum": 0, - "type": "integer" - } - }, - "required": [ - "total", - "succeeded", - "failed" - ], - "type": "object" - } - }, - "required": [ - "results", - "summary" - ], - "type": "object" -}New value: +null
- Changed
edit1 field changed- changed
Output schema / (root)Previous value: -{ - "additionalProperties": false, - "properties": { - "results": { - "description": "Per-path edit results ordered to match the input paths", - "items": { - "additionalProperties": false, - "properties": { - "error": { - "additionalProperties": false, - "description": "Error details; present on failure", - "properties": { - "code": { - "type": "string" - }, - "message": { - "type": "string" - }, - "path": { - "type": "string" - }, - "suggestion": { - "type": "string" - } - }, - "required": [ - "code", - "message" - ], - "type": "object" - }, - "path": { - "description": "Requested file path", - "type": "string" - }, - "value": { - "additionalProperties": false, - "description": "Edit result; present on success", - "properties": { - "appliedEdits": { - "description": "Number of edits successfully applied", - "minimum": 0, - "type": "integer" - }, - "diff": { - "description": "Unified diff of all changes (present only in dryRun mode)", - "type": "string" - }, - "kind": { - "description": "Broad file kind: text, binary, image, audio, or pdf", - "enum": [ - "text", - "binary", - "image", - "audio", - "pdf" - ], - "type": "string" - }, - "lineCount": { - "description": "Number of lines in the file after edits", - "minimum": 0, - "type": "integer" - }, - "lineRange": { - "description": "Line range [firstLine, lastLine] covering all applied edits", - "prefixItems": [ - { - "exclusiveMinimum": 0, - "type": "integer" - }, - { - "exclusiveMinimum": 0, - "type": "integer" - } - ], - "type": "array" - }, - "linesAdded": { - "description": "Net lines added by all applied edits", - "minimum": 0, - "type": "integer" - }, - "linesRemoved": { - "description": "Net lines removed by all applied edits", - "minimum": 0, - "type": "integer" - }, - "mimeType": { - "description": "Detected MIME type of the file", - "type": "string" - }, - "modified": { - "description": "Last modification timestamp after edits (ISO 8601 UTC)", - "format": "date-time", - "type": "string" - }, - "path": { - "description": "Resolved absolute path of the edited file", - "type": "string" - }, - "resourceUri": { - "description": "Resource URI pointing to the updated file content; omitted when no edit matched (appliedEdits is 0) and the file was left untouched", - "type": "string" - }, - "size": { - "description": "File size in bytes after edits", - "minimum": 0, - "type": "integer" - }, - "unmatchedEdits": { - "description": "oldText values that did not match any content in the file", - "items": { - "type": "string" - }, - "type": "array" - } - }, - "required": [ - "path", - "size", - "lineCount", - "mimeType", - "kind", - "modified", - "appliedEdits" - ], - "type": "object" - } - }, - "required": [ - "path" - ], - "type": "object" - }, - "type": "array" - }, - "summary": { - "additionalProperties": false, - "properties": { - "failed": { - "minimum": 0, - "type": "integer" - }, - "succeeded": { - "minimum": 0, - "type": "integer" - }, - "total": { - "minimum": 0, - "type": "integer" - } - }, - "required": [ - "total", - "succeeded", - "failed" - ], - "type": "object" - } - }, - "required": [ - "results", - "summary" - ], - "type": "object" -}New value: +null
- Changed
list1 field changed- changed
Input schema / properties / maxEntries / descriptionPrevious value: -"Page size (default: 1000). Continue with nextCursor; resourceUri is only for hard-cap overflow."New value: +"Page size (default: 1000). Continue with nextCursor; an incomplete first page also carries resourceUri for the whole list."
- Changed
read1 field changed- changed
Output schema / (root)Previous value: -{ - "additionalProperties": false, - "properties": { - "results": { - "description": "Per-path results ordered to match the input paths", - "items": { - "additionalProperties": false, - "properties": { - "error": { - "additionalProperties": false, - "description": "Error details; present on failure", - "properties": { - "code": { - "type": "string" - }, - "message": { - "type": "string" - }, - "path": { - "type": "string" - }, - "suggestion": { - "type": "string" - } - }, - "required": [ - "code", - "message" - ], - "type": "object" - }, - "path": { - "description": "Requested file path", - "type": "string" - }, - "value": { - "additionalProperties": false, - "description": "Read result; present on success", - "properties": { - "contentHash": { - "description": "SHA-256 hex digest of the returned content (present when includeHash=true)", - "pattern": "^[0-9a-f]{64}$", - "type": "string" - }, - "continuation": { - "additionalProperties": false, - "description": "Next-read arguments; present when content was truncated due to size limits", - "properties": { - "args": { - "additionalProperties": false, - "description": "Ready-to-use arguments for the next call; pass verbatim", - "properties": { - "endLine": { - "exclusiveMinimum": 0, - "type": "integer" - }, - "path": { - "type": "string" - }, - "startLine": { - "exclusiveMinimum": 0, - "type": "integer" - } - }, - "required": [ - "path", - "startLine", - "endLine" - ], - "type": "object" - }, - "hint": { - "description": "One-sentence description of the data still remaining to be read", - "type": "string" - }, - "tool": { - "description": "Tool name to call for the next chunk", - "type": "string" - } - }, - "required": [ - "tool", - "args", - "hint" - ], - "type": "object" - }, - "endLine": { - "description": "End line", - "exclusiveMinimum": 0, - "type": "integer" - }, - "hasMoreLines": { - "description": "True when additional lines remain beyond what was returned", - "type": "boolean" - }, - "head": { - "description": "Head lines requested", - "exclusiveMinimum": 0, - "type": "integer" - }, - "kind": { - "description": "Broad file kind: text, binary, image, audio, or pdf", - "enum": [ - "text", - "binary", - "image", - "audio", - "pdf" - ], - "type": "string" - }, - "linesRead": { - "description": "Number of lines returned in this response", - "minimum": 0, - "type": "integer" - }, - "mimeType": { - "description": "Detected MIME type (e.g. text/typescript)", - "type": "string" - }, - "resourceUri": { - "description": "Resource URI for externalized content (present when file is stored in resource store)", - "type": "string" - }, - "startLine": { - "description": "Start line", - "exclusiveMinimum": 0, - "type": "integer" - }, - "tail": { - "description": "Tail lines requested", - "exclusiveMinimum": 0, - "type": "integer" - }, - "totalLines": { - "description": "Total line count in the full file", - "minimum": 0, - "type": "integer" - } - }, - "type": "object" - } - }, - "required": [ - "path" - ], - "type": "object" - }, - "type": "array" - }, - "summary": { - "additionalProperties": false, - "properties": { - "failed": { - "minimum": 0, - "type": "integer" - }, - "succeeded": { - "minimum": 0, - "type": "integer" - }, - "total": { - "minimum": 0, - "type": "integer" - } - }, - "required": [ - "total", - "succeeded", - "failed" - ], - "type": "object" - } - }, - "required": [ - "results", - "summary" - ], - "type": "object" -}New value: +null
- Changed
replace_text1 field changed- changed
Output schema / (root)Previous value: -{ - "additionalProperties": false, - "properties": { - "diff": { - "description": "Unified diff of all changes (present when returnDiff=true or dryRun=true)", - "type": "string" - }, - "diffTruncated": { - "description": "True when the diff was cut due to the size limit", - "type": "boolean" - }, - "filesScanned": { - "description": "Total number of files examined", - "minimum": 0, - "type": "integer" - }, - "results": { - "description": "Per-file results: modified files, then any that could not be processed", - "items": { - "additionalProperties": false, - "properties": { - "error": { - "additionalProperties": false, - "description": "Error details; present on failure", - "properties": { - "code": { - "type": "string" - }, - "message": { - "type": "string" - }, - "path": { - "type": "string" - }, - "suggestion": { - "type": "string" - } - }, - "required": [ - "code", - "message" - ], - "type": "object" - }, - "path": { - "description": "File path relative to the search root", - "type": "string" - }, - "value": { - "additionalProperties": false, - "description": "Replacement outcome; present on success", - "properties": { - "matches": { - "description": "Replacements applied in this file", - "minimum": 0, - "type": "integer" - } - }, - "required": [ - "matches" - ], - "type": "object" - } - }, - "required": [ - "path" - ], - "type": "object" - }, - "type": "array" - }, - "resultsTruncated": { - "description": "True when the results list holds fewer entries than summary.total: the changed-file or failed-file cap was hit. Trust summary over results.length.", - "type": "boolean" - }, - "stoppedReason": { - "description": "Why enumeration stopped early: maxResults = match cap reached, maxFiles = file cap reached, timeout = time limit hit or cancelled. Absent when every matching file was enumerated. Marks the sweep incomplete, not the writes; files already dispatched still complete.", - "enum": [ - "maxResults", - "maxFiles", - "timeout" - ], - "type": "string" - }, - "summary": { - "additionalProperties": false, - "properties": { - "failed": { - "minimum": 0, - "type": "integer" - }, - "succeeded": { - "minimum": 0, - "type": "integer" - }, - "total": { - "minimum": 0, - "type": "integer" - } - }, - "required": [ - "total", - "succeeded", - "failed" - ], - "type": "object" - }, - "totalMatches": { - "description": "Total number of replacements made across all files", - "minimum": 0, - "type": "integer" - } - }, - "required": [ - "results", - "summary", - "totalMatches", - "filesScanned" - ], - "type": "object" -}New value: +null
28 tool updates
v2.0.0- Removed
apply_patch - Removed
calculate_hash - Added
create - Added
delete - Added
diff - Removed
diff_files - Changed
edit27 fields changed- added
Input schema / $defsAdded value: +{ + "EditSpec": { + "additionalProperties": false, + "properties": { + "newText": { + "description": "Replacement text. Use an empty string to delete the matched oldText.", + "type": "string" + }, + "oldText": { + "description": "Exact literal text to locate in the file. Must include 3-5 lines of context to ensure uniqueness and avoid matching the wrong block.", + "minLength": 1, + "type": "string" + } + }, + "required": [ + "oldText", + "newText" + ], + "type": "object" + } +} - removed
Input schema / $schemaRemoved value: -"https://json-schema.org/draft/2020-12/schema" - added
Input schema / oneOfAdded value: +[ + { + "required": [ + "path", + "edits" + ] + }, + { + "required": [ + "files" + ] + } +] - changed
Input schema / properties / dryRun / descriptionPrevious value: -"Preview edits without writing. Check `unmatchedEdits` in response."New value: +"Preview diffs without writing to disk (default: false = apply edits)" - changed
Input schema / properties / edits / descriptionPrevious value: -"List of replacements to apply sequentially. Each edit replaces the first occurrence of oldText."New value: +"Replacements applied to path; not allowed when using files" - added
Input schema / properties / edits / items / $refAdded value: +"#/$defs/EditSpec" - removed
Input schema / properties / edits / items / additionalPropertiesRemoved value: -false - removed
Input schema / properties / edits / items / propertiesRemoved value: -{ - "newText": { - "description": "Replacement string. Preserve surrounding indentation style.", - "type": "string" - }, - "oldText": { - "description": "Exact literal string to replace (character-for-character). Include 3–5 lines of context for unique targeting.", - "maxLength": 102400, - "minLength": 1, - "type": "string" - } -} - removed
Input schema / properties / edits / items / requiredRemoved value: -[ - "oldText", - "newText" -] - removed
Input schema / properties / edits / items / typeRemoved value: -"object" - added
Input schema / properties / edits / maxItemsAdded value: +100 - added
Input schema / properties / filesAdded value: +{ + "description": "Per-file entries (batch mode)", + "items": { + "additionalProperties": false, + "properties": { + "edits": { + "description": "Replacements to apply to this specific file", + "items": { + "$ref": "#/$defs/EditSpec" + }, + "maxItems": 100, + "minItems": 1, + "type": "array" + }, + "path": { + "description": "File or directory path inside an allowed workspace root.", + "maxLength": 4096, + "minLength": 1, + "type": "string" + } + }, + "required": [ + "path", + "edits" + ], + "type": "object" + }, + "maxItems": 5, + "minItems": 1, + "type": "array" +} - changed
Input schema / properties / ignoreWhitespace / descriptionPrevious value: -"Treat all whitespace sequences as equivalent when matching oldText."New value: +"Ignore leading/trailing whitespace differences when matching oldText" - changed
Input schema / properties / path / descriptionPrevious value: -"Absolute path to file or directory."New value: +"Single file path; mutually exclusive with files" - removed
Input schema / requiredRemoved value: -[ - "path", - "edits" -] - removed
Output schema / $schemaRemoved value: -"https://json-schema.org/draft/2020-12/schema" - removed
Output schema / properties / appliedEditsRemoved value: -{ - "maximum": 9007199254740991, - "minimum": 0, - "type": "integer" -} - removed
Output schema / properties / diffRemoved value: -{ - "description": "Unified diff of changes (dryRun)", - "type": "string" -} - removed
Output schema / properties / lineRangeRemoved value: -{ - "description": "Line range modified [start, end] (1-based)", - "prefixItems": [ - { - "maximum": 9007199254740991, - "minimum": 1, - "type": "integer" - }, - { - "maximum": 9007199254740991, - "minimum": 1, - "type": "integer" - } - ], - "type": "array" -} - removed
Output schema / properties / linesAddedRemoved value: -{ - "description": "Lines added", - "maximum": 9007199254740991, - "minimum": 0, - "type": "integer" -} - removed
Output schema / properties / linesRemovedRemoved value: -{ - "description": "Lines removed", - "maximum": 9007199254740991, - "minimum": 0, - "type": "integer" -} - removed
Output schema / properties / okRemoved value: -{ - "type": "boolean" -} - removed
Output schema / properties / pathRemoved value: -{ - "type": "string" -} - added
Output schema / properties / resultsAdded value: +{ + "description": "Per-path edit results ordered to match the input paths", + "items": { + "additionalProperties": false, + "properties": { + "error": { + "additionalProperties": false, + "description": "Error details; present on failure", + "properties": { + "code": { + "type": "string" + }, + "message": { + "type": "string" + }, + "path": { + "type": "string" + }, + "suggestion": { + "type": "string" + } + }, + "required": [ + "code", + "message" + ], + "type": "object" + }, + "path": { + "description": "Requested file path", + "type": "string" + }, + "value": { + "additionalProperties": false, + "description": "Edit result; present on success", + "properties": { + "appliedEdits": { + "description": "Number of edits successfully applied", + "minimum": 0, + "type": "integer" + }, + "diff": { + "description": "Unified diff of all changes (present only in dryRun mode)", + "type": "string" + }, + "kind": { + "description": "Broad file kind: text, binary, image, audio, or pdf", + "enum": [ + "text", + "binary", + "image", + "audio", + "pdf" + ], + "type": "string" + }, + "lineCount": { + "description": "Number of lines in the file after edits", + "minimum": 0, + "type": "integer" + }, + "lineRange": { + "description": "Line range [firstLine, lastLine] covering all applied edits", + "prefixItems": [ + { + "exclusiveMinimum": 0, + "type": "integer" + }, + { + "exclusiveMinimum": 0, + "type": "integer" + } + ], + "type": "array" + }, + "linesAdded": { + "description": "Net lines added by all applied edits", + "minimum": 0, + "type": "integer" + }, + "linesRemoved": { + "description": "Net lines removed by all applied edits", + "minimum": 0, + "type": "integer" + }, + "mimeType": { + "description": "Detected MIME type of the file", + "type": "string" + }, + "modified": { + "description": "Last modification timestamp after edits (ISO 8601 UTC)", + "format": "date-time", + "type": "string" + }, + "path": { + "description": "Resolved absolute path of the edited file", + "type": "string" + }, + "resourceUri": { + "description": "Resource URI pointing to the updated file content; omitted when no edit matched (appliedEdits is 0) and the file was left untouched", + "type": "string" + }, + "size": { + "description": "File size in bytes after edits", + "minimum": 0, + "type": "integer" + }, + "unmatchedEdits": { + "description": "oldText values that did not match any content in the file", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "path", + "size", + "lineCount", + "mimeType", + "kind", + "modified", + "appliedEdits" + ], + "type": "object" + } + }, + "required": [ + "path" + ], + "type": "object" + }, + "type": "array" +} - added
Output schema / properties / summaryAdded value: +{ + "additionalProperties": false, + "properties": { + "failed": { + "minimum": 0, + "type": "integer" + }, + "succeeded": { + "minimum": 0, + "type": "integer" + }, + "total": { + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "total", + "succeeded", + "failed" + ], + "type": "object" +} - removed
Output schema / properties / unmatchedEditsRemoved value: -{ - "description": "Edits that could not be applied", - "items": { - "type": "string" - }, - "type": "array" -} - changed
Output schema / requiredPrevious value: -[ - "ok" -]New value: +[ + "results", + "summary" +]
- Removed
find - Added
find_files - Removed
grep - Added
list - Added
list_roots - Removed
ls - Removed
mkdir - Added
move - Removed
mv - Added
patch - Changed
read31 fields changed- removed
Input schema / $schemaRemoved value: -"https://json-schema.org/draft/2020-12/schema" - added
Input schema / dependentRequiredAdded value: +{ + "endLine": [ + "startLine" + ] +} - removed
Input schema / descriptionRemoved value: -"Use one read mode only: 'head', 'tail', or 'startLine'/'endLine'." - added
Input schema / oneOfAdded value: +[ + { + "required": [ + "path" + ] + }, + { + "required": [ + "paths" + ] + } +] - changed
Input schema / properties / endLine / descriptionPrevious value: -"End line (1-based, inclusive). Defaults to last line when startLine is set."New value: +"End line (1-indexed)" - changed
Input schema / properties / endLine / maximumPrevious value: -9007199254740991New value: +100000 - changed
Input schema / properties / head / descriptionPrevious value: -"Read first N lines (preview)"New value: +"Return first N lines" - changed
Input schema / properties / includeHash / descriptionPrevious value: -"Include SHA-256 hash of full file content"New value: +"Include SHA-256 hash of the returned content in the response" - changed
Input schema / properties / path / descriptionPrevious value: -"Absolute path to file or directory."New value: +"Single file path; mutually exclusive with paths" - added
Input schema / properties / pathsAdded value: +{ + "description": "Array of file paths for batch mode (max 1000); mutually exclusive with path", + "items": { + "description": "File or directory path inside an allowed workspace root.", + "maxLength": 4096, + "minLength": 1, + "type": "string" + }, + "maxItems": 1000, + "minItems": 1, + "type": "array" +} - changed
Input schema / properties / startLine / descriptionPrevious value: -"Start line (1-based, inclusive). Defaults to 1 when endLine is set."New value: +"Start line (1-indexed)" - changed
Input schema / properties / startLine / maximumPrevious value: -9007199254740991New value: +100000 - changed
Input schema / properties / tail / descriptionPrevious value: -"Read last N lines"New value: +"Return last N lines" - removed
Input schema / requiredRemoved value: -[ - "path" -] - removed
Output schema / $schemaRemoved value: -"https://json-schema.org/draft/2020-12/schema" - removed
Output schema / properties / contentRemoved value: -{ - "description": "Content", - "type": "string" -} - removed
Output schema / properties / contentHashRemoved value: -{ - "description": "SHA-256 of full file content", - "pattern": "^[a-f0-9]{64}$", - "type": "string" -} - removed
Output schema / properties / endLineRemoved value: -{ - "description": "End line", - "maximum": 9007199254740991, - "minimum": 1, - "type": "integer" -} - removed
Output schema / properties / hasMoreLinesRemoved value: -{ - "description": "More lines?", - "type": "boolean" -} - removed
Output schema / properties / headRemoved value: -{ - "description": "Head lines", - "maximum": 9007199254740991, - "minimum": 1, - "type": "integer" -} - removed
Output schema / properties / linesReadRemoved value: -{ - "description": "Lines read", - "maximum": 9007199254740991, - "minimum": 0, - "type": "integer" -} - removed
Output schema / properties / okRemoved value: -{ - "const": true, - "type": "boolean" -} - removed
Output schema / properties / pathRemoved value: -{ - "type": "string" -} - removed
Output schema / properties / resourceUriRemoved value: -{ - "description": "Full content URI", - "type": "string" -} - added
Output schema / properties / resultsAdded value: +{ + "description": "Per-path results ordered to match the input paths", + "items": { + "additionalProperties": false, + "properties": { + "error": { + "additionalProperties": false, + "description": "Error details; present on failure", + "properties": { + "code": { + "type": "string" + }, + "message": { + "type": "string" + }, + "path": { + "type": "string" + }, + "suggestion": { + "type": "string" + } + }, + "required": [ + "code", + "message" + ], + "type": "object" + }, + "path": { + "description": "Requested file path", + "type": "string" + }, + "value": { + "additionalProperties": false, + "description": "Read result; present on success", + "properties": { + "contentHash": { + "description": "SHA-256 hex digest of the returned content (present when includeHash=true)", + "pattern": "^[0-9a-f]{64}$", + "type": "string" + }, + "continuation": { + "additionalProperties": false, + "description": "Next-read arguments; present when content was truncated due to size limits", + "properties": { + "args": { + "additionalProperties": false, + "description": "Ready-to-use arguments for the next call; pass verbatim", + "properties": { + "endLine": { + "exclusiveMinimum": 0, + "type": "integer" + }, + "path": { + "type": "string" + }, + "startLine": { + "exclusiveMinimum": 0, + "type": "integer" + } + }, + "required": [ + "path", + "startLine", + "endLine" + ], + "type": "object" + }, + "hint": { + "description": "One-sentence description of the data still remaining to be read", + "type": "string" + }, + "tool": { + "description": "Tool name to call for the next chunk", + "type": "string" + } + }, + "required": [ + "tool", + "args", + "hint" + ], + "type": "object" + }, + "endLine": { + "description": "End line", + "exclusiveMinimum": 0, + "type": "integer" + }, + "hasMoreLines": { + "description": "True when additional lines remain beyond what was returned", + "type": "boolean" + }, + "head": { + "description": "Head lines requested", + "exclusiveMinimum": 0, + "type": "integer" + }, + "kind": { + "description": "Broad file kind: text, binary, image, audio, or pdf", + "enum": [ + "text", + "binary", + "image", + "audio", + "pdf" + ], + "type": "string" + }, + "linesRead": { + "description": "Number of lines returned in this response", + "minimum": 0, + "type": "integer" + }, + "mimeType": { + "description": "Detected MIME type (e.g. text/typescript)", + "type": "string" + }, + "resourceUri": { + "description": "Resource URI for externalized content (present when file is stored in resource store)", + "type": "string" + }, + "startLine": { + "description": "Start line", + "exclusiveMinimum": 0, + "type": "integer" + }, + "tail": { + "description": "Tail lines requested", + "exclusiveMinimum": 0, + "type": "integer" + }, + "totalLines": { + "description": "Total line count in the full file", + "minimum": 0, + "type": "integer" + } + }, + "type": "object" + } + }, + "required": [ + "path" + ], + "type": "object" + }, + "type": "array" +} - removed
Output schema / properties / startLineRemoved value: -{ - "description": "Start line", - "maximum": 9007199254740991, - "minimum": 1, - "type": "integer" -} - added
Output schema / properties / summaryAdded value: +{ + "additionalProperties": false, + "properties": { + "failed": { + "minimum": 0, + "type": "integer" + }, + "succeeded": { + "minimum": 0, + "type": "integer" + }, + "total": { + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "total", + "succeeded", + "failed" + ], + "type": "object" +} - removed
Output schema / properties / tailRemoved value: -{ - "description": "Tail lines", - "maximum": 9007199254740991, - "minimum": 1, - "type": "integer" -} - removed
Output schema / properties / totalLinesRemoved value: -{ - "description": "Total lines", - "maximum": 9007199254740991, - "minimum": 0, - "type": "integer" -} - removed
Output schema / properties / truncatedRemoved value: -{ - "description": "Truncated?", - "type": "boolean" -} - changed
Output schema / requiredPrevious value: -[ - "ok" -]New value: +[ + "results", + "summary" +]
- Removed
read_many - Added
replace_text - Removed
rm - Removed
roots - Removed
search_and_replace - Added
search_text - Changed
stat6 fields changed- removed
Input schema / $schemaRemoved value: -"https://json-schema.org/draft/2020-12/schema" - added
Input schema / oneOfAdded value: +[ + { + "required": [ + "path" + ] + }, + { + "required": [ + "paths" + ] + } +] - changed
Input schema / properties / path / descriptionPrevious value: -"Absolute path to file or directory."New value: +"Single file path; mutually exclusive with paths" - added
Input schema / properties / pathsAdded value: +{ + "description": "Array of file paths for batch mode (max 1000); mutually exclusive with path", + "items": { + "description": "File or directory path inside an allowed workspace root.", + "maxLength": 4096, + "minLength": 1, + "type": "string" + }, + "maxItems": 1000, + "minItems": 1, + "type": "array" +} - removed
Input schema / requiredRemoved value: -[ - "path" -] - changed
Output schema / (root)Previous value: -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "additionalProperties": false, - "properties": { - "info": { - "additionalProperties": false, - "properties": { - "accessed": { - "description": "Accessed", - "format": "date-time", - "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$", - "type": "string" - }, - "created": { - "description": "Created", - "format": "date-time", - "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$", - "type": "string" - }, - "isHidden": { - "description": "Hidden?", - "type": "boolean" - }, - "mimeType": { - "description": "MIME type", - "type": "string" - }, - "modified": { - "description": "Modified", - "format": "date-time", - "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$", - "type": "string" - }, - "name": { - "description": "Name", - "type": "string" - }, - "path": { - "description": "Absolute path", - "type": "string" - }, - "permissions": { - "description": "Permissions", - "type": "string" - }, - "size": { - "description": "Size (bytes)", - "maximum": 9007199254740991, - "minimum": 0, - "type": "integer" - }, - "symlinkTarget": { - "description": "Target (symlink)", - "type": "string" - }, - "tokenEstimate": { - "description": "Est. tokens (size/4)", - "maximum": 9007199254740991, - "minimum": 0, - "type": "integer" - }, - "type": { - "description": "Type", - "enum": [ - "file", - "directory", - "symlink", - "other" - ], - "type": "string" - } - }, - "required": [ - "name", - "path", - "type", - "size", - "created", - "modified", - "accessed", - "permissions", - "isHidden" - ], - "type": "object" - }, - "ok": { - "const": true, - "type": "boolean" - } - }, - "required": [ - "ok" - ], - "type": "object" -}New value: +null
- Removed
stat_many - Removed
tree - Removed
write
TDQS
Scored across 13 tools
Each tool targets a clearly distinct file operation (read, write, edit, diff, patch, search, metadata) with explicit cross-references in the descriptions. Overlaps like edit vs replace_text are well delineated by exact-match uniqueness vs global replacement.
All names use consistent snake_case with imperative verbs (create, delete, list, read, move, stat, etc.). Multi-word names like replace_text, search_text, and find_files follow the same verb_noun pattern.
13 tools is well-scoped for a filesystem server, covering essential operations without redundancy. Each tool earns its place by handling a specific action or resource.
Core file lifecycle (create, read, update, delete, move, list, search, diff, stat) is well covered, with parent directory creation handled implicitly. Minor gaps remain for permission changes (chmod/chown) and link creation, but agents can work around most needs.
Maintenance
Related MCP Connectors
Agent-native MCP server over the public saagarpatel.dev corpus. Read-only, stateless.
Nifty's MCP server — exposes tasks, projects, messages, and files as tools for AI agents.
An MCP server that provides an API to LLMs to manage their JumpCloud resources.
Related MCP Servers
- AlicenseBqualityCmaintenanceAn MCP server that provides LLMs access to other LLMs433 npm79MIT
- -licenseNot gradedqualityNot gradedmaintenanceA Filesystem MCP server that allows an LLM to read and list files from a specified directory on your local machine through the Model Context Protocol.2-
- FlicenseNot gradedqualityDmaintenanceMCP server providing filesystem operations, shell execution, and web search capabilities.-
- AlicenseNot gradedqualityDmaintenanceExperimental MCP server for local LLM orchestration with filesystem tools (read, write, list, delete files) and a CLI agent that communicates via Ollama.6 npmISC