An experimental high-performance MCP (Model Context Protocol) file editing toolkit in Go — atomic writes, smart batch sorting, and intelligent function-scope detection. Experimental project: tool names, parameters, and behaviors may change as the design evolves. Do not hardcode specific tool names into prompts; prefer capability-based or dynamically resolved tool selection. Tool descriptions are localized at startup via
--lang <zh|en>and fall back to theLANGenvironment variable when omitted.
Based on recent findings, using Chinese prompts with Chinese-language models is no longer recommended, as the tokenizer produces more tokens for semantically equivalent content in Chinese.⚠️ For Chinese-speaking users: if you are using a Chinese-language model (e.g., Kimi), make sure to add"args": ["--lang", "zh"]to your MCP configuration. Otherwise tool descriptions will fall back to English.
If you are a Go developer who wants to embed editing capabilities directly in your agent framework, see the Go API documentation.
🤖 Want an AI agent to install and configure the binary for you? See the LLM self-setup guide. 📜 For historical decisions and closed feature proposals, see the decision log (Simplified Chinese only).
To have an AI agent install it for you:
install this mcp server:https://conglinyizhi.github.io/better-edit-tools-mcp/llms.txt
Structural sanity check for brackets, braces, parentheses, HTML/XML tag closure, and quote parity. The scanner avoids interference from strings and comments. The verbose parameter controls output detail:
false(default): only outputs unmatched items.true: outputs all matched pairs.
——Catch structural mistakes early, even when the file mixes code, markup, and strings.
Read-only source inspection tool. Prints file content with line numbers. Pass a positive end value for an explicit range, or 0 or negative to auto-expand to the enclosing function scope. Returns a viewed_code_id (v0.4+) that can be passed to be-replace for line-number validation.
When embedding the Go library directly, prefer the Read API name.
——Read the exact slice you need without guessing the enclosing function range.
Precise line-range substitution. Accepts a viewed_code_id parameter from a prior be-read session to validate that line numbers still match. When old is provided, the tool verifies current content before writing and returns an error on mismatch. The server also accepts old_text as an alias.
——Replace a known block with minimal movement and minimal surprise.
Adds content after a specified line. after_line=0 inserts at the very beginning of the file. The preferred primitive for incremental edits — avoids rewriting unrelated lines. The sole parameter for insertion position is after_line, replacing the old ambiguous line/after_line dual param.
——Insert new content exactly where it belongs without touching the rest of the file.
Inserts content from a file (file:///absolute/path) or a previously saved chip cache (chip://{id}). When from is omitted, lists all available chip IDs. This tool bridges the gap between failed operations and recovery: when be-write fails due to malformed JSON and saves its arguments as a chip, be-insert-chip can replay that content directly into the target file.
——Replay cached arguments from a prior failure, or inject file content at a precise line.
Removes a line range using start/end line numbers or a target descriptor. Line-oriented for predictable, easy-to-reason-about results. Legacy aliases (start_line, end_line, line, lines) have been removed to eliminate tool confusion.
——Remove targets with line-level precision and predictable results.
Raw file write tool for full-content replacement. Accepts both single-file and multi-file payloads via direct arguments:
- Single file:
{"file":"...","content":"..."} - Multi file:
{"files":[{"file":"...","content":"..."}]}
A degraded parsing path is automatically invoked when standard JSON parsing fails, rescuing AI-generated content with broken escaping. Literal \n in content is auto-detected and converted to real newlines, solving the double-encoding problem in MCP call chains.
——Even when the JSON wrapper breaks, the write still tries to rescue the payload.
Detects the enclosing {} block or function range for a given line. Uses brace counting with string- and comment-aware scanning for reliability on real-world source code.
——Find the logical function boundary instead of guessing from raw braces alone.
Finds the enclosing XML/HTML/Vue tag pair for a line. The markup-oriented counterpart to be-func-range.
——Locate the surrounding tag pair that defines the real editing boundary.
- Atomic writes: File modifications go through a temp-file-then-rename cycle, preventing data corruption if the process crashes mid-write.
- isError signaling: Errors properly report
isError: trueper the MCP spec. - Go-native: No runtime dependencies — a single binary with a small embedded editing library.
- Fault-tolerant JSON parsing: AI-generated content often contains backticks,
${}, or unescaped quotes;be-writeautomatically falls back to character-level extraction. - Session state bridging:
be-readreturns aviewed_code_idthatbe-replacecan accept to validate consistent line numbering. - Localized descriptions:
--lang <zh|en>switches tool description language; parameter names and behavior remain unchanged.
go build -o better-edit-tools ./cmd/better-edit-toolsThe binary will be at ./better-edit-tools.
./better-edit-tools --lang enIf --lang is not provided, the server tries to infer the language from the LANG environment variable and defaults to English.
Add --no-prefix to strip the be- prefix from tool names (e.g., be-read becomes read). This is useful for MCP controllers that cannot re-edit tool names.
Add to your MCP client configuration:
{
"mcpServers": {
"better-edit-tools": {
"command": "/path/to/better-edit-tools/better-edit-tools",
"args": ["--lang", "en"]
}
}
}For example, Claude Desktop's config is at ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows).
The same binary can be used as a command-line tool. When invoked with a subcommand, it executes a single operation and exits; otherwise it starts the MCP server as usual.
# Read
./better-edit-tools read --file main.go --start 1 --end auto
# Replace
./better-edit-tools replace --file main.go --start 5 --end 10 --content "..."
# Insert
./better-edit-tools insert --file main.go --after-line 4 --content "..."
# Delete
./better-edit-tools delete --file main.go --start 5 --end 10
# Write
./better-edit-tools write --file main.go --content "package main\n\nfunc main() {}"
# Balance / scope detection
./better-edit-tools balance --file main.go
./better-edit-tools func-range --file main.go --line 12
./better-edit-tools tag-range --file index.html --line 8Use --output json to get machine-parseable output, and --preview to see the diff without writing to disk.
./better-edit-tools read --file main.go --start 1 --end 10 --output json
./better-edit-tools replace --file main.go --start 5 --end 10 --content "..." --previewNote: viewed_code_id and snapshot/transaction tools are MCP-only because they rely on in-process session state.
The helper script downloads the latest release for your OS and architecture, verifies the SHA-256 checksum, and installs the binary into ~/.local/share/better-edit-tools/bin/. Pass a tag name to install a specific version.
bash <(curl -fsSL https://raw.githubusercontent.com/conglinyizhi/better-edit-tools-mcp/main/scripts/install.sh)
bash <(curl -fsSL https://raw.githubusercontent.com/conglinyizhi/better-edit-tools-mcp/main/scripts/install.sh) v0.2Release assets are published for Linux, macOS, and Windows on both amd64 and arm64, with matching .sha256 checksum files. Windows releases are packaged as .zip files. Release notes are grouped from Conventional Commits.
The replace, insert, and delete operations are inspired by includewudi/fast-edit.
MIT