pub struct CodingMcp<T: CodingTools = DefaultCodingTools> { /* private fields */ }Expand description
The primary MCP tool server for coding workflows. Provides file I/O, shell execution, regex search, structural AST search, glob-based file discovery, LSP code intelligence, and web fetch/search – all exposed as MCP tools that an agent can invoke.
§Construction
Use the builder-style methods to configure the server:
use mcp_servers::CodingMcp;
// Default: local filesystem tools, no LSP
let server = CodingMcp::new();
// With LSP code intelligence and explicit read-rule directories
let server = CodingMcp::new()
.with_rules_dirs(vec!["/my/project/.aether/skills".into(), "/my/project/.claude/rules".into()])
.with_lsp("/my/project".into())
.with_root_dir("/my/project".into())
.with_permission_mode(mcp_servers::PermissionMode::Auto);For custom tool backends, use CodingMcp::with_tools:
let server = CodingMcp::with_tools(my_custom_tools);§Tools provided
File operations:
read_file– Read file contents with optional offset/limitwrite_file– Write content to a file (creates parent dirs)edit_file– String replacement in an existing filelist_files– List directory contents with metadata
Shell & search:
bash– Execute shell commands (with background process support)read_background_bash– Read output from a running background processgrep– Regex search across files with glob filtersfind– Find files by glob pattern
Web:
web_fetch– Fetch a URL and extract text contentweb_search– Web search via Brave Search API
LSP (requires with_lsp):
lsp_symbol– Go to definition, find references, find implementationslsp_workspace_search– Search for symbols across the workspacelsp_document– List symbols in a filelsp_check_errors– Get diagnostics for a file or workspacelsp_rename– Rename a symbol across the project
§Safety
The server enforces several safety checks:
- Read-before-edit –
write_fileandedit_filerequire the file to have been read first in the same session, preventing blind overwrites. - Dangerous command detection – Bash commands containing destructive patterns (
rm,git push --force, redirect operators, etc.) are flagged. - Permission modes –
PermissionModecontrols whether flagged operations require user approval via MCP elicitation.
§See also
CodingTools– Trait abstracting the tool backend (implement for custom environments)DefaultCodingTools– The default local-filesystem implementationPermissionMode– User approval settingsLspRegistry– LSP daemon connection managerCodingError– Error types for tool operations
Implementations§
Source§impl<T: CodingTools + 'static> CodingMcp<T>
impl<T: CodingTools + 'static> CodingMcp<T>
Sourcepub fn with_tools(tools: T) -> Self
pub fn with_tools(tools: T) -> Self
Create a CodingMcp with custom tool implementation
Sourcepub fn with_lsp(self, root_path: PathBuf) -> Self
pub fn with_lsp(self, root_path: PathBuf) -> Self
Enable LSP code intelligence for the given project root.
LSP servers for detected project languages are spawned immediately in the background, allowing indexing to start right away.
Sourcepub fn with_roots(self, roots: Vec<PathBuf>) -> Self
pub fn with_roots(self, roots: Vec<PathBuf>) -> Self
Set workspace roots.
Sourcepub fn with_rules_dirs(self, rules_dirs: Vec<PathBuf>) -> Self
pub fn with_rules_dirs(self, rules_dirs: Vec<PathBuf>) -> Self
Set prompt directories used for read-triggered rule activation.
Sourcepub fn with_root_dir(self, root_dir: PathBuf) -> Self
pub fn with_root_dir(self, root_dir: PathBuf) -> Self
Set the workspace root directory from a single path.
Sourcepub fn with_permission_mode(self, mode: PermissionMode) -> Self
pub fn with_permission_mode(self, mode: PermissionMode) -> Self
Set the permission mode controlling user approval for tool calls.
Sourcepub fn grep_tool_attr() -> Tool
pub fn grep_tool_attr() -> Tool
Generated tool metadata function for grep
Sourcepub fn grep(
&self,
request: Parameters<GrepInput>,
context: RequestContext<RoleServer>,
) -> Pin<Box<dyn Future<Output = Result<Json<GrepOutput>, String>> + Send + '_>>
pub fn grep( &self, request: Parameters<GrepInput>, context: RequestContext<RoleServer>, ) -> Pin<Box<dyn Future<Output = Result<Json<GrepOutput>, String>> + Send + '_>>
Text/pattern search using ripgrep.
For code structure (definitions, usages, types), use lsp_symbol instead. Grep is for string literals, TODOs, logs, and non-code files.
§Usage
{"pattern": "TODO|FIXME"}
{"pattern": "error.*failed", "outputMode": "content", "lineNumbers": true}
{"pattern": "impl Handler", "type": "rust"}
{"pattern": "api_key", "glob": "*.ts", "caseInsensitive": true}
{"pattern": "struct \\{[\\s\\S]*?field", "multiline": true}pattern— required, regex pattern to search forpath— absolute path to file or directory (defaults to cwd)outputMode—content(default, shows matching lines),filesWithMatches(file paths only), orcount(match counts per file)type— file type filter (js,py,rust, etc.)glob— glob pattern filter (e.g.,*.ts,*.{js,jsx})caseInsensitive— case insensitive search (default: false)lineNumbers— show line numbers (content mode only, default: true)contextBefore— lines before each match (content mode only)contextAfter— lines after each match (content mode only)contextAround— lines before and after each match (content mode only, overrides contextBefore/contextAfter)headLimit— limit output to first N entriesmultiline— for cross-line patterns where.matches newlines
Sourcepub fn ast_grep_tool_attr() -> Tool
pub fn ast_grep_tool_attr() -> Tool
Generated tool metadata function for ast_grep
Sourcepub fn ast_grep(
&self,
request: Parameters<AstGrepInput>,
context: RequestContext<RoleServer>,
) -> Pin<Box<dyn Future<Output = Result<Json<AstGrepOutput>, String>> + Send + '_>>
pub fn ast_grep( &self, request: Parameters<AstGrepInput>, context: RequestContext<RoleServer>, ) -> Pin<Box<dyn Future<Output = Result<Json<AstGrepOutput>, String>> + Send + '_>>
Structural AST search using ast-grep patterns.
Use ast_grep when you need to find syntax shapes such as functions, calls, hooks, imports, or language constructs. Use grep for raw text, logs, TODOs, and regex searches. Use LSP tools for definitions, references, types, and symbol navigation when a language server is available.
§Usage
{"language": "rs", "pattern": "fn $NAME($$$ARGS) { $$$BODY }", "glob": "**/*.rs"}
{"language": "rs", "pattern": "use $PATH;", "glob": "**/*.rs"}
{"language": "rs", "pattern": "use $CRATE;", "constraints": {"CRATE": "^crossterm"}, "glob": "**/*.rs"}
{"language": "ts", "pattern": "console.log($$$ARGS)", "path": "src", "headLimit": 20}
{"language": "tsx", "pattern": "useEffect($$$ARGS)", "contextAround": 2}
{"language": "py", "pattern": "def $NAME($$$ARGS): $$$BODY"}§Filtering by capture value
Use constraints to keep only matches whose captured text matches a regex. For example, this finds every file that imports crossterm in 1-toolcall:
{
"language": "rs",
"pattern": "use $CRATE;",
"constraints": {"CRATE": "^crossterm"},
"glob": "**/*.rs"
}§Parameters
pattern— required ast-grep pattern code.language— required ast-grep language alias such asrs,rust,ts,tsx,py, orjs.path— file or directory to search. Defaults to the workspace root.glob— optional file filter such as**/*.rsor*.{ts,tsx}.constraints— optional map from metavariable name (without$) to a regex the captured text must match. Only matches where every constraint is satisfied are returned. Example:{"CRATE": "^crossterm"}with patternuse $CRATE;.contextBefore— lines before each match.contextAfter— lines after each match.contextAround— lines before and after each match; overridescontextBeforeandcontextAfter.headLimit— maximum number of matches to return.
Directory searches respect .gitignore, skip hidden files, do not follow symlinks, and search only files matching the selected language. Explicit file searches parse the provided file with the selected language even if the extension does not match.
Result line and column ranges are 1-based. Byte ranges are 0-based and end-exclusive.
Sourcepub fn find_tool_attr() -> Tool
pub fn find_tool_attr() -> Tool
Generated tool metadata function for find
Sourcepub fn find(
&self,
request: Parameters<FindInput>,
context: RequestContext<RoleServer>,
) -> Pin<Box<dyn Future<Output = Result<Json<FindOutput>, String>> + Send + '_>>
pub fn find( &self, request: Parameters<FindInput>, context: RequestContext<RoleServer>, ) -> Pin<Box<dyn Future<Output = Result<Json<FindOutput>, String>> + Send + '_>>
Finds files by name pattern.
§Usage
{"pattern": "**/*.rs"}
{"pattern": "*.test.ts", "path": "/path/to/search"}pattern— required, glob pattern (e.g.,**/*.js,config*.json)path— directory to search (default: cwd)
Returns: matching file paths, sorted alphabetically.
§Tips
- Run multiple searches in parallel when exploring
- For open-ended searches requiring multiple rounds, consider spawning a sub-agent
Sourcepub fn read_file_tool_attr() -> Tool
pub fn read_file_tool_attr() -> Tool
Generated tool metadata function for read_file
Sourcepub fn read_file(
&self,
request: Parameters<ReadFileArgs>,
context: RequestContext<RoleServer>,
) -> Pin<Box<dyn Future<Output = Result<Json<ReadFileResult>, String>> + Send + '_>>
pub fn read_file( &self, request: Parameters<ReadFileArgs>, context: RequestContext<RoleServer>, ) -> Pin<Box<dyn Future<Output = Result<Json<ReadFileResult>, String>> + Send + '_>>
Reads a file from the local filesystem with line numbers.
§Usage
{"file_path": "/absolute/path/to/file.rs"}
{"file_path": "/path/to/file.rs", "offset": 150, "limit": 50}file_path— required, must be absolute pathoffset— 1-indexed starting line (default: 1)limit— max lines to read (default: 2000)
Output format: 1\tline content (line number, tab, content)
§Tips
- Read the whole file by omitting
offset/limit— use them only for large files - Read multiple files in parallel when you need several
- Use
list_filesfor directories, not this tool
§Safety
You MUST read a file before editing (edit_file) or overwriting (write_file). This prevents accidental data loss.
Sourcepub fn write_file_tool_attr() -> Tool
pub fn write_file_tool_attr() -> Tool
Generated tool metadata function for write_file
Sourcepub fn write_file(
&self,
request: Parameters<WriteFileArgs>,
context: RequestContext<RoleServer>,
) -> Pin<Box<dyn Future<Output = Result<Json<WriteFileResponse>, String>> + Send + '_>>
pub fn write_file( &self, request: Parameters<WriteFileArgs>, context: RequestContext<RoleServer>, ) -> Pin<Box<dyn Future<Output = Result<Json<WriteFileResponse>, String>> + Send + '_>>
Writes a file to the filesystem, replacing entire contents. Creates parent directories if needed.
§Usage
{"filePath": "/path/to/new_file.rs", "content": "fn main() {}"}filePath— required, absolute pathcontent— required, full file contents
§Tips
- Prefer
edit_filefor existing files — only usewrite_filefor new files or complete rewrites - Don’t proactively create documentation (*.md, README) unless explicitly requested
§Safety
If the file exists, you MUST read it with read_file first. This prevents accidental data loss. New files don’t require reading.
Sourcepub fn edit_file_tool_attr() -> Tool
pub fn edit_file_tool_attr() -> Tool
Generated tool metadata function for edit_file
Sourcepub fn edit_file(
&self,
request: Parameters<EditFileArgs>,
context: RequestContext<RoleServer>,
) -> Pin<Box<dyn Future<Output = Result<Json<EditFileResponse>, String>> + Send + '_>>
pub fn edit_file( &self, request: Parameters<EditFileArgs>, context: RequestContext<RoleServer>, ) -> Pin<Box<dyn Future<Output = Result<Json<EditFileResponse>, String>> + Send + '_>>
Use this tool to edit a file. This tool accepts an array of batched exact-string replacements. If 1 edit fails, no edits in the batch are applied.
§Usage
{"filePath": "/path/to/file.rs", "edits": [
{"oldString": "foo", "newString": "bar"},
{"oldString": "old_name", "newString": "new_name", "replaceAll": true}
]}filePath— required, absolute pathedits— required, a non-empty array. Each edit replacesoldStringwithnewString.oldString— exact string to find (must be unique unlessreplaceAll).newString— replacement text.replaceAll— replace all occurrences (default: false).
§Tips
- Batch every edit to a file into one call; edits must target non-overlapping regions.
- Preserve exact indentation from
read_fileoutput — match text AFTER the tab character, not the line-number prefix. - To rename symbols across the codebase, prefer
lsp_renameinstead (if available). - Unless your edits require overwriting an entire file, prefer this tool over
create_file.
§Safety
You MUST read a file with read_file before editing it. This prevents accidental data loss.
Sourcepub fn list_files_tool_attr() -> Tool
pub fn list_files_tool_attr() -> Tool
Generated tool metadata function for list_files
Sourcepub fn list_files(
&self,
request: Parameters<ListFilesArgs>,
context: RequestContext<RoleServer>,
) -> Pin<Box<dyn Future<Output = Result<Json<ListFilesResult>, String>> + Send + '_>>
pub fn list_files( &self, request: Parameters<ListFilesArgs>, context: RequestContext<RoleServer>, ) -> Pin<Box<dyn Future<Output = Result<Json<ListFilesResult>, String>> + Send + '_>>
Lists files and directories in a path with detailed metadata.
§Usage
{"path": "/absolute/path"}
{"path": "/path", "include_hidden": true}path— directory to list (default: current directory)include_hidden— include files starting with ‘.’ (default: false)
Returns: name, path, type (file/directory/symlink), size, permissions, modification time. Sorted alphabetically.
Sourcepub fn bash_tool_attr() -> Tool
pub fn bash_tool_attr() -> Tool
Generated tool metadata function for bash
Sourcepub fn bash(
&self,
request: Parameters<BashInput>,
context: RequestContext<RoleServer>,
) -> Pin<Box<dyn Future<Output = Result<Json<BashOutput>, String>> + Send + '_>>
pub fn bash( &self, request: Parameters<BashInput>, context: RequestContext<RoleServer>, ) -> Pin<Box<dyn Future<Output = Result<Json<BashOutput>, String>> + Send + '_>>
Executes bash commands in a persistent shell session.
For terminal operations only (git, npm, docker, cargo, etc.). Use dedicated tools for file operations.
§Usage
{"command": "cargo test", "description": "Run tests"}
{"command": "git status && git diff", "description": "Check git status and diff"}
{"command": "npm run build", "timeout": 300000, "description": "Build with 5min timeout"}command— required, the bash commanddescription— concise description (5-10 words)timeout— max runtime in ms (default: 120000, max: 600000)run_in_background— run async, check output withread_background_bash
§Tips
- Run independent commands in parallel with multiple
bashcalls - Chain dependent commands with
&&in a single call - Use
;only if you don’t care if earlier commands fail
Sourcepub fn read_background_bash_tool_attr() -> Tool
pub fn read_background_bash_tool_attr() -> Tool
Generated tool metadata function for read_background_bash
Sourcepub fn read_background_bash(
&self,
request: Parameters<ReadBackgroundBashInput>,
) -> Pin<Box<dyn Future<Output = Result<Json<ReadBackgroundBashOutput>, String>> + Send + '_>>
pub fn read_background_bash( &self, request: Parameters<ReadBackgroundBashInput>, ) -> Pin<Box<dyn Future<Output = Result<Json<ReadBackgroundBashOutput>, String>> + Send + '_>>
Retrieves output from a background bash shell (started with run_in_background: true).
bash_id— required, shell ID returned from the original bash call- Returns only new output since the last check, along with shell status (running/completed/failed)
- Supports optional regex filtering to show only matching lines
Sourcepub fn web_fetch_tool_attr() -> Tool
pub fn web_fetch_tool_attr() -> Tool
Generated tool metadata function for web_fetch
Sourcepub fn web_fetch(
&self,
request: Parameters<WebFetchInput>,
context: RequestContext<RoleServer>,
) -> Pin<Box<dyn Future<Output = Result<Json<WebFetchOutput>, String>> + Send + '_>>
pub fn web_fetch( &self, request: Parameters<WebFetchInput>, context: RequestContext<RoleServer>, ) -> Pin<Box<dyn Future<Output = Result<Json<WebFetchOutput>, String>> + Send + '_>>
Fetches content from a URL, extracts the main article content, and converts it to Markdown.
Uses a readability algorithm to strip navigation, sidebars, footers, and other non-content elements, giving you clean article text instead of the full page.
§Usage
{"url": "https://docs.rs/serde"}
{"url": "https://example.com", "prompt": "Find API documentation", "timeout": 60000}url— required, HTTP/HTTPS URL (HTTP auto-upgraded)prompt— describe what you’re looking for (optional)timeout— max wait in ms (default: 30000, max: 60000)
§Tips
- Use specific URLs rather than relying on search
- Handle 4xx/5xx status codes gracefully
- Falls back to full-page conversion when readability extraction fails
Sourcepub fn web_search_tool_attr() -> Tool
pub fn web_search_tool_attr() -> Tool
Generated tool metadata function for web_search
Sourcepub fn web_search(
&self,
request: Parameters<WebSearchInput>,
context: RequestContext<RoleServer>,
) -> Pin<Box<dyn Future<Output = Result<Json<WebSearchOutput>, String>> + Send + '_>>
pub fn web_search( &self, request: Parameters<WebSearchInput>, context: RequestContext<RoleServer>, ) -> Pin<Box<dyn Future<Output = Result<Json<WebSearchOutput>, String>> + Send + '_>>
Searches the web via Brave Search API for up-to-date information.
§Usage
{"query": "rust async best practices 2024"}
{"query": "tokio documentation", "count": 5, "allowed_domains": ["docs.rs"]}query— required, search query (be specific)count— max results (default: 10, max: 20)allowed_domains— only include these domainsblocked_domains— exclude these domains
§Tips
- Use snippets to assess relevance before fetching full pages
- Always cite sources using the returned URLs
- Use
web_fetchto get full content from promising results
Sourcepub fn lsp_symbol_tool_attr() -> Tool
pub fn lsp_symbol_tool_attr() -> Tool
Generated tool metadata function for lsp_symbol
Sourcepub fn lsp_symbol(
&self,
request: Parameters<LspSymbolInput>,
context: RequestContext<RoleServer>,
) -> Pin<Box<dyn Future<Output = Result<Json<LspSymbolOutput>, String>> + Send + '_>>
pub fn lsp_symbol( &self, request: Parameters<LspSymbolInput>, context: RequestContext<RoleServer>, ) -> Pin<Box<dyn Future<Output = Result<Json<LspSymbolOutput>, String>> + Send + '_>>
Code navigation powered by a LSP server. Prefer this over grep and find.
§Operations
| Query | Operation |
|---|---|
| “Where is X defined?” | definition |
| “Where is X used?” | references |
| “What type is X?” | hover |
| “What implements this trait?” | implementation |
| “What calls X?” | incoming_calls |
| “What does X call?” | outgoing_calls |
§Usage
Required: file_path, symbol (exact name as it appears)
Optional: line (1-indexed, skips auto-resolution — faster)
{"operation": "definition", "file_path": "/path/to/file.rs", "symbol": "HashMap"}
{"operation": "references", "file_path": "/path/to/file.rs", "symbol": "process_request"}
{"operation": "incoming_calls", "file_path": "/path/to/file.rs", "symbol": "process_request", "limit": 20}§Output Control
limit— cap results. Use forincoming_calls/outgoing_callson large functions.context_lines— include N lines of source around each result (definition/implementation/references only). Eliminates need forread_file.include_declaration— forreferencesonly (default: true)
§Tips
- Cross-crate navigation: Use
definitionon an import to jump directly into dependency source — no need to manually navigate~/.cargo/registry/.... outgoing_callsnoise: Returns ALL calls including stdlib/dep calls (map_err,collect, etc.). Uselimitand filter byfile_pathfor project-local calls.- Workspace-wide search: If you don’t know which file a symbol is in, use
lsp_workspace_searchinstead.
Sourcepub fn lsp_workspace_search_tool_attr() -> Tool
pub fn lsp_workspace_search_tool_attr() -> Tool
Generated tool metadata function for lsp_workspace_search
Sourcepub fn lsp_workspace_search(
&self,
request: Parameters<LspWorkspaceSearchInput>,
context: RequestContext<RoleServer>,
) -> Pin<Box<dyn Future<Output = Result<Json<LspWorkspaceSearchOutput>, String>> + Send + '_>>
pub fn lsp_workspace_search( &self, request: Parameters<LspWorkspaceSearchInput>, context: RequestContext<RoleServer>, ) -> Pin<Box<dyn Future<Output = Result<Json<LspWorkspaceSearchOutput>, String>> + Send + '_>>
Searches for symbols across the entire workspace by name.
Use this when you don’t know which file a symbol lives in. For definition/references/hover on a known file, use lsp_symbol instead.
§Usage
{"query": "AppState"}
{"query": "Repository", "limit": 10, "context_lines": 3}query— required, symbol name (fuzzy/substring matching)limit— cap resultscontext_lines— include N lines of source around each result
§When to Use
- “Where is
AppStatedefined?” (don’t know the file) - “Find all structs matching
Repository” - “Which module declares
process_request?”
§Notes
- Query matching is LSP-server dependent (typically fuzzy)
- Results deduplicated across language servers
Sourcepub fn lsp_document_tool_attr() -> Tool
pub fn lsp_document_tool_attr() -> Tool
Generated tool metadata function for lsp_document
Sourcepub fn lsp_document(
&self,
request: Parameters<LspDocumentInput>,
context: RequestContext<RoleServer>,
) -> Pin<Box<dyn Future<Output = Result<Json<LspDocumentOutput>, String>> + Send + '_>>
pub fn lsp_document( &self, request: Parameters<LspDocumentInput>, context: RequestContext<RoleServer>, ) -> Pin<Box<dyn Future<Output = Result<Json<LspDocumentOutput>, String>> + Send + '_>>
Sourcepub fn lsp_check_errors_tool_attr() -> Tool
pub fn lsp_check_errors_tool_attr() -> Tool
Generated tool metadata function for lsp_check_errors
Sourcepub fn lsp_check_errors(
&self,
request: Parameters<LspDiagnosticsRequest>,
context: RequestContext<RoleServer>,
) -> Pin<Box<dyn Future<Output = Result<Json<LspDiagnosticsOutput>, String>> + Send + '_>>
pub fn lsp_check_errors( &self, request: Parameters<LspDiagnosticsRequest>, context: RequestContext<RoleServer>, ) -> Pin<Box<dyn Future<Output = Result<Json<LspDiagnosticsOutput>, String>> + Send + '_>>
Gets instant compiler errors and warnings without running a build.
Prefer this over cargo check, npm run build, tsc, go build.
§Usage
The tool has two explicit modes:
Workspace-wide diagnostics:
{"input":{"scope":"workspace"}}Single-file diagnostics:
{"input":{"scope":"file","filePath":"/absolute/path/to/file.rs"}}§Parameters
input— required, wrapper object for the diagnostics queryinput.scope— required, either"workspace"or"file"input.filePath— required wheninput.scope="file", must be an absolute path to an existing file
Sourcepub fn lsp_rename_tool_attr() -> Tool
pub fn lsp_rename_tool_attr() -> Tool
Generated tool metadata function for lsp_rename
Sourcepub fn lsp_rename(
&self,
request: Parameters<LspRenameInput>,
context: RequestContext<RoleServer>,
) -> Pin<Box<dyn Future<Output = Result<Json<LspRenameOutput>, String>> + Send + '_>>
pub fn lsp_rename( &self, request: Parameters<LspRenameInput>, context: RequestContext<RoleServer>, ) -> Pin<Box<dyn Future<Output = Result<Json<LspRenameOutput>, String>> + Send + '_>>
Renames a symbol across the entire workspace using LSP-powered refactoring.
A single rename updates all references — no manual file-by-file editing needed.
§Usage
{"file_path": "/project/src/lib.rs", "symbol": "old_name", "new_name": "better_name"}file_path— required, file containing the symbolsymbol— required, current symbol namenew_name— required, new symbol nameline— optional, 1-indexed line (skips auto-resolution)
Returns: files affected, line/column ranges, total edit count.
Source§impl<T: CodingTools + 'static> CodingMcp<T>
impl<T: CodingTools + 'static> CodingMcp<T>
Sourcepub async fn test_read_file(
&self,
args: ReadFileArgs,
) -> Result<Json<ReadFileResult>, String>
pub async fn test_read_file( &self, args: ReadFileArgs, ) -> Result<Json<ReadFileResult>, String>
Read a file and track it in the read set (test helper, no MCP context needed).
Sourcepub async fn test_write_file(
&self,
args: WriteFileArgs,
) -> Result<Json<WriteFileResponse>, String>
pub async fn test_write_file( &self, args: WriteFileArgs, ) -> Result<Json<WriteFileResponse>, String>
Write a file with read-before-write safety check (test helper, no MCP context needed).
Sourcepub async fn test_edit_file(
&self,
args: EditFileArgs,
) -> Result<Json<EditFileResponse>, String>
pub async fn test_edit_file( &self, args: EditFileArgs, ) -> Result<Json<EditFileResponse>, String>
Edit a file with read-before-edit safety check (test helper, no MCP context needed).