Skip to main content
Glama

fileTools

A robust file–editing tool suite for AI agents, exposed as a Model Context Protocol (MCP) server (and usable as a plain TypeScript library). It fixes the editing failures that plague LLM coding agents — Could not find oldString, Windows CRLF mismatches, line-number drift, ambiguous duplicate matches, and regex corruption of replacement text.

Point any MCP-capable client (opencode, Claude Desktop, …) at it and the model gets three reliable tools: viewFile, replaceFileContent, writeToFile.

Why

The built-in edit tool of most agents does an exact string match of an oldString the model reproduces from memory. On real projects that fails constantly:

  • Indentation / whitespace drift — the model guesses 2 spaces where the file has 4.

  • Windows CRLF — the read path strips \r, so the model sends LF and the exact match misses.

  • Line drift — a previous edit shifted the lines the model was targeting.

  • Ambiguity — return true; appears ten times and the wrong one gets replaced.

  • Regex corruption — String.replace() mangles replacements containing $1, $&, $`.

replaceFileContent removes all of these: matching is scoped to a [startLine, endLine] window (read first, then edit from ground truth), replacement is byte-literal, line endings are detected and preserved, writes are atomic, and on a mismatch it returns the actual current content of the range so the model corrects from reality instead of guessing.

Related MCP server: mcp-hashline-edit-server

Requirements

  • Node ≥ 23 (the server imports the TypeScript library directly via native type-stripping).

Tools

Tool

Purpose

viewFile

Read a file with 1-based line numbers and bounded slicing (startLine/endLine, byte/line caps). Always read before editing.

replaceFileContent

Replace exact targetContent within [startLine, endLine]. Preserves CRLF/LF and indentation, rejects ambiguous matches, returns a unified diff, and emits a self-correction hint on failure.

writeToFile

Create a new file or atomically overwrite/append an existing one (with overwrite protection).

Install into opencode

AI agent: this is a runbook. Do steps 1–5 exactly, in order. Do NOT skip the preflight. You CANNOT finish the install yourself — step 6 (restarting opencode) must be done by the human, because opencode loads MCP servers and permissions only at startup. End your turn by telling them to do it.

1. Preflight — Node version (hard requirement)

Run:

node --version

This server imports a TypeScript file directly, which needs Node ≥ 23.

  • v23 or newer → continue.

  • v22.6–v22.x → it works but the command must pass --experimental-strip-types (see note in step 4).

  • Older than v22.6 → STOP. Tell the human to upgrade Node, then restart this setup. Do not continue.

2. Clone and install

Pick a permanent location (NOT a temp dir — opencode will launch it on every start):

git clone https://github.com/testAccountDeltas/fileTools.git
cd fileTools
npm install

3. Get the absolute path

# macOS / Linux
pwd            # -> e.g. /Users/alex/tools/fileTools
# Windows (PowerShell)
(Get-Location).Path   # -> e.g. C:\Users\alex\tools\fileTools

The server file is <that path>/mcp-server.mjs. Use the absolute path in step 4 — never a relative one.

4. Edit the opencode config

Config file location:

  • macOS / Linux: ~/.config/opencode/opencode.json

  • Windows: %USERPROFILE%\.config\opencode\opencode.json

Merge these two keys into the existing JSON — do not overwrite the whole file:

{
  "mcp": {
    "filetools": {
      "type": "local",
      "command": ["node", "/ABSOLUTE/PATH/TO/fileTools/mcp-server.mjs"],
      "enabled": true
    }
  },
  "permission": {
    "*": "allow",
    "edit": "deny"
  }
}

Merge rules:

  • If an mcp object already exists, add the filetools entry inside it (keep the others).

  • If a permission object already exists, just add "edit": "deny" to it (keep the rest). Only add "*": "allow" if there is no permission block at all.

  • Replace /ABSOLUTE/PATH/TO/fileTools/mcp-server.mjs with the real path from step 3. On Windows use forward slashes, e.g. C:/Users/alex/tools/fileTools/mcp-server.mjs.

  • Node 22.6–22.x only: change the command to ["node", "--experimental-strip-types", "/ABSOLUTE/PATH/.../mcp-server.mjs"].

Why "edit": "deny": it removes opencode's built-in edit from the model's toolset so the model uses filetools_replaceFileContent instead. Without it, both exist and the brittle built-in may still be chosen.

5. Sanity-check the server runs

node mcp-server.mjs

Expected on stderr: filetools MCP server ready (root: ...). It then waits for stdin — press Ctrl+C to exit. If instead you see Cannot find package '@modelcontextprotocol/sdk', step 2's npm install didn't run. If you see a TypeScript/ERR_UNKNOWN_FILE_EXTENSION error, the Node version is too old (go back to step 1).

Optionally run the full smoke test:

npm run smoke   # expects "5 passed, 0 failed"

6. Hand off — the human restarts opencode

Config and MCP servers are read only at startup. Fully quit and reopen opencode (the desktop app, or stop the running opencode process and start a new session) — a window reload is not enough.

After restart, the model edits via filetools_replaceFileContent: line-range scoped, CRLF-safe, no more Could not find oldString. The server resolves relative paths against the project directory opencode launches it in.

The tools are robust on their own, but a couple of habits make the model use them flawlessly. Copy these into your agent's instructions — for opencode, your global AGENTS.md (~/.config/opencode/AGENTS.md), not a file inside this repo (a repo-local AGENTS.md would only apply while editing this repo):

- Edit files ONLY via `filetools_replaceFileContent` (and `filetools_viewFile` to read a
  range). If the built-in `edit`/`grep`/`glob` are disabled, don't call them — search file
  contents through the shell instead.
- Ground truth before every edit: immediately before `filetools_replaceFileContent`, call
  `filetools_viewFile` on the exact range — even if you read the file earlier. Context-saving
  ("don't re-read unchanged files") does NOT apply to editing; editing from memory causes
  "Could not find oldString" and line drift.
- Copy `targetContent` byte-for-byte from the `filetools_viewFile` output; never type it from
  memory. Set `startLine`/`endLine` to that range.
- On a mismatch the tool returns the real current content of the range — fix from that, don't
  guess.

Use it with other MCP clients (e.g. Claude Desktop)

{
  "mcpServers": {
    "filetools": {
      "command": "node",
      "args": ["/absolute/path/to/fileTools/mcp-server.mjs"],
      "env": { "FILETOOLS_ROOT": "/absolute/path/to/your/project" }
    }
  }
}

FILETOOLS_ROOT (or the first CLI argument) overrides the workspace root; it defaults to the process working directory.

Use it as a library

import { FileToolSuite } from "./fileTools.ts";

const tools = new FileToolSuite(process.cwd());
tools.viewFile({ targetFile: "src/app.ts", startLine: 1, endLine: 50 });
tools.replaceFileContent({
  targetFile: "src/app.ts",
  startLine: 15, endLine: 16,
  targetContent: "  const port = 3000;",
  replacementContent: "  const port = process.env.PORT || 8080;",
});

FileToolSuite.getToolDefinitions() returns JSON schemas ready for OpenAI, Anthropic, Gemini function-calling, or MCP.

Develop / test

npm test          # 17 unit tests (node:test)
npm run demo      # scripted agent walkthrough with diffs + self-correction
npm run smoke     # spins up the MCP server and exercises it over the protocol

License

MIT

Available Tools

3 tools
replaceFileContentC

Surgically replace exact targetContent inside bounded lines [startLine, endLine].

ParametersJSON Schema
NameRequiredDescriptionDefault
endLineYesEnd line of search window.
startLineYesStart line of search window.
targetFileYesPath to target file.
instructionNoWhat this edit does.
allowMultipleNoAllow replacing multiple matches.
targetContentYesExact string to be replaced.
replacementContentYesNew string to insert.

TDQS

C2.9/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full behavioral burden and falls short. It does not say what happens when targetContent is not found, when it matches multiple times (despite an allowMultiple parameter existing), whether the file must exist, or what the result looks like. Only the replacement mechanics are conveyed.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single front-loaded sentence with no padding; the core action and line-bounded scope come first. 'Surgically' is the only non-earning word, and the sentence is arguably too terse given the unimplemented behavioral gaps.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a mutation tool with 7 parameters, no annotations and no output schema, the description omits the essential behavior around multiple matches, no-match/failure handling, and the two optional parameters (instruction, allowMultiple). An agent cannot confidently predict the outcome of a call from this text alone.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

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 all seven parameters, including targetContent, startLine/endLine, allowMultiple and instruction. The description adds no syntax, format, or constraint detail beyond the schema; baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (replace) on a specific resource (file content) and adds scope: exact targetContent, bounded by [startLine, endLine]. This implicitly separates it from writeToFile (wholesale write) and viewFile (read), though it never names those siblings. 'Surgically' is flavor rather than clarification.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

There is no explicit when-to-use or when-not-to-use guidance, and no alternative tool is named despite two close siblings (writeToFile for full rewrites, viewFile for reads). The bounded-window scope hints at targeted edits, but the agent must infer that replaceFileContent is preferred over writeToFile.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

viewFileB

Read contents of a file with line numbering and bounded slicing.

ParametersJSON Schema
NameRequiredDescriptionDefault
endLineNoEnding line (1-indexed, inclusive).
maxBytesNoMax bytes allowed in output.
maxLinesNoMax lines to view at once. Default 800.
startLineNoStarting line (1-indexed, inclusive).
targetFileYesAbsolute or workspace-relative path.

TDQS

B3.2/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden. It does disclose two real behavioral traits beyond the schema: output is line-numbered and slicing is bounded. However, it says nothing about truncation when bounds are exceeded, error behavior for missing/binary files, or the default line cap (that detail lives only 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.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single front-loaded sentence with zero filler; the core action comes first and the qualifiers follow. It is efficient, though arguably it errs on the terse side for a 5-parameter tool.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a no-annotation, no-output-schema read tool with five parameters, the description is minimally adequate. It omits the interaction between maxBytes/maxLines, what happens on truncation, and any error semantics, which an agent would need to call it confidently at the edges.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the parameters (startLine, endLine, maxLines, maxBytes, targetFile) are already fully documented and the baseline is 3. The description's 'line numbering' and 'bounded slicing' phrasing only loosely connects to those params and adds no new syntax or constraint detail.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

'Read contents of a file' states a specific verb and resource, and the modifiers 'line numbering' and 'bounded slicing' narrow the behavior meaningfully. It doesn't name the siblings writeToFile/replaceFileContent, but the read-vs-write distinction is self-evident from the verb.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No when-to-use guidance, no exclusions, and no mention of the sibling tools. An agent gets no help deciding between an unbounded read and a sliced read, or when to prefer this over other file operations.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

writeToFileB

Create a new file or atomically overwrite/append to an existing file.

ParametersJSON Schema
NameRequiredDescriptionDefault
appendNoSet true to append.
overwriteNoSet true to overwrite existing file.
targetFileYesPath to target file.
codeContentYesFile content to write.
descriptionNoSummary of file creation.

TDQS

B3.1/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden, and it does add one genuine behavioral fact: writes are atomic. However it omits permission requirements, directory-creation behavior, error/failure semantics, and the precedence rule between append and overwrite, which are the traits an agent most needs for a destructive mutation.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single front-loaded sentence with zero filler, and the create-vs-modify distinction leads. It is arguably too terse for a five-parameter mutation tool, but nothing in it is wasted.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 5-parameter, no-annotation, no-output-schema mutation tool, the description leaves too much unspecified: flag interaction, behavior when the target does not exist and append is set, and failure behavior. The atomicity note is the only added behavior.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

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 all five parameters and the baseline is 3. The description ties 'atomic overwrite/append' to the two boolean flags, but adds no precedence or conflict semantics beyond the terse schema prose.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description names a specific verb+resource ('Create a new file or ... overwrite/append to an existing file') and even discloses the atomic write behavior. It is clear in isolation, but it never differentiates itself from the sibling replaceFileContent, so an agent can't tell from the description alone which mutation path to pick.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

There is no when-to-use guidance and no mention of the alternatives viewFile or replaceFileContent. The description also never explains how the append and overwrite flags interact or what happens when both are false, leaving the selection logic entirely to inference.

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. 3 tool updatesv1.0.0
    • First observedreplaceFileContent
    • First observedviewFile
    • First observedwriteToFile

TDQS

B3.4/5.0

Scored across 3 tools

Disambiguation5/5

Each tool has a clearly distinct purpose: writeToFile creates or overwrites/appends whole files, viewFile reads with line numbering, and replaceFileContent performs surgical edits. The overlap between write and replace is minimal and well-differentiated by granularity.

Naming Consistency4/5

All names use camelCase and start with a verb, which is consistent. However, writeToFile includes a preposition ('To') while the others do not, creating a minor structural deviation.

Tool Count5/5

Three tools is within the ideal 3-15 range and each tool covers a core file content operation (create/overwrite, read, modify). The set is well-scoped for a focused file manipulation server.

Completeness3/5

The surface covers create, read, and update operations, but lacks a delete operation and basic file management tools like listing or moving. This is a notable gap for a general filetools server, though the existing tools cover common content editing workflows.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables AI agents to safely explore directories, read files, search content by pattern or filename, and edit files with checksum verification and dry-run preview within sandboxed filesystem access.
    13 npm
    75
    ISC
  • A
    license
    Not graded
    quality
    D
    maintenance
    Provides hashline-based file editing using line-addressed edits and content hashes for integrity verification. It enables LLMs to perform precise file modifications while ensuring edits are rejected if the file content has changed since the last read.
    20 npm
    9
    MIT
  • A
    license
    A
    quality
    D
    maintenance
    Exposes hash-anchored file edits to MCP-compatible AI coding agents, enabling safe read and write operations with stale edit detection.
    1
    56 npm
    1
    MIT