Skip to content

Modernize MCP Server - #9

Merged
peteretelej merged 8 commits into
mainfrom
modernize-mcp
Mar 15, 2026
Merged

Modernize MCP Server#9
peteretelej merged 8 commits into
mainfrom
modernize-mcp

Conversation

@peteretelej

@peteretelej peteretelej commented Mar 14, 2026

Copy link
Copy Markdown
Owner

The Python MCP SDK has evolved significantly since the MCP server was implemented. The addition of FastMCP into the SDK simplifies a lot of complexity previously manually implemented server. This change updates the MCP server to adopt the newer SDK features.

Summary by CodeRabbit

  • New Features

    • Exposed remote file tools: inspect, search (fuzzy/regex/case/count), read (lines/semantic/head/tail), edit (preview + backups), revert, and directory search/listing with depth/limits.
    • Atomic batch edits—either all changes apply or none.
    • Configurable log level via LARGEFILE_LOG_LEVEL.
  • Bug Fixes

    • Clearer handling and messaging for permission-denied and write failures.
  • Chores

    • Bumped project version and updated MCP-related constraints; added dev CLI dependency.
  • Tests

    • Updated to reflect exception-based error handling and new defaults (case-insensitive by default; context_lines default 2).

Widen MCP SDK to >=1.7.0,<2.0.0 for FastMCP support and add Python logging to stderr so tool errors produce stack traces instead of being silently swallowed.
Replace manual schema definitions and dispatch table with FastMCP-decorated functions, fix parameter defaults (case_sensitive, context_lines), and suppress outputSchema generation.
Domain exceptions now raise ToolError instead of returning error dicts, so MCP clients can distinguish errors from successes. Updated all tests accordingly.
Verify tool registration, descriptions, annotations, and outputSchema suppression. Update CLAUDE.md for the new FastMCP workflow.
Batch edits are now all-or-nothing (file unchanged if any change fails). Added Field constraints to FastMCP wrappers and explicit PermissionError handling in write operations.
No longer imported anywhere; all schemas now live as FastMCP decorator annotations in server.py.
@coderabbitai

coderabbitai Bot commented Mar 14, 2026

Copy link
Copy Markdown
Contributor

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: f46fbb8d-7f4b-4b49-997a-d36693d45cae

📥 Commits

Reviewing files that changed from the base of the PR and between 0eba366 and 40ea49c.

⛔ Files ignored due to path filters (1)
  • uv.lock is excluded by !**/*.lock
📒 Files selected for processing (1)
  • pyproject.toml
🚧 Files skipped from review as they are similar to previous changes (1)
  • pyproject.toml

📝 Walkthrough

Walkthrough

Migrates the MCP server to FastMCP, exposes seven mcp.tool endpoints (overview, search, read, edit, revert, list, search_directory), centralizes logging/config, switches tools to raise ToolError, removes src/mcp_schemas.py, adds atomic batch-edit guard and explicit PermissionError handling in file writes.

Changes

Cohort / File(s) Summary
Project metadata & config
pyproject.toml, src/config.py
Bumped package version; relaxed/changed mcp requirement and added mcp[cli] as a dev dep; added log_level config sourced from LARGEFILE_LOG_LEVEL.
Server migration & MCP tools
src/server.py, src/main.py
Replaced custom server bootstrap with a FastMCP mcp instance; declared seven @mcp.tool handlers with Pydantic annotations; CLI now calls mcp.run() instead of previous main.
Schema removal
src/mcp_schemas.py
Deleted module that defined ToolsModule protocol, tool schema builders, and handler registration; schemas are now provided inline by server/tool decorators.
Error handling & logging
src/tools.py, src/editor.py, src/file_access.py
Introduced module loggers; converted tool error-return flows to raise ToolError via decorator; editor gained an all-or-nothing batch-edit guard; write paths now handle PermissionError with temp-file cleanup and clearer FileAccessError surfaces.
Tests
tests/integration/..., tests/unit/...
Updated tests to expect ToolError exceptions instead of error dicts; swapped server tests to reference FastMCP mcp; added tests for atomic batch edits and write-permission errors; adjusted defaults and assertions (e.g., case_sensitive, context_lines).

Sequence Diagram(s)

mermaid
sequenceDiagram
participant Client as rgba(70,130,180,0.5)
participant FastMCP as rgba(34,139,34,0.5)
participant ServerLogic as rgba(218,165,32,0.5)
participant FileSystem as rgba(178,34,34,0.5)
participant BackupStore as rgba(123,104,238,0.5)

Client->>FastMCP: invoke tool (e.g., edit_content)
FastMCP->>ServerLogic: dispatch to decorated handler
ServerLogic->>FileSystem: read file / compute diffs / previews
alt preview mode
ServerLogic-->>Client: return diff preview
else apply changes
ServerLogic->>BackupStore: create backup
ServerLogic->>FileSystem: attempt atomic write
alt PermissionError or edit failure
ServerLogic->>BackupStore: cleanup if needed
ServerLogic-->>FastMCP: raise ToolError
FastMCP-->>Client: return error
else success
ServerLogic-->>Client: return success with backup_id
end
end

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

🐰 I hopped through lines both old and new,

Replaced the schemas, let FastMCP chew,
Tools now speak and logs glow bright,
Edits are guarded through the night,
Backups hum — the code sleeps tight.

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Modernize MCP Server' is concise and directly reflects the main objective of the PR: migrating from the previous MCP server implementation to FastMCP, a newer SDK feature.
Docstring Coverage ✅ Passed Docstring coverage is 81.33% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch modernize-mcp
📝 Coding Plan
  • Generate coding plan for human review comments

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (5)
src/file_access.py (1)

15-16: Logger defined but unused.

The logger is created but not used in the visible code. Consider either adding log statements for important operations (e.g., file writes, backup creation) or removing the unused import and variable if logging is not planned for this module.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/file_access.py` around lines 15 - 16, The module currently defines logger
= logging.getLogger(__name__) but never uses it; either remove the logging
import and the logger variable or add appropriate log statements (e.g.,
info/debug/error) in key functions such as any file write/backup-related
functions (use logger.info(...) on successful writes, logger.error(...) on
exceptions, and logger.debug(...) for detailed state) so the logger symbol is
actually referenced; update imports accordingly and ensure exception handlers
call logger.exception where applicable.
tests/unit/test_file_access.py (1)

1124-1126: Use pytest.skip() instead of bare return.

Using return silently exits the test without reporting it was skipped. Using pytest.skip() properly marks the test as skipped in test reports.

♻️ Proposed fix
         # Skip on Windows where chmod doesn't restrict owner writes reliably
         if sys.platform == "win32":
-            return
+            pytest.skip("chmod doesn't restrict owner writes reliably on Windows")
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/unit/test_file_access.py` around lines 1124 - 1126, Replace the bare
early return used to skip the test on Windows with pytest.skip so the test run
records a skipped test; in tests/unit/test_file_access.py update the
sys.platform == "win32" branch to call pytest.skip("Skipping on Windows where
chmod doesn't restrict owner writes reliably") and ensure pytest is imported in
the file (add import pytest if missing), leaving the rest of the test intact.
src/editor.py (1)

13-14: Logger defined but unused.

Similar to src/file_access.py, the logger is created but not used in the visible code.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/editor.py` around lines 13 - 14, The module-level logger variable created
by logging.getLogger(__name__) is defined but never used; either remove the
unused logger declaration or use it for relevant runtime messages—e.g., replace
silent exceptions/prints in functions in this module with
logger.debug/info/warning/error calls or add a short initialization log like
logger.debug("editor module loaded")—update the logger variable (named logger)
accordingly throughout the module or delete the unused declaration.
tests/integration/test_documentation_workflows.py (1)

156-164: Cover the negative-limit case promised by the test docstring.

Line 157 says “zero or negative limit,” but the test only asserts limit=0. Add limit=-1 (parametrized) to keep intent and coverage aligned.

♻️ Suggested test tweak
-    def test_read_content_tail_mode_requires_positive_limit(self):
-        """Raises ToolError for zero or negative limit."""
+    `@pytest.mark.parametrize`("bad_limit", [0, -1])
+    def test_read_content_tail_mode_requires_positive_limit(self, bad_limit):
+        """Raises ToolError for zero or negative limit."""
         doc = self.test_data_dir / "markdown" / "fastapi-docs.md"
@@
-        with pytest.raises(ToolError, match="limit must be >= 1"):
-            read_content(str(doc), limit=0, mode="tail")
+        with pytest.raises(ToolError, match="limit must be >= 1"):
+            read_content(str(doc), limit=bad_limit, mode="tail")
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/integration/test_documentation_workflows.py` around lines 156 - 164,
Update the test_read_content_tail_mode_requires_positive_limit to assert both
zero and negative limits: parametrize the test (or loop) so it runs with limit=0
and limit=-1 and in each case call read_content(str(doc), limit=limit,
mode="tail") inside pytest.raises(ToolError, match="limit must be >= 1"); ensure
the test still skips early if the doc file doesn't exist and retains the same
error match and mode to cover the negative-limit case promised by the docstring.
tests/unit/test_search_engine.py (1)

281-289: Strengthen count_only expectation with a deterministic count assertion.

This test currently only checks that count exists. Since the fixture content is fixed, asserting the expected value will catch search regressions earlier.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/unit/test_search_engine.py` around lines 281 - 289, The
test_count_only_mode currently only asserts that "count" exists; update it to
assert the deterministic expected integer count for the fixed temp_file fixture
when calling search_content(temp_file, "error", fuzzy=False, count_only=True).
Replace or add to the existing assertion with assert result["count"] ==
<expected_count> (the known number of matches in the temp_file fixture) while
keeping the other boolean assertions (fuzzy_enabled, regex_enabled,
case_sensitive, inverted) unchanged; this ensures test_count_only_mode fails if
search_content's counting logic regresses.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/tools.py`:
- Around line 371-379: The code currently validates offset/limit/mode by raising
ToolError but still returns a dict with an "error" key when pattern is missing;
change that behavior to raise a ToolError instead of returning an error dict.
Locate the pattern-check branches (the one near the shown validation block and
the similar branch referenced at lines 416-425) and replace the dict-return path
with raise ToolError(f"pattern must be provided") or a descriptive ToolError
including the invalid/missing pattern; keep existing ToolError usage consistent
with the offset/limit/mode checks (use ToolError and the same message style).
- Around line 591-597: In revert_edit, failure handling is inconsistent: an
unknown backup_id currently results in success=False and raw filesystem
exceptions can bubble; change both to use the same public-tool failure path by
raising ToolError with descriptive messages. Specifically, in the revert_edit
function, after calling list_backups(file_path) and when validating backup_id,
raise ToolError("Unknown backup id: {backup_id}") instead of returning a
success=False dict, and wrap any filesystem operations (open/read/write/remove)
in try/except to catch OSError/IOError and re-raise as ToolError with context
(include file_path and backup_id where relevant). Ensure all early checks (file
existence, empty backups) already raise ToolError and follow the same pattern so
revert_edit consistently surfaces failures via ToolError.

In `@tests/integration/test_mcp_server.py`:
- Around line 41-42: Replace direct access to the private tool registry
(mcp._tool_manager._tools) with the public FastMCP API: call mcp.get_tools() to
get the list/iterable of tool metadata and build tool_names from that, and use
mcp.get_tool(name) when the test needs to inspect a specific tool's metadata
(name, description, output_schema, annotations). Update the assertions at the
locations that read _tool_manager._tools (lines referenced) to use set(t.name
for t in mcp.get_tools()) or similar, and replace any direct lookups into _tools
with mcp.get_tool(tool_name) to fetch metadata synchronously via the public
methods.

---

Nitpick comments:
In `@src/editor.py`:
- Around line 13-14: The module-level logger variable created by
logging.getLogger(__name__) is defined but never used; either remove the unused
logger declaration or use it for relevant runtime messages—e.g., replace silent
exceptions/prints in functions in this module with
logger.debug/info/warning/error calls or add a short initialization log like
logger.debug("editor module loaded")—update the logger variable (named logger)
accordingly throughout the module or delete the unused declaration.

In `@src/file_access.py`:
- Around line 15-16: The module currently defines logger =
logging.getLogger(__name__) but never uses it; either remove the logging import
and the logger variable or add appropriate log statements (e.g.,
info/debug/error) in key functions such as any file write/backup-related
functions (use logger.info(...) on successful writes, logger.error(...) on
exceptions, and logger.debug(...) for detailed state) so the logger symbol is
actually referenced; update imports accordingly and ensure exception handlers
call logger.exception where applicable.

In `@tests/integration/test_documentation_workflows.py`:
- Around line 156-164: Update the
test_read_content_tail_mode_requires_positive_limit to assert both zero and
negative limits: parametrize the test (or loop) so it runs with limit=0 and
limit=-1 and in each case call read_content(str(doc), limit=limit, mode="tail")
inside pytest.raises(ToolError, match="limit must be >= 1"); ensure the test
still skips early if the doc file doesn't exist and retains the same error match
and mode to cover the negative-limit case promised by the docstring.

In `@tests/unit/test_file_access.py`:
- Around line 1124-1126: Replace the bare early return used to skip the test on
Windows with pytest.skip so the test run records a skipped test; in
tests/unit/test_file_access.py update the sys.platform == "win32" branch to call
pytest.skip("Skipping on Windows where chmod doesn't restrict owner writes
reliably") and ensure pytest is imported in the file (add import pytest if
missing), leaving the rest of the test intact.

In `@tests/unit/test_search_engine.py`:
- Around line 281-289: The test_count_only_mode currently only asserts that
"count" exists; update it to assert the deterministic expected integer count for
the fixed temp_file fixture when calling search_content(temp_file, "error",
fuzzy=False, count_only=True). Replace or add to the existing assertion with
assert result["count"] == <expected_count> (the known number of matches in the
temp_file fixture) while keeping the other boolean assertions (fuzzy_enabled,
regex_enabled, case_sensitive, inverted) unchanged; this ensures
test_count_only_mode fails if search_content's counting logic regresses.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 77008338-f1b8-43af-b2ad-cefb4737cf9c

📥 Commits

Reviewing files that changed from the base of the PR and between e3f50f4 and 64af159.

⛔ Files ignored due to path filters (1)
  • uv.lock is excluded by !**/*.lock
📒 Files selected for processing (19)
  • pyproject.toml
  • src/config.py
  • src/editor.py
  • src/file_access.py
  • src/main.py
  • src/mcp_schemas.py
  • src/server.py
  • src/tools.py
  • tests/integration/test_directory_workflows.py
  • tests/integration/test_documentation_workflows.py
  • tests/integration/test_mcp_server.py
  • tests/integration/test_search_directory_workflows.py
  • tests/unit/test_editor.py
  • tests/unit/test_file_access.py
  • tests/unit/test_revert_edit.py
  • tests/unit/test_search_engine.py
  • tests/unit/test_tools.py
  • tests/unit/test_tools_list_directory.py
  • tests/unit/test_tools_search_directory.py
💤 Files with no reviewable changes (1)
  • src/mcp_schemas.py

Comment thread src/tools.py
Comment thread src/tools.py
Comment thread tests/integration/test_mcp_server.py Outdated
@codecov

codecov Bot commented Mar 14, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 78.66667% with 16 lines in your changes missing coverage. Please review.
✅ Project coverage is 89.86%. Comparing base (e3f50f4) to head (40ea49c).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
src/server.py 77.41% 7 Missing ⚠️
src/tools.py 80.64% 6 Missing ⚠️
src/main.py 0.00% 2 Missing ⚠️
src/file_access.py 83.33% 1 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main       #9      +/-   ##
==========================================
+ Coverage   89.03%   89.86%   +0.82%     
==========================================
  Files          12       11       -1     
  Lines        1478     1490      +12     
==========================================
+ Hits         1316     1339      +23     
+ Misses        162      151      -11     
Files with missing lines Coverage Δ
src/config.py 100.00% <100.00%> (ø)
src/editor.py 84.25% <100.00%> (+0.29%) ⬆️
src/file_access.py 84.73% <83.33%> (-0.03%) ⬇️
src/main.py 0.00% <0.00%> (ø)
src/tools.py 96.82% <80.64%> (-1.09%) ⬇️
src/server.py 78.12% <77.41%> (+11.45%) ⬆️

... and 1 file with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

…I in tests

- read_content pattern-not-found now raises ToolError instead of returning error dict
- revert_edit unknown backup_id now raises ToolError instead of returning success=False
- revert_edit filesystem operations wrapped in try/except for PermissionError/OSError
- MCP server tests use list_tools()/get_tool() instead of private _tools dict

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/tools.py (2)

416-423: ⚠️ Potential issue | 🟡 Minor

The retry hint is misleading in this branch.

Line 418 already does a fuzzy search, so telling callers to switch to search_content “for fuzzy matching” points them at a capability they already used.

✏️ Suggested patch
         if not matches:
             raise ToolError(
                 f"Pattern '{pattern}' not found in file. "
-                f"Try a different search term or use search_content for fuzzy matching."
+                "Try a different search term, or use search_content to explore the file first."
             )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/tools.py` around lines 416 - 423, The error message when no matches are
found after calling search_file(canonical_path, pattern, fuzzy=True) is
misleading; update the ToolError raised in that branch to remove the suggestion
to use search_content for fuzzy matching and instead provide an accurate hint
(e.g., suggest a different search term or turning off fuzzy matching) so callers
aren’t directed to a capability already used by search_file; locate the block
that calls search_file(...) and raises ToolError and replace the message text
accordingly.

215-223: ⚠️ Potential issue | 🟠 Major

Preserve the existing search defaults or treat this as a breaking API change.

These public tool signatures now default to case-insensitive matching, and search_content() also returns less context by default. Any caller that omits those fields will start getting different results after what otherwise looks like an MCP SDK refactor.

↩️ Suggested patch
 def search_content(
     absolute_file_path: str,
     pattern: str,
     max_results: int = 20,
-    context_lines: int = 2,
+    context_lines: int = 3,
     fuzzy: bool = True,
     regex: bool = False,
-    case_sensitive: bool = False,
+    case_sensitive: bool = True,
     invert: bool = False,
     count_only: bool = False,
 ) -> dict:
@@
-    - case_sensitive: Case sensitive search (default False)
+    - case_sensitive: Case sensitive search (default True)
@@
-        if context_lines != 2:
+        if context_lines != 3:
             warnings.append("context_lines ignored in count_only mode")
@@
 def search_directory(
@@
-    case_sensitive: bool = False,
+    case_sensitive: bool = True,
@@
-        case_sensitive: Case-sensitive search (default False).
+        case_sensitive: Case-sensitive search (default True).

Also applies to: 239-240, 251-255, 864-873, 895-896

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/tools.py` around lines 215 - 223, search_content() and other public tool
function signatures were changed to default to case-insensitive and reduced
context, which is a breaking change; revert the defaults to the original
behavior by setting search_content's parameters back to the previous defaults
(restore case_sensitive=True and context_lines to the previous value), and apply
the same restoration to the other public tool signatures referenced in the
review (the functions around the other noted ranges) so callers receive the same
results as before. Ensure you only change the default parameter values (e.g., in
search_content) and do not alter the function signatures or behavior otherwise.
🧹 Nitpick comments (1)
tests/unit/test_revert_edit.py (1)

126-176: Add coverage for the new revert-copy failure branch.

These tests cover the early ToolError cases, but they never hit the new PermissionError/OSError handling around the actual restore in src/tools.py. A regression there would still leak a raw filesystem exception unnoticed.

🧪 Suggested patch
 class TestRevertErrors:
@@
     def test_revert_nonexistent_file(self):
         """Raises ToolError for missing file."""
         with tempfile.TemporaryDirectory() as backup_dir:
             with patch("src.file_access.config") as mock_config:
                 mock_config.backup_dir = backup_dir

                 with patch("src.tools.config", mock_config):
                     with pytest.raises(ToolError, match="does not exist"):
                         revert_edit("/nonexistent/path/file.txt")
+
+    def test_revert_copy_failure_raises_tool_error(self):
+        """Raises ToolError when restoring the backup fails."""
+        with tempfile.NamedTemporaryFile(mode="w", delete=False, suffix=".txt") as f:
+            f.write("content")
+            temp_path = f.name
+
+        with tempfile.TemporaryDirectory() as backup_dir:
+            with patch("src.file_access.config") as mock_config:
+                mock_config.backup_dir = backup_dir
+                mock_config.max_backups = 10
+                mock_config.memory_threshold = 50 * 1024 * 1024
+
+                create_backup(temp_path)
+                Path(temp_path).write_text("modified")
+
+                with patch("src.tools.config", mock_config), patch(
+                    "src.tools.shutil.copy2", side_effect=PermissionError("denied")
+                ):
+                    with pytest.raises(ToolError, match="Failed to revert file"):
+                        revert_edit(temp_path)
+
+        Path(temp_path).unlink(missing_ok=True)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/unit/test_revert_edit.py` around lines 126 - 176, Add a test that
exercises the restore I/O failure branch by creating a real backup (use
create_backup(temp_path)), then patching the filesystem copy/restore routine
used by revert_edit (e.g., patch "shutil.copyfile" or "pathlib.Path.replace"
depending on which src/tools.py calls) to raise PermissionError and/or OSError,
call revert_edit(target_path) and assert it raises a ToolError (not the raw
PermissionError/OSError) with an appropriate failure message; ensure you still
set up mock_config.backup_dir/max_backups as in other tests and clean up the
temp file.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@src/tools.py`:
- Around line 416-423: The error message when no matches are found after calling
search_file(canonical_path, pattern, fuzzy=True) is misleading; update the
ToolError raised in that branch to remove the suggestion to use search_content
for fuzzy matching and instead provide an accurate hint (e.g., suggest a
different search term or turning off fuzzy matching) so callers aren’t directed
to a capability already used by search_file; locate the block that calls
search_file(...) and raises ToolError and replace the message text accordingly.
- Around line 215-223: search_content() and other public tool function
signatures were changed to default to case-insensitive and reduced context,
which is a breaking change; revert the defaults to the original behavior by
setting search_content's parameters back to the previous defaults (restore
case_sensitive=True and context_lines to the previous value), and apply the same
restoration to the other public tool signatures referenced in the review (the
functions around the other noted ranges) so callers receive the same results as
before. Ensure you only change the default parameter values (e.g., in
search_content) and do not alter the function signatures or behavior otherwise.

---

Nitpick comments:
In `@tests/unit/test_revert_edit.py`:
- Around line 126-176: Add a test that exercises the restore I/O failure branch
by creating a real backup (use create_backup(temp_path)), then patching the
filesystem copy/restore routine used by revert_edit (e.g., patch
"shutil.copyfile" or "pathlib.Path.replace" depending on which src/tools.py
calls) to raise PermissionError and/or OSError, call revert_edit(target_path)
and assert it raises a ToolError (not the raw PermissionError/OSError) with an
appropriate failure message; ensure you still set up
mock_config.backup_dir/max_backups as in other tests and clean up the temp file.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 7b242477-7010-4eef-8887-1337edbef6e1

📥 Commits

Reviewing files that changed from the base of the PR and between 64af159 and 0eba366.

📒 Files selected for processing (4)
  • src/tools.py
  • tests/integration/test_mcp_server.py
  • tests/unit/test_revert_edit.py
  • tests/unit/test_tools.py
🚧 Files skipped from review as they are similar to previous changes (2)
  • tests/unit/test_tools.py
  • tests/integration/test_mcp_server.py

@peteretelej
peteretelej merged commit 34f038a into main Mar 15, 2026
5 checks passed
@peteretelej
peteretelej deleted the modernize-mcp branch March 15, 2026 07:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant