Skip to main content
Glama

overwrite

Replace selected text lines with new content in editor-mcp. Preview changes and syntax errors for JS or Python before applying updates.

Instructions

Overwrite the selected lines with new text. Amount of new lines can differ from the original selection

Args: new_lines (dict): Example: {"lines":["line one", "second line"]}

Returns: dict: Diff preview showing the proposed changes, and any syntax errors for JS or Python

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
new_linesYes

Implementation Reference

  • The primary handler function for the 'overwrite' MCP tool. This async function takes new_lines as input, verifies the current selection using ID, reads the file, computes new content, generates a diff preview, performs optional syntax checking with Black for Python or Babel for JS/JSX, detects syntax errors, sets pending_modified_lines and pending_diff for later confirm/cancel, and returns a preview or error.
    async def overwrite( new_lines: dict, ) -> Dict[str, Any]: """ Overwrite the selected lines with new text. Amount of new lines can differ from the original selection Args: new_lines (dict): Example: {"lines":["line one", "second line"]} Returns: dict: Diff preview showing the proposed changes, and any syntax errors for JS or Python """ new_lines = new_lines.get("lines") if self.current_file_path is None: return {"error": "No file path is set. Use set_file first."} if ( self.selected_start is None or self.selected_end is None or self.selected_id is None ): return {"error": "No selection has been made. Use select tool first."} try: with open(self.current_file_path, "r", encoding="utf-8") as file: lines = file.readlines() except Exception as e: return {"error": f"Error reading file: {str(e)}"} start = self.selected_start end = self.selected_end id = self.selected_id current_content = "".join(lines[start - 1 : end]) computed_id = calculate_id(current_content, start, end) if computed_id != id: return { "error": "id verification failed. The content may have been modified since you last read it." } processed_new_lines = [] for line in new_lines: if not line.endswith("\n"): processed_new_lines.append(line + "\n") else: processed_new_lines.append(line) if ( processed_new_lines and end < len(lines) and not processed_new_lines[-1].endswith("\n") ): processed_new_lines[-1] += "\n" before = lines[: start - 1] after = lines[end:] modified_lines = before + processed_new_lines + after diff_result = generate_diff_preview(lines, modified_lines, start, end) error = None if self.current_file_path.endswith(".py"): full_content = "".join(modified_lines) try: black.format_file_contents( full_content, fast=True, mode=black.Mode(), ) except black.InvalidInput as e: error = { "error": f"Python syntax error: {str(e)}", "diff_lines": diff_result, "auto_cancel": self.fail_on_python_syntax_error, } except Exception as e: if not isinstance(e, NothingChanged): error = { "error": f"Black check raised {type(e)}: {str(e)}", "diff_lines": diff_result, } elif self.enable_js_syntax_check and self.current_file_path.endswith( (".jsx", ".js") ): with tempfile.NamedTemporaryFile( mode="w", suffix=".jsx", delete=False ) as temp: temp_path = temp.name temp.writelines(modified_lines) try: presets = ( ["@babel/preset-react"] if self.current_file_path.endswith(".jsx") else ["@babel/preset-env"] ) cmd = [ "npx", "babel", "--presets", ",".join(presets), "--no-babelrc", temp_path, "--out-file", "/dev/null", # Output to nowhere, we just want to check syntax ] # Execute Babel to transform (which validates syntax) process = subprocess.run(cmd, capture_output=True, text=True) if process.returncode != 0: error_output = process.stderr filtered_lines = [] for line in error_output.split("\n"): if "node_modules/@babel" not in line: filtered_lines.append(line) filtered_error = "\n".join(filtered_lines).strip() if not filtered_error: filtered_error = "JavaScript syntax error detected" error = { "error": f"JavaScript syntax error: {filtered_error}", "diff_lines": diff_result, "auto_cancel": self.fail_on_js_syntax_error, } except Exception as e: os.unlink(temp_path) error = { "error": f"Error checking JavaScript syntax: {str(e)}", "diff_lines": diff_result, } finally: if os.path.exists(temp_path): os.unlink(temp_path) self.pending_modified_lines = modified_lines self.pending_diff = diff_result result = { "status": "preview", "message": "Changes ready to apply. Use confirm() to apply or cancel() to discard.", "diff_lines": diff_result["diff_lines"], "start": start, "end": end, } if error: result.update(error) if error.get("auto_cancel", False): self.pending_modified_lines = None self.pending_diff = None result["status"] = "auto_cancelled" result["message"] = ( "Changes automatically cancelled due to syntax error. The lines are still selected." ) else: result["message"] += ( " It looks like there is a syntax error, but you can choose to fix it in the subsequent edits." ) return result # Later on this tool should be shown conditionally, however, most clients don't support this functionality yet.
  • generate_diff_preview: Helper function called by overwrite to create a visual diff showing context lines before/after, removed lines (-prefix), and added lines (+prefix) for the proposed edit.
    def generate_diff_preview( original_lines: list, modified_lines: list, start: int, end: int ) -> dict: """ Generate a diff preview comparing original and modified content. Args: original_lines (list): List of original file lines modified_lines (list): List of modified file lines start (int): Start line number of the edit (1-based) end (int): End line number of the edit (1-based) Returns: dict: A dictionary with keys prefixed with + or - to indicate additions/deletions Format: [("-1", "removed line"), ("+1", "added line")] """ diffs = [] # Add some context lines before the change context_start = max(0, start - 1 - 3) # 3 lines of context before for i in range(context_start, start - 1): diffs.append((i + 1, original_lines[i].rstrip())) # Show removed lines for i in range(start - 1, end): diffs.append((f"-{i+1}", original_lines[i].rstrip())) # Show added lines new_content = "".join( modified_lines[ start - 1 : start - 1 + len(modified_lines) - len(original_lines) + (end - (start - 1)) ] ) new_lines = new_content.splitlines() for i, line in enumerate(new_lines): diffs.append((f"+{start+i}", line)) context_end = min(len(original_lines), end + 3) # 3 lines of context after for i in range(end, context_end): diffs.append((i + 1, original_lines[i].rstrip())) return { "diff_lines": diffs, }
  • calculate_id: Helper function used in overwrite for content verification by generating a unique ID from line range prefix and truncated SHA256 hash of the selected text.
    def calculate_id(text: str, start: int = None, end: int = None) -> str: """ Calculate a unique ID for content verification based on the text content. The ID is formed by combining a line prefix (if line numbers are provided) with a truncated SHA-256 id of the content. This allows quick verification that content hasn't changed between operations. Args: text (str): Content to generate ID for start (Optional[int]): Starting line number for the content end (Optional[int]): Ending line number for the content Returns: str: ID string in format: [LinePrefix]-[Truncatedid] Example: "L10-15-a7" for content spanning lines 10-15 Example: "L5-b3" for content on line 5 only """ prefix = "" if start and end: prefix = f"L{start}-{end}-" if start == end: prefix = f"L{start}-" return f"{prefix}{hashlib.sha256(text.encode()).hexdigest()[:2]}"

Other Tools

Related Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/danielpodrazka/editor-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server