file-mcp
by yun-wulian
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