mcp-fstools
by devrandom
README.md
# mcp-fstools
Minimal MCP server that exposes **opencode-style** file tools
(`read` / `edit` / `write`) over stdio. Designed for models that handle a
small, structured schema better than a free-form patch grammar.
## Why this exists
Alternatives tried:
- **`codex-rs` `apply_patch` shell command** — the model has to compose a
custom multi-line patch grammar (`*** Begin Patch` / `*** Update File:`
/ `-old` / `+new` / `*** End Patch`) inside a shell argument. Smaller
models stumble on this format.
- **`mcp-workspace`** (Python, stdio) — exposes the same opencode shape
but enforces two extra boundaries the host already covers: a
`--project-dir` filter and a `.gitignore` filter that blocks reading
common ignored files (`target/`, `.env`, etc.).
This server keeps the opencode tool shape and drops the extra
boundaries, so models get a familiar three-field schema and can reach
every file the OS sandbox allows.
## Tools
| Name | Args | Notes |
|--------|-----------------------------------------------|--------------------------------------------------------------------|
| `read` | `path`, `offset?`, `limit?`, `max_chars?` | Line-numbered output; defaults 100 lines / 10,000 chars, up to 2,000 lines / 100,000 chars; records file hash for must-read-first. |
| `edit` | `filePath` / `file_path`, `oldString` / `old_string`, `newString` / `new_string` | Exact match; must be unique; must-read-first enforced. |
| `write`| `filePath` / `file_path`, `content` | Atomic full-file write; creates parent dirs. |
## Read limits
`read` is bounded so one call can't flood the model's context. By default
it returns at most **100 content lines** and **10,000 content characters**
(plus a short paging hint). The agent can request more by passing `limit`
(up to 2,000 lines) and `max_chars` (up to 100,000 chars); when only
`limit` is given, `max_chars` defaults to 100 per line, capped at 100,000
chars. A read that hits either limit or needs more lines ends with a hint
like `call read(offset=N) to continue`; the model pages through large
files with `offset`.
`edit` mirrors opencode's contract:
1. You must call `read` on the same file first in the session.
2. `oldString` must appear **exactly once** in the current file content.
3. The file must not have changed since the last `read` *or* since the
last successful `edit`/`write` on that file (hash mismatch → fail).
The hash check runs before the `oldString` check, so a stale edit
against a changed file reports "file changed" rather than the
misleading "oldString not found".
## JSON-RPC arg names
Tool calls accept either casing — pick whichever feels natural. The
schema `tools/list` reports uses camelCase (MCP convention), but the
server also accepts snake_case at call time, so all of these are
equivalent for `edit`:
- `filePath` / `file_path`
- `oldString` / `old_string`
- `newString` / `new_string`
If a Pydantic error names a field as missing, check both spellings
before assuming truncation — that's the diagnostic FastMCP surfaces
when an unknown key is dropped.
## Sandbox
None at the application layer. The host (e.g. Codex) provides the
OS-level sandbox (Seatbelt/landlock) which already wraps the spawned
subprocess. This server intentionally does *not* enforce a
`--project-dir` boundary or a `.gitignore` filter.
## Install
```bash
# First install
uv tool install .
# After source changes — use --reinstall (not --force)
uv tool install --reinstall .
```
Both commands write outside the default Codex sandbox scope
(`~/.local/share/uv/tools/`, `~/.cache/uv/`), so run with
`sandbox_permissions: "require_escalated"`. See `AGENTS.md` for the
why behind `--reinstall`.
Entry point: `mcp-fstools` (stdio MCP server).
## Wire into Codex
In `~/.codex/config.toml`:
```toml
[mcp_servers.mcp_fstools]
command = "mcp-fstools"
default_tools_approval_mode = "approve"
```
Restart Codex after the install. To verify, run a `read` and an `edit`
in a fresh session — both should succeed without a permission prompt.
TDQS
A4.2/5.0
Scored across 3 tools
Disambiguation5/5
Each tool has a clear, distinct purpose: read retrieves content, edit modifies parts, write overwrites entirely. No overlap in functionality.
Naming Consistency5/5
All tool names are single-word verbs, simple and consistent. No mixing of conventions.
Tool Count4/5
Three tools is minimal but appropriate for a focused file editing server. Each tool earns its place, though more tools could be added for listing or deletion.
Completeness2/5
The tool set lacks fundamental file operations like delete, rename, list, or search. For a general file system server, this is a significant gap.
Maintenance
ActivityMaintained
ResponsivenessNo issues