filesystem-mcp
Filesystem MCP gives an AI assistant 14 sandboxed file tools to read, search, edit, and manage files inside folders you allow.
Explore:
list_rootsshows allowed folders;listprints a folder tree with optional sizes and pagination;statreports size, dates, type, permissions, MIME type, and token estimate without reading.Find:
find_filesmatches names/globs like**/*.test.ts;search_textgreps file contents with RE2 regex, context lines, and glob filters.Read:
readreturns files whole, by head/tail or line range, or in batches — images and audio as media, other binaries as base64.Create:
createwrites new files, appends, or makes empty directories; asks before overwriting unlessoverwrite: true.Edit:
editreplaces exact unique text (all-or-nothing, withdryRun);patchapplies a unified diff;replace_textdoes find-and-replace across one file or a whole tree.Compare:
diffreturns a unified diff between two files.Organize:
moverenames, moves, or copies files and folders;deleteremoves files, folders, or symlinks (asking first for non-empty folders).Revert:
undorolls back recent changes by undo id or the last N calls.Stay safe: writes are scoped to allowed roots, secret files (
.env, keys, credentials) are blocked and hidden,.gitignoreandnode_modulesare skipped by default, and reads can be capped by file size.
Provides filesystem access for AI assistants within the Amp development environment, enabling reading, writing, searching, diffing, and patching files through structured MCP tools.
Integrates with Codeium's Windsurf editor to give AI coding assistants secure filesystem access for reading, writing, and managing project files through structured MCP tools.
Provides containerized filesystem access for AI assistants, allowing secure file operations within Docker containers through volume mounting and isolated execution environments.
Enables AI assistants to perform filesystem operations on Node.js projects, including reading, writing, and managing JavaScript/TypeScript files with structured output for reliable parsing.
Filesystem MCP
Let your AI assistant work with your files, safely.
Read, search, edit, and patch files in the folders you choose. Secret files stay hidden, and risky changes wait for your OK.

What is this?
Model Context Protocol (MCP) is how AI apps such as Claude, GitHub Copilot in VS Code, and Cursor connect to tools. Filesystem MCP is an MCP server: a small program that runs on your computer and gives the AI 14 tools for working with files. You choose which folders it can use, and everything outside them is off limits.
Once it is connected, you can ask things like:
"Find every TODO in this repo and group them by file."
"Rename
getUsertofetchUserin all.tsfiles. Show me the diff first.""What changed between
config.dev.jsonandconfig.prod.json?""Read the last 50 lines of
server.logand explain the error.""Move the old screenshots into
archive/2025/."
Related MCP server: Filesys
Why Filesystem MCP?
It is safe by default. The AI can use only the folders you allow, and
.envfiles, private keys, and cloud credentials are blocked. The server asks you before the AI deletes a non-empty folder, opens a folder you did not allow, or writes over a file withcreateormove. Onlycreateand copies can skip that question, by passingoverwrite: true. Edits made withedit,patch, andreplace_textapply without asking, but the AI can show you the diff first withdryRun. If the AI should never change anything,--read-onlyremoves every tool that writes.Search and editing are made for code. The AI can search inside files like
grep, with a regex engine (RE2) that cannot hang, and by default the server skips.gitignored files and folders likenode_modules. Edits are exact-match replacements that return an error when the text does not match, and you can preview them as a diff first.It saves the AI's context. The AI can read many files in one call or only the lines it needs, and it can check a file's size and token estimate before reading it.
It works with any MCP client, over stdio or HTTP, on macOS, Linux, and Windows. You can install it with npx, Docker, or a one-click Claude Desktop extension, or build your own client on it.
It is private. It runs on your machine, has no telemetry, and makes no network calls.
Compared with the reference server
How this server differs from the official
@modelcontextprotocol/server-filesystem,
checked against its README on 2026-11-02:
Capability | Filesystem MCP | Reference server |
Search inside files |
| None; |
Secret files |
| Not blocked |
Overwriting a file |
|
|
Delete files |
| None |
| Respected by listing and search tools | Not supported |
Read-only mode |
| Docker |
Per-folder read-only |
| Docker |
Apply a unified diff |
| None |
Compare two files |
| None |
Replace across many files |
| None |
Watch files | Subscribe to a file and get change notifications | None |
Transport | stdio, or Streamable HTTP with | stdio |
Quick start
You need Node.js 24 or later. Check withnode --version.
Add the server to your AI app. Pick yours below.
Replace
/path/to/projectwith the folder the AI may use. You can list several folders.Restart the app and ask: "Which folders can you access?"
VS Code currently shares the folders you have open with the server, so the
one-click VS Code install works without a path. In other apps, or over HTTP,
put the folder inargs. If the AI says it has no folders, that is the fix.
Click Install in VS Code above, or add this to .vscode/mcp.json:
{
"servers": {
"filesystem": {
"command": "npx",
"args": ["-y", "@j0hanz/filesystem-mcp@latest", "/path/to/project"]
}
}
}Or from a terminal:
code --add-mcp '{"name":"filesystem","command":"npx","args":["-y","@j0hanz/filesystem-mcp@latest","/path/to/project"]}'Click Install in Cursor above, then add your folder to args. Or add this
to .cursor/mcp.json in your project, or ~/.cursor/mcp.json for all
projects:
{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": ["-y", "@j0hanz/filesystem-mcp@latest", "/path/to/project"]
}
}
}For a one-click install, download
filesystem-mcp.mcpb,
open it with Claude Desktop, and pick the folders to allow. Claude Desktop's
built-in Node.js runs it. The extension's settings also let you turn on
read-only mode and block more files.
To set it up by hand, add this to claude_desktop_config.json
(Settings → Developer → Edit Config):
{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": ["-y", "@j0hanz/filesystem-mcp@latest", "/path/to/project"]
}
}
}claude mcp add filesystem -- npx -y @j0hanz/filesystem-mcp@latest /path/to/projectOr install the plugin, which points the server at your current project:
/plugin marketplace add j0hanz/j0hanz-marketplace
/plugin install filesystem-mcp@j0hanz-marketplaceAdd this to .vs\mcp.json in your solution folder, or %USERPROFILE%\.mcp.json
for all solutions:
{
"servers": {
"filesystem": {
"command": "npx",
"args": ["-y", "@j0hanz/filesystem-mcp@latest", "C:/path/to/project"]
}
}
}The filesystem-mcp plugin sets the server up for your current project:
Client | Install |
Copilot CLI |
|
Antigravity CLI |
|
The container can only see the folders you mount. This setup blocks writes
twice, with the :ro mount and with the --read-only flag.
{
"mcpServers": {
"filesystem": {
"command": "docker",
"args": [
"run",
"-i",
"--rm",
"-v",
"/path/to/project:/workspace:ro",
"ghcr.io/j0hanz/filesystem-mcp:latest",
"--read-only",
"/workspace"
]
}
}
}Drop :ro and --read-only to let the AI make changes. VS Code and Visual
Studio use "servers" instead of "mcpServers". See
Running in Docker for more.
Windsurf, Cline, and most other clients use the same mcpServers JSON as
Claude Desktop above. In any client, the server is:
command:
npxargs:
-y,@j0hanz/filesystem-mcp@latest, then one or more folders
You can also install it globally and run filesystem-mcp /path/to/project:
npm install -g @j0hanz/filesystem-mcpTools
Tool | What it does |
| Shows the folders the server may use. |
| Lists a folder as a tree, like |
| Finds files by name or glob, such as |
| Searches inside files for text or a regex, like |
| Gets size, dates, type, permissions, and a token estimate without reading the file. |
| Reads text files whole or by lines, head, or tail. Images and audio come back as media; others with |
| Compares two files and returns a unified diff. |
| Writes new files, appends, or makes empty folders. Asks before replacing a file, unless |
| Replaces exact text in files. All edits to a file apply, or none do. |
| Applies a unified diff to a file. All hunks apply, or none do. |
| Finds and replaces text or a regex across many files. |
| Moves, renames, or copies files and folders. Asks before overwriting, unless a copy passes |
| Deletes files and folders. Asks before deleting a non-empty folder. |
| Reverts recent changes by undo id or the last N calls, for 30 minutes while the server runs. Skips files changed since. |
✎ changes files. --read-only removes these tools. To refuse changes under
one folder while the rest stay writable, pass --read-only-root <dir>
(repeatable, or FS_READ_ONLY_DIRS): those tools still exist, but a call
that writes, moves, or deletes under the folder fails with
Read-only root: ..., while listing, searching, and reading keep working.
Search and listing tools skip hidden files, .gitignored files, and folders
like node_modules, dist, and .git unless the AI asks for them.
Configuration
Most people only need the folder argument. These options cover the common cases:
Option | What it does |
| Removes every tool that changes files. |
| Refuses writes, moves, and deletes under this folder, which stays readable. Repeatable. |
| Blocks more files, for example |
| Unblocks one built-in secret pattern, for example |
| Also allows the folder the server was started from. |
| Largest file |
| Serves over HTTP at |
| Prints the settings the server would use, then exits. |
Flags go in args after the package name, for example
["-y", "@j0hanz/filesystem-mcp@latest", "--read-only", "/path/to/project"].
The full configuration reference covers every flag and environment variable, the complete secret-file list, limits, HTTP setup with API keys, Docker, and troubleshooting.
Security
Protection | How it works |
Folder sandbox | The server resolves every path, including symlinks, and the resolved path must stay inside an allowed folder. |
Secret files |
|
You stay in charge | The server asks you before the AI deletes a non-empty folder, gets access to a new folder, or writes over a file with |
Off-limits folders | Neither the AI nor the client can ever add your home folder itself, system folders, or |
Safe writes | New content goes to a temporary file that is then renamed into place, so a crash never leaves a half-written file. Writes keep the file's permissions. |
No regex hangs | RE2 runs in linear time, so no search pattern can freeze the server. |
HTTP | The server listens only on localhost by default. Any other address requires an API key. |
Container | The Docker image runs as a non-root user. |
If you find a vulnerability, please report it privately. SECURITY.md explains how.
Build your own client
You can also call Filesystem MCP from your own code: an agent, an editor plugin, a web app, a CI job, or a script. The same rules apply as for an AI app, so your code cannot reach outside the allowed folders or read secret files.
import { Client } from '@modelcontextprotocol/client';
import { StdioClientTransport } from '@modelcontextprotocol/client/stdio';
const dir = '/path/to/project';
const client = new Client(
{ name: 'my-app', version: '1.0.0' },
{ capabilities: { elicitation: { form: {} } }, versionNegotiation: { mode: 'auto' } },
);
client.setRequestHandler('elicitation/create', async () => ({ action: 'decline' }));
await client.connect(
new StdioClientTransport({
command: 'npx',
args: ['-y', '@j0hanz/filesystem-mcp', dir],
cwd: dir,
}),
);
const result = await client.callTool({ name: 'search_text', arguments: { searchPattern: 'TODO' } });
const { matches } = (result.structuredContent ?? result._meta) as { matches: unknown[] };
console.log(matches);
await client.close(); // stops the server process; without it the script never exitsThe basics:
Where the data is. The text block is written for a model. The same data as JSON is in
_metafor tools that write their own text (list,search_text,edit, ...) and instructuredContentforstat,create, andlist_roots.readis the exception: the file's text is only in the text block, and_metaholds metadata about it.Paths. A relative path resolves against the server's working directory when that is inside a root, and against the root otherwise. With several roots, it must exist under exactly one of them. Absolute paths are never ambiguous. Search results are printed relative to the root, so a result can be passed straight back. A name that differs from the one on disk only in Unicode form (NFC or NFD) or in its space characters (U+00A0, U+202F) finds that entry.
Confirmations. Overwrites, recursive deletes, and paths outside the roots are questions for the user. Declare the
elicitationcapability and answer them in a handler, or, on the 2026-07-28 protocol, take them as data (input_required) and answer later.Protocol versions. The server speaks the 2025 protocol and 2026-07-28, over stdio and Streamable HTTP. Over HTTP, 2025-era clients get no confirmations or change notifications.
Resources. Read and subscribe to any file as
filesystem-mcp://file/{+path};internal://instructionsand theget-helpprompt hold the server's guide for models.
The client guide has the details, tested with the
TypeScript and Python SDKs, and examples/ has six runnable
clients:
Example | What it is |
Any tool from your shell, over stdio or HTTP; | |
A local web UI where the server's questions appear in the page | |
| |
A coding agent that shows each change's diff and waits for your y/N | |
Runs a task through a model whenever the workspace changes | |
A TODO report for a workspace, with the Python SDK |
Privacy policy
Filesystem MCP runs entirely on your machine. This policy covers the npm
package, the Docker image, and the .mcpb desktop extension.
Data collection: none. The server has no telemetry, analytics, or crash reporting, and makes no outbound network requests.
Use and storage: the server reads and writes files only inside the folders you allow, and only when your MCP client calls a tool. Tool results go to that client and nowhere else. Short-lived result caches and the undo history (saved file contents) live in memory and disappear when the server exits.
Third-party sharing: none by this server. Your MCP client may send tool results to its model provider under that client's own privacy policy.
Retention: the server keeps nothing after the process exits. Diagnostic logs go to stderr on your machine; your MCP client may save them in its own log files.
Contact: open an issue at https://github.com/j0hanz/filesystem-mcp/issues, or report security problems privately through GitHub Security Advisories.
Contributing
Bug reports, ideas, and pull requests are welcome. Start with CONTRIBUTING.md. It covers setup, running the server from source, and the checks a pull request needs.
If Filesystem MCP is useful to you, a star on GitHub helps other people find it.
License
Available Tools
14 toolscreateCreate FilesADestructive
Write whole text files (create new ones, overwrite, or append) or make empty directories. Missing parent directories are created. edit or patch changes part of an existing file.
| Name | Required | Description | Default |
|---|---|---|---|
| files | No | List of files to create (max 100); each entry requires path and content; combined content is capped at the file-size limit | |
| directories | No | Empty directories to create, like mkdir -p; one that already exists is left as it is |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=false and destructiveHint=true, so the safety profile is covered. The description adds genuinely useful behavior beyond that: missing parent directories are created automatically, and the tool writes verbatim content. It omits the confirmation/overwrite interaction, but that is in the schema.
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 tight sentences with zero filler; the capability and mode list come first and the disambiguation from edit/patch is front-loaded rather than buried.
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?
With no output schema, the description still covers the core write behaviors and the sibling boundary adequately, and detailed constraints (caps, path format, confirmation) live in the fully-covered schema. The remaining gap is that nothing is said about what happens on failure or what a call returns.
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 both parameters are richly documented (append vs. overwrite semantics, the non-empty absolute path requirement, the 100-item and size caps). The description's 'create new ones, overwrite, or append' largely restates what the schema's append/overwrite fields already say, so the baseline 3 is correct.
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 ... or make empty directories') and enumerates the supported modes (create, overwrite, append). It explicitly distinguishes itself from the overlapping siblings edit and patch by scoping them to partial-file changes.
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 second sentence gives a clear when-not rule: partial modifications belong to edit or patch, so whole-file writes belong here. It does not, however, say anything about how append vs. overwrite should be chosen or that a plain overwrite triggers a confirmation prompt, decisions an agent must get right.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
deleteDelete FileADestructive
Delete files, directories, or symlinks, like rm or rm -r. Paths are exact; globs are not expanded. undo reverts a delete whose result gives an undo id.
| 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 declare destructiveHint=true and openWorldHint=false, so safety is covered. The description adds genuinely useful behavioral detail beyond that: exact-path semantics with no glob expansion (a real footgun) and the fact that a successful result yields an undo id reversible via undo.
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 dense sentences with zero filler; the operation and its rm analogy are front-loaded, followed by the two most important behavioral caveats (no globs, undo id).
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 with full annotations and no output schema, the description covers the key call-time concerns: path exactness, recursion, and reversibility via undo. It trusts the schema for flag semantics, which is reasonable given 100% coverage, though it could note failure behavior on non-existent paths.
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 three parameters are already fully documented, including recursive and ignoreIfNotExists defaults. The description only implicitly maps 'rm -r' to recursive and 'paths are exact' to the path array, adding little beyond the schema baseline.
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 (delete) and the exact resource types (files, directories, symlinks), and anchors it with a comparison to rm/rm -r so the agent immediately knows the operation's scope. This distinguishes it from siblings like move, undo, and edit.
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?
'like rm or rm -r' plus the note that globs are not expanded gives clear guidance on expectations and the recursive flag's role. It also points to undo for reverting, but does not explicitly state when to prefer this over siblings such as move or when deletion should be avoided.
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. Identical files give no hunks; binary and non-UTF-8 files are refused.
| 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 cover read-only and closed-world behavior. The description adds useful behavioral detail beyond that: output is a unified diff, identical files produce no hunks, and binary/non-UTF-8 inputs are refused.
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 tightly written sentences with no filler. The main behavior is front-loaded, and the edge cases are stated compactly.
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 simple read-only diff tool with fully described parameters and annotations covering safety, the description provides enough context: what it returns, how identical files behave, and what inputs are rejected.
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 parameters a, b, and context are already documented. The description adds the directional 'from a to b' framing but does not provide additional syntax or semantic 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: compare two text files and return a unified diff from a to b. The 'like diff -u' analogy and mention of identical/binary handling make the tool's identity clear and distinguish it from siblings like read or search_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 clearly establishes the use case: comparing two text files. It also gives exclusions by noting that binary and non-UTF-8 files are refused, but it does not explicitly name sibling alternatives or explain when to prefer them over this tool.
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. Pass path with edits, or files for a batch; never both. 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 (required with path); not allowed with 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; newText is re-indented to the match and replaces its inner blank lines |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already flag this as destructive and non-read-only, so the description's job is to add specifics — and it does: 'Each oldText must match exactly once, and a file is written only if all its edits match,' which discloses uniqueness constraints and per-file all-or-nothing atomicity. It omits failure reporting details (partially covered by the schema's mention of line numbers) and says nothing about dryRun, which is the safety valve for a destructive write.
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?
Four short sentences, zero waste, front-loaded with the core mechanism before the mode-selection rule and the matching constraint. Each sentence contributes a distinct fact an agent needs.
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 five-parameter destructive mutation with no output schema, the description covers mechanism, mode exclusivity, match uniqueness, and per-file atomicity — the essentials. Gaps remain on failure/rollback behavior across multiple files and on when to reach for dryRun, both of which matter for a tool annotated destructiveHint=true.
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 already documents path, edits, files, dryRun, and ignoreWhitespace in detail. The description restates the path/edits vs files exclusivity and the match-once rule, adding only the 'never both' framing beyond structured data. Baseline 3 is appropriate when the schema carries the semantic load.
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 ('Edit text files in place by replacing exact oldText with newText') plus an analogy ('like str_replace') that pins down the mechanism instantly. It also names the sibling it differs from — 'replace_text replaces every occurrence across files' — so the agent can distinguish the two without opening either schema.
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 gives the two calling modes and the exclusion: 'Pass path with edits, or files for a batch; never both.' It also routes the agent to replace_text for the global-replace case. It stops short of covering other plausible alternatives (patch, create, undo) or when to prefer dryRun, so it is clear context rather than full when/when-not guidance.
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 root, ready to pass to read. 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 establish readOnlyHint=true and openWorldHint=false, so the safety profile is covered. The description adds meaningful non-annotation context: results are relative to the root and directly consumable by read, and pattern-without-slash matches at any depth. It omits pagination/snapshot expiry, though the cursor schema documents that.
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 short sentences, zero filler. Purpose and return value are front-loaded, and the depth rule and sibling routing follow in the order an agent needs them.
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 an 8-parameter tool with no output schema, the description supplies the essentials: what comes back, how patterns behave, and where to go for content search. Pagination, hidden/ignored defaults, and depth limits live in the schema, so nothing critical is missing, though a note about paging large result sets would close the loop.
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 a 3 is the baseline. The description earns above baseline by explaining glob matching semantics that the schema does not — the "no / matches at any depth" rule is a real behavioral detail an agent cannot infer from the pattern field alone.
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 ("Find files by name or glob pattern") and immediately clarifies the return shape (paths relative to root) and downstream use ("ready to pass to read"). It also names the sibling search_text and its distinct domain, so an agent can differentiate without opening sibling 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 routes content searching to search_text, which is the most likely confusable alternative. It does not cover when to prefer find_files over list or stat, and offers no exclusions for the path/maxDepth options, so routing is clear but not exhaustive.
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, one level deep unless maxDepth is raised. Hidden entries are skipped unless includeHidden is set, and ignored ones (.gitignore matches, node_modules, dist, build, out, tmp) unless includeIgnored is set. includeSizes adds sizes and a total; stat returns dates; find_files searches by name pattern.
| 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. | |
| sortBy | No | Order within each directory: name (default) or size (largest first) | name |
| 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. | |
| includeSizes | No | Show file sizes in the tree and a totals line of counts and bytes | |
| 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 and openWorldHint=false, so safety is covered. The description adds useful behavioral context: hidden entries are skipped by default, ignored patterns (.gitignore, node_modules, dist, build, out, tmp) are excluded unless includeIgnored is set, and maxDepth defaults to one level. It doesn't discuss pagination or cursor expiry, but that is in the schema.
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 front-loaded with the core behavior and default depth, then covers exclusions, then optional features. The final sentence mixes sibling-tool functions ('stat returns dates; find_files searches by name pattern') which is slightly off-tool but still useful for routing; overall it is efficient with little waste.
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?
With 8 optional parameters, 100% schema coverage, no output schema, and clear annotations, the description provides enough context for correct invocation: it explains default depth, exclusions, and size totals. Pagination details live in the schema, so no critical gap remains, though the return format could be slightly more explicit.
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. The description earns a higher score by clarifying the effect of parameters: 'unless maxDepth is raised', 'unless includeHidden is set', 'unless includeIgnored is set', and 'includeSizes adds sizes and a total'. This adds practical meaning beyond the schema's technical 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?
States a specific verb+resource ('List a directory's files and subdirectories as a tree of names') and explicitly contrasts with sibling tools 'stat' and 'find_files' in the same breath. An agent can distinguish this from other file-listing/search tools 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?
The description routes the agent: use this for directory trees, use 'stat' for dates, use 'find_files' for name-pattern search. It does not mention when to prefer 'list_roots' or when-not to use this tool, but the primary alternatives are clearly named.
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. Directories marked read-only appear in readOnlyDirs; writes, moves, and deletes under them are refused. 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?
Beyond readOnlyHint=true and openWorldHint=false, the description discloses that read-only roots are segregated into readOnlyDirs and that writes, moves, and deletes under them are refused — a concrete consequence an agent would not otherwise know. It stops short of describing ordering, empty-list behavior, or error modes.
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 short sentences, front-loaded with what is returned, then the read-only caveat, then the grant path. Each sentence carries distinct, actionable information with no repetition of the annotations.
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?
With no output schema, the description does the work of explaining that results are absolute paths and that read-only entries land in a separate readOnlyDirs collection. That is nearly sufficient, though the exact response shape (single list vs. two collections) remains slightly ambiguous.
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 takes zero parameters, so there is nothing for the description to disambiguate; the baseline of 4 applies. Nothing about the description misrepresents the parameter surface.
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 ('List the directories this server can access') plus the return form ('as absolute paths'). This clearly separates it from the file-content siblings such as list, stat, and find_files, which operate on entries rather than access roots.
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?
Usage is implied: it says session-granted paths are included and that other tools can request access to paths outside these roots, which hints at calling this first to discover scope. However, it never states explicitly when to call it versus alternatives, nor any when-not condition.
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. undo reverts a move whose result gives an undo id; a copy cannot be undone.
| 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?
Goes well beyond the annotations (which only flag destructiveHint=true and readOnlyHint=false) by disclosing implicit side effects: missing parent directories are created, moves yield an undo id, and copies are irreversible. That reversibility information is exactly what an agent needs before invoking a destructive operation.
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, zero waste, with the core verb/resource and the most error-prone semantic (destination = full path) front-loaded. 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 destructive batch mutation with annotations present and no output schema, the description covers path semantics, parent creation, and undo/irreversibility. It leaves batch-size limits and overwrite defaults to the schema, which is acceptable but slightly incomplete for the destructive path.
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 adds real meaning beyond the schema's terse 'Destination path' by clarifying it is the full new path, not a containing folder. Copy vs move semantics are reinforced, though overwrite behavior is left to 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 set (move, rename, copy) against a specific resource (files and directories) and anchors it with the mv / cp -r analogy. This clearly separates it from siblings like delete, create, and patch.
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?
Explains the key semantic that destinations are full new paths rather than folders, and routes the agent to the undo sibling for reverting a move, plus notes copies cannot be undone. It stops short of stating when to prefer this over e.g. create or replace_text, but the guidance is otherwise concrete.
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; pass binary: true to get any other binary file whole as a base64 embedded resource.
| 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 | |
| binary | No | Return a binary file that is not an image or audio whole, as a base64 embedded resource. Full reads only. | |
| endLine | No | End line (1-indexed); requires startLine | |
| 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?
Annotations already declare readOnlyHint=true and openWorldHint=false, so the safety profile is covered. The description adds real behavioral value beyond that: images and audio come back as media, other binaries require binary: true and return as a base64 embedded resource, and binary reads are full reads only. Return-format behavior is exactly what an agent needs before calling.
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, no waste, front-loaded with the primary whole-file behavior before the mode and media qualifiers. Every clause carries information an agent needs.
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 an 8-parameter, annotation-backed tool with no output schema, the description covers the decision-relevant surface: text vs image/audio vs other binary, whole vs slice, and the full-read restriction on binary. Remaining details (batch paths, hash option) are adequately documented in the schema itself.
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 and the schema carries per-parameter meaning. The description adds semantics the schema does not spell out: that the slice parameters select 'one slice' (implying they are alternatives, not combinable) and that binary is incompatible with slicing. It does not touch path/paths batch semantics or includeHash, which the schema covers.
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 ('Read text files, like cat') and enumerates the three read modes plus media/binary handling, so an agent immediately knows this is a content-retrieval tool distinct from list, stat, or search_text. It stops short of naming any sibling explicitly, so differentiation is inferred from function rather than stated.
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 selection context for modes: whole read by default, one slice via head, tail, or startLine/endLine, and binary: true only for non-media binaries. It does not state when to prefer this over siblings like search_text or find_files, nor any exclusion conditions, so it is clear context without routing guidance.
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) | |
| maxMatches | No | Maximum total match count across all files before stopping (default: 100) | |
| maxResults | No | Deprecated alias of maxMatches; removed in the next release | |
| 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?
Annotations already declare destructiveHint=true and readOnlyHint=false, so the safety profile is covered; the description adds real behavioral context the annotations cannot: in-place rewriting ("like sed -i") and the fact that the pattern spans lines and that ^/$ anchor to file start/end rather than line boundaries. It does not state irreversibility or that `undo` is the recovery path, which is a remaining gap for a destructive tool.
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 sentences, front-loaded with the action and scope, then matching semantics, then the sibling differentiation. Every sentence adds information; nothing is boilerplate.
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, 15-parameter bulk rewrite tool with no output schema, the definition covers what it does, matching semantics, and the sibling alternative, while the schema handles per-parameter and return-shape detail (returnDiff). It would be complete at 5 if it flagged the irreversibility/dryRun-first practice in the description given how damaging a wide-scope run is.
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 15 parameters are already documented (including dryRun, maxMatches, casing, hidden/ignored files). The description adds only the isRegex literal-vs-regex distinction and the path/glob scoping, which the schema already carries. Baseline 3 is appropriate.
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+resource (find and replace) with precise scope: literal or RE2 regex, one file or a directory tree, glob-filtered. It also distinguishes itself from the sibling `edit` ("edit replaces one unique exact match"), so an agent can choose without opening either schema.
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 closing sentence routes multi-match work here versus single-unique-match work to `edit`, and "optionally filtered by glob" plus the sed analogy imply the bulk-edit use case. It stops short of explicit exclusions (e.g., prefer `search_text` first, or `diff` to verify) and never mentions dryRun in the description itself, so it is clear context rather than a full when/when-not map.
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 root, ready to pass to read. searchPattern is the text to find, matched within one line; pattern filters files by glob. 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?
Annotations already declare readOnlyHint=true and openWorldHint=false, so the safety profile is covered. The description adds genuine value by disclosing the return shape (matching lines with line numbers and root-relative paths) and that matching is per-line. It omits pagination behavior and the cursor snapshot expiry, though the schema covers those.
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 dense sentences, front-loaded with the core action and the most confusable parameter distinction. Every clause eliminates a likely mis-invocation; nothing is 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 an 11-parameter tool with no output schema, the description covers purpose, return shape, and the key sibling boundary, which is enough to call it correctly. It leaves pagination and the ~60s snapshot expiry to the schema, a minor omission given the description's scope.
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?
With 100% schema coverage the baseline is 3, but the description earns more: it clarifies that searchPattern is matched within a single line and that 'pattern' is a file glob, not the content pattern — a naming ambiguity the schema alone leaves easy to misread. It also implies path/file-vs-directory inheritance from 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 ('Search file contents'), names both modes (literal text / RE2 regex) with a grep analogy, and explicitly differentiates from the sibling find_files ('find_files matches file names'). An agent can distinguish this from every other sibling without opening a schema.
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 routing: use this for contents, find_files for names, and the output is 'ready to pass to read', which establishes the follow-up workflow. It stops short of exclusion rules (e.g., when not to use it on huge trees, or how it relates to replace_text for edits), so not a full 5.
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 (files) or entryCount (directories; secret files not counted), tokenEstimate, timestamps, permissions (readOnly on Windows), MIME type guessed from the extension, and symlink target. Also checks whether paths exist: each missing path gets its own NOT_FOUND entry.
| 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?
Beyond the readOnlyHint annotation, the description discloses relevant behavior: no content reads, secret files excluded from directory entry counts, Windows-specific readOnly behavior, MIME type guessed from extension, symlink target reporting, and per-path NOT_FOUND entries. This is substantive operational context for an agent.
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 front-loaded with the core operation and then efficiently packs the relevant metadata fields and existence-check behavior into two sentences. There is no filler; every clause adds useful scope or behavior.
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?
There is no output schema, so the description carries the return-value burden and it does so by enumerating key metadata fields and NOT_FOUND behavior. Combined with the readOnly annotation and complete schema documentation, this is sufficient for calling 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?
With 100% schema description coverage, the schema already documents the single-path and batch-path parameters and their mutual exclusivity. The description adds only general references to 'paths' and missing-path entries, without parameter-specific syntax or rules beyond what the schema provides.
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 operation: retrieve path metadata without reading file contents, explicitly contrasting with content-reading tools. It enumerates the metadata returned and mentions directory entry counts and existence checks, making it clear how this differs from read/list-style 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?
It gives clear usage context: use this for metadata and existence checks rather than reading contents. However, it does not explicitly name alternative sibling tools or state when-not to use it beyond the implied contrast with reading contents.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
undoUndoADestructive
Revert earlier calls that changed files, by undo id or the last N calls. A file is restored only if unchanged since. dryRun lists the history.
| Name | Required | Description | Default |
|---|---|---|---|
| id | No | The undo id from a tool result | |
| steps | No | Revert the last N calls (not over HTTP) | |
| dryRun | No | Preview which calls would restore, changing nothing |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already mark the tool as destructive and non-read-only. The description adds important behavioral nuance beyond that: a file is restored only if unchanged since the call, and dryRun lists history without modifying anything. It stops short of explaining conflict handling or result format, but the key safety behavior is disclosed.
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 short sentences, front-loaded with the core action and followed by the key conditional behavior and preview option. Every sentence carries useful information with no waste.
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?
Given a destructive mutation tool with no output schema, the description covers the essential behaviors: what gets reverted, the conditional restore rule, and dryRun preview. It leaves minor gaps such as how id and steps interact or what happens when files have changed, but 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?
Schema description coverage is 100%, so all three parameters are already documented in the schema. The description reinforces the id-vs-steps selection and clarifies that dryRun lists history, but adds little 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?
The description states a specific verb and resource: revert earlier calls that changed files. It clearly distinguishes the operation from sibling tools like edit, replace_text, or diff by focusing on undoing prior file-changing calls.
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 context for when to use the tool (reverting changed files) and mentions both selection modes: by undo id or by last N calls. It does not explicitly exclude alternatives or name sibling tools, but the usage scenario is unambiguous.
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.13.0- Changed
edit1 field changed- changed
Input schema / properties / ignoreWhitespace / descriptionPrevious value: -"Ignore leading/trailing whitespace differences when matching oldText"New value: +"Ignore leading/trailing whitespace differences when matching oldText; newText is re-indented to the match and replaces its inner blank lines"
1 tool update
v2.12.1- Changed
replace_text4 fields changed- added
Input schema / properties / maxMatchesAdded value: +{ + "description": "Maximum total match count across all files before stopping (default: 100)", + "maximum": 10000, + "minimum": 1, + "type": "integer" +} - removed
Input schema / properties / maxResults / defaultRemoved value: -100 - added
Input schema / properties / maxResults / deprecatedAdded value: +true - changed
Input schema / properties / maxResults / descriptionPrevious value: -"Maximum total match count across all files before stopping"New value: +"Deprecated alias of maxMatches; removed in the next release"
1 tool update
v2.10.0- Added
undo
5 tool updates
v2.9.1- Changed
create2 fields changed- added
Input schema / properties / directoriesAdded value: +{ + "description": "Empty directories to create, like mkdir -p; one that already exists is left as it is", + "items": { + "description": "File or directory path inside an allowed workspace root.", + "maxLength": 4096, + "minLength": 1, + "type": "string" + }, + "maxItems": 100, + "minItems": 1, + "type": "array" +} - removed
Input schema / requiredRemoved value: -[ - "files" -]
- Changed
edit2 fields changed- removed
Input schema / oneOfRemoved value: -[ - { - "required": [ - "path", - "edits" - ] - }, - { - "required": [ - "files" - ] - } -] - changed
Input schema / properties / edits / descriptionPrevious value: -"Replacements applied to path; not allowed when using files"New value: +"Replacements applied to path (required with path); not allowed with files"
- Changed
list2 fields changed- added
Input schema / properties / includeSizesAdded value: +{ + "default": false, + "description": "Show file sizes in the tree and a totals line of counts and bytes", + "type": "boolean" +} - added
Input schema / properties / sortByAdded value: +{ + "default": "name", + "description": "Order within each directory: name (default) or size (largest first)", + "enum": [ + "name", + "size" + ], + "type": "string" +}
- Changed
read4 fields changed- removed
Input schema / dependentRequiredRemoved value: -{ - "endLine": [ - "startLine" - ] -} - removed
Input schema / oneOfRemoved value: -[ - { - "required": [ - "path" - ] - }, - { - "required": [ - "paths" - ] - } -] - added
Input schema / properties / binaryAdded value: +{ + "default": false, + "description": "Return a binary file that is not an image or audio whole, as a base64 embedded resource. Full reads only.", + "type": "boolean" +} - changed
Input schema / properties / endLine / descriptionPrevious value: -"End line (1-indexed)"New value: +"End line (1-indexed); requires startLine"
- Changed
stat1 field changed- removed
Input schema / oneOfRemoved value: -[ - { - "required": [ - "path" - ] - }, - { - "required": [ - "paths" - ] - } -]
4 tool updates
v2.8.1- Changed
edit11 fields changed- removed
Input schema / $defsRemoved value: -{ - "EditSpec": { - "additionalProperties": false, - "properties": { - "newText": { - "description": "Replacement text. Use an empty string to delete the matched oldText.", - "examples": [ - "const x = 2;", - "function newName(", - "" - ], - "type": "string" - }, - "oldText": { - "description": "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.", - "examples": [ - "const x = 1;", - "function oldName(" - ], - "minLength": 1, - "type": "string" - } - }, - "required": [ - "oldText", - "newText" - ], - "type": "object" - } -} - removed
Input schema / properties / edits / items / $refRemoved value: -"#/$defs/EditSpec" - added
Input schema / properties / edits / items / additionalPropertiesAdded value: +false - added
Input schema / properties / edits / items / propertiesAdded value: +{ + "newText": { + "description": "Replacement text. Use an empty string to delete the matched oldText.", + "examples": [ + "const x = 2;", + "function newName(", + "" + ], + "type": "string" + }, + "oldText": { + "description": "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.", + "examples": [ + "const x = 1;", + "function oldName(" + ], + "minLength": 1, + "type": "string" + } +} - added
Input schema / properties / edits / items / requiredAdded value: +[ + "oldText", + "newText" +] - added
Input schema / properties / edits / items / typeAdded value: +"object" - removed
Input schema / properties / files / items / properties / edits / items / $refRemoved value: -"#/$defs/EditSpec" - added
Input schema / properties / files / items / properties / edits / items / additionalPropertiesAdded value: +false - added
Input schema / properties / files / items / properties / edits / items / propertiesAdded value: +{ + "newText": { + "description": "Replacement text. Use an empty string to delete the matched oldText.", + "examples": [ + "const x = 2;", + "function newName(", + "" + ], + "type": "string" + }, + "oldText": { + "description": "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.", + "examples": [ + "const x = 1;", + "function oldName(" + ], + "minLength": 1, + "type": "string" + } +} - added
Input schema / properties / files / items / properties / edits / items / requiredAdded value: +[ + "oldText", + "newText" +] - added
Input schema / properties / files / items / properties / edits / items / typeAdded value: +"object"
- Changed
read2 fields changed- changed
Input schema / properties / endLine / maximumPrevious value: -100000New value: +2147483647 - changed
Input schema / properties / startLine / maximumPrevious value: -100000New value: +2147483647
- Changed
replace_text1 field changed- removed
Input schema / properties / searchPattern / examplesRemoved value: -[ - "TODO", - "function\\s+(\\w+)", - "import.*from" -]
- Changed
search_text1 field changed- removed
Input schema / properties / searchPattern / examplesRemoved value: -[ - "TODO", - "function\\s+(\\w+)", - "import.*from" -]
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 14 tools
Each tool has a clearly distinct operation, and the descriptions explicitly distinguish the easily confused ones: edit vs replace_text vs patch, search_text vs find_files, and read vs stat vs list. There are no overlapping tools that would plausibly cause misselection.
All names use consistent lower snake_case and are either concise verbs (read, create, delete, move, undo) or verb_noun forms (search_text, find_files, list_roots). No mixed conventions or vague naming appear.
At 14 tools, the surface is well scoped for a filesystem server: core file operations, discovery, comparison, patching, and undo each earn a place. There is no obvious redundancy that should be collapsed.
The set covers the full lifecycle: listing/root discovery, reading, creating, editing, patching, moving/copying, deleting, searching, metadata, diffing, and undo. Missing niche operations like chmod or symlink creation are minor and not required for the apparent text-file-focused scope.
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 LLMs444 npm81MIT
- -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.2 npmISC