Skip to main content
Glama
README.md
# file-mcp

`file-mcp` is a Windows-first MCP server focused on deterministic text writes.
It intentionally exposes write-only tools for create, replace, and structured edit workflows.
Public read and search capabilities have been removed from the tool surface.

## Goals

- Keep the MCP surface focused on writing files
- Preserve encoding, BOM, newline style, and trailing newline by default when editing existing files
- Support atomic writes guarded by `base_hash`
- Handle chunked large-file generation without giant single-call payloads
- Keep existing mixed-newline files writable without forcing full normalization first

## Tool Surface

- `write_full_text(path, content, encoding="preserve", bom="preserve", newline="preserve", final_newline="preserve", create_dirs=True, if_exists="overwrite", base_hash=None)`
  Whole-file atomic write.

- `apply_text_edits(path, edits, encoding="preserve", bom="preserve", newline="preserve", final_newline="preserve", base_hash=None)`
  Atomic line-range edits. Each `edits[]` item must provide `start_line` and `new_text`; `end_line` and `expected_old_text` are optional.

- `apply_text_spans(path, spans, encoding="preserve", bom="preserve", newline="preserve", final_newline="preserve", base_hash=None)`
  Atomic offset-based edits using normalized-text offsets. Each `spans[]` item must provide `start_offset`, `end_offset`, and `new_text`; `expected_old_text` is optional.

- `replace_literal(path, old_text, new_text, encoding="preserve", expected_occurrences=1, bom="preserve", newline="preserve", final_newline="preserve", base_hash=None)`
  Exact-count literal replacement. When no exact match is found, the server also tries conservative mojibake recovery for non-ASCII `old_text`/`new_text` pairs before failing and reporting whitespace or codec hints.


- `replace_regex(path, pattern, replacement, encoding="preserve", expected_occurrences=1, case_sensitive=True, dotall=False, bom="preserve", newline="preserve", final_newline="preserve", base_hash=None)`
  Exact-count regex replacement.

- `replace_block(path, start_marker, end_marker, replacement, encoding="preserve", occurrence=1, mode="between", bom="preserve", newline="preserve", final_newline="preserve", base_hash=None)`
  Marker-delimited block replacement.

- `begin_write_session(path, encoding="preserve", bom="preserve", newline="preserve", final_newline="preserve", create_dirs=True, if_exists="overwrite", base_hash=None)`
- `append_write_chunk(session_id, content)`
- `commit_write_session(session_id)`
- `abort_write_session(session_id)`

## What Changed

- `inspect_text` was removed from the public MCP interface
- `read_text` was removed from the public MCP interface
- `search_text` was removed from the public MCP interface
- `apply_search_replacements` was removed from the public MCP interface

The server still reads existing file contents internally when a write operation needs style preservation, conflict checks, or targeted replacement.
That internal read path is now an implementation detail rather than a client-facing capability.

## Editing Model

Recommended usage now is:

1. Use a caller-side source of truth for the target file content or edit coordinates.
2. Choose one write primitive:
   `write_full_text`, `apply_text_edits`, `apply_text_spans`, `replace_literal`, `replace_regex`, or `replace_block`.
3. Pass `base_hash` when you already have a trusted hash and want fail-closed concurrency protection.
4. Use chunked sessions for large generated outputs.

## Return Format

Successful write tools return compact natural-language summaries for LLM attention hygiene. The default result includes only the operation outcome, target path, and essential counts or session id.

Examples:

```text
Created C:\work\repo\README.md.
Updated C:\work\repo\src\app.ts: replaced 1 occurrence.
Unchanged C:\work\repo\README.md: new content matched existing file.
Write session started for C:\work\repo\large.txt. Session: 8f6c2c4e0f134f49a6b48bbf55f7156a
Committed write session 8f6c2c4e0f134f49a6b48bbf55f7156a to C:\work\repo\large.txt: updated file.
```

The tool output intentionally omits audit fields such as hashes, byte counts, encoding, newline style, and total line counts.

### Nested Edit Objects

`apply_text_edits` item fields:
- `start_line`: 1-based inclusive line number.
- `end_line`: optional 1-based inclusive end line. Omit to replace only `start_line`; set to `start_line - 1` to insert before `start_line`.
- `new_text`: replacement text for the line range.
- `expected_old_text`: optional guard text for the existing line range.

`apply_text_spans` item fields:
- `start_offset`: 0-based inclusive offset in normalized file text.
- `end_offset`: 0-based exclusive offset in normalized file text.
- `new_text`: replacement text for the offset range.
- `expected_old_text`: optional guard text for the existing normalized offset range.


## Style Preservation

When editing an existing file with the default `"preserve"` modes:

- `encoding` keeps the detected file encoding
- `bom` keeps the existing BOM state
- `newline` keeps `LF`, `CRLF`, or `CR`
- `final_newline` keeps whether the file ended with a newline

If the existing file uses mixed newline styles and you keep `newline="preserve"`, unchanged or positionally corresponding lines retain their original endings and inserted lines use the dominant existing newline style.

## Allowed Roots

By default the server only allows access under `F:\`.

Override with an environment variable:

```powershell
$env:FILE_MCP_ALLOWED_ROOTS = 'F:\;F:\GGPK3\;F:\repo\'
```

Multiple roots are separated with `;`.
Set `FILE_MCP_ALLOWED_ROOTS` to `*` to disable root restrictions entirely.

## Install

```powershell
cd D:\file-mcp
py -m pip install -e .
```

## Run

```powershell
cd D:\file-mcp
py -m file_mcp
```

## Example MCP Client Config

```json
{
  "mcpServers": {
    "file-mcp": {
      "command": "py",
      "args": ["-m", "file_mcp.server"],
      "cwd": "D:\\file-mcp",
      "env": {
        "FILE_MCP_ALLOWED_ROOTS": "*"
      }
    }
  }
}
```

## Notes

- Auto-detection supports UTF-8, UTF-8 BOM, UTF-16 LE/BE, UTF-32 LE/BE, and `gb18030`, and it now prefers `gb18030` over UTF-8 only when both decoders succeed and the UTF-8 result looks materially more like mojibake

- Successful write tools return compact natural-language summaries instead of JSON metadata
- `write_full_text` is the simplest primitive when whole-file replacement is acceptable

TDQS

B3.2/5.0

Scored across 10 tools

Disambiguation5/5

Each tool has a clearly distinct purpose: session management, various replace methods, and full file writing. No two tools appear to do the same thing, and descriptions clarify the differences.

Naming Consistency5/5

All tool names follow a consistent verb_noun snake_case pattern (e.g., abort_write_session, replace_literal), making them predictable and easy to interpret.

Tool Count5/5

10 tools is well within the ideal range. Each tool addresses a specific file editing operation without being excessive or insufficient.

Completeness2/5

The tool set lacks basic file operations like reading, deleting, or listing files. While editing and writing are covered, the absence of read functionality creates a significant gap for typical file management workflows.

Maintenance

ActivityInactive
ResponsivenessNo issues