Skip to main content
Glama
devrandom

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