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_textwas removed from the public MCP interfaceread_textwas removed from the public MCP interfacesearch_textwas removed from the public MCP interfaceapply_search_replacementswas 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:
- Use a caller-side source of truth for the target file content or edit coordinates.
- Choose one write primitive:
write_full_text, apply_text_edits, apply_text_spans, replace_literal, replace_regex, or replace_block.
- Pass
base_hashwhen you already have a trusted hash and want fail-closed concurrency protection. - 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:
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 onlystart_line; set tostart_line - 1to insert beforestart_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:
encodingkeeps the detected file encodingbomkeeps the existing BOM statenewlinekeepsLF,CRLF, orCRfinal_newlinekeeps 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:
$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
cd D:\file-mcp
py -m pip install -e .
Run
cd D:\file-mcp
py -m file_mcp
Example MCP Client Config
{
"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 prefersgb18030over 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_textis the simplest primitive when whole-file replacement is acceptable











