Skip to content

Modernize MCP Server#11

Merged
peteretelej merged 12 commits intomainfrom
modernize-mcp
Mar 15, 2026
Merged

Modernize MCP Server#11
peteretelej merged 12 commits intomainfrom
modernize-mcp

Conversation

@peteretelej
Copy link
Owner

@peteretelej peteretelej commented Mar 14, 2026

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

    • Per-call chunk-size override for diff processing.
    • Case-insensitive file matching for queries and retrievals.
    • Service now exposes function-based tool endpoints (new startup flow).
  • Bug Fixes

    • More actionable and consistent error messages, including clearer out-of-range chunk wording.
    • Improved matching behavior with better guidance when multiple/no matches found.
  • Documentation

    • Design docs updated to reflect new tool/resource behavior and error guidance.
  • Chores

    • Tightened dependency range; added .gitattributes for LF endings.
  • Tests

    • Added case-insensitive tests; removed legacy server-related tests and updated timing tolerances.

Replace the class-based DiffChunkServer with module-level FastMCP wiring,
removing the manual tool dispatcher and isError suppression. Tool annotations
and structured_output=False are set on all tools.
Pass max_chunk_lines as a parameter instead of mutating shared state,
add structured logging to stderr, and make error messages actionable
for LLM self-correction.
Rewrite server-layer tests to exercise the real MCP protocol path,
testing tool discovery, annotations, error propagation with isError,
and resource access through create_connected_server_and_client_session.
Make pattern matching case-insensitive in find_chunks_for_files and
get_file_diff, add .gitattributes for LF line endings in test data,
and update docs/design.md to reflect FastMCP architecture.
The old test_handle_call_tool and test_server_error_handling files tested
the manual dispatcher that was replaced by FastMCP. Equivalent coverage
now exists in the protocol-level tests.
@coderabbitai
Copy link

coderabbitai bot commented Mar 14, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Replaces class-based MCP server with FastMCP module-level tools/resources, adds per-call max_chunk_lines for chunking, makes file-pattern matching case-insensitive, adds logging/timing and improved error messages, tightens MCP dependency range, updates docs, and adjusts tests (removals and expectation changes).

Changes

Cohort / File(s) Summary
FastMCP server & entry
src/server.py, src/main.py
Replaces DiffChunkServer class with a top-level mcp (FastMCP) exposing decorated resources/tools (current_overview, load_diff, list_chunks, get_chunk, find_chunks_for_files, get_file_diff); main now calls mcp.run() and handles KeyboardInterrupt/CancelledError.
Chunking API
src/chunker.py, src/tools.py
Adds optional per-call max_chunk_lines to DiffChunker.chunk_diff and _split_large_file, propagates it through split logic; tools call chunking with this parameter and update splitting thresholds.
Case-insensitive matching & tests
src/models.py, tests/test_case_insensitive.py
File matching logic changed to case-insensitive (lowercasing paths/patterns and case-insensitive glob matching); adds tests validating case-insensitive matching and retrieval.
Logging / parser
src/parser.py, src/tools.py
Introduces module-level diffchunk logger, emits debug when encoding detected, and logs/times diff loading and chunking operations with enhanced messages.
Docs & packaging
docs/design.md, pyproject.toml, .gitattributes
Docs updated to describe FastMCP decorator-based tools/resources, actionable error guidance, and file-matching notes; pyproject.toml tightens MCP to mcp>=1.7.0,<2.0.0; adds .gitattributes to enforce LF for diffs/test data.
Tests: removals & expectations
tests/test_handle_call_tool.py, tests/test_server_error_handling.py, tests/test_mcp_components.py, tests/test_filesystem_edge_cases.py, tests/test_integration.py, tests/test_get_file_diff.py
Removes tests tied to the old class-based MCP server and server error suite; updates several assertions/messages/regexes to new wording (e.g., "does not exist"); adjusts timeouts and platform waits in CLI integration tests.
Misc & formatting
tests/*, src/*
Minor wording/formatting adjustments across docs, tests, and code to align with FastMCP-based implementation, updated error messages, and logging additions.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant FastMCP as mcp (FastMCP)
    participant Tools as DiffChunkTools
    participant FS as FileSystem

    Client->>FastMCP: Call tool (e.g., load_diff / find_chunks_for_files)
    FastMCP->>Tools: Invoke tool function with params (path, max_chunk_lines, patterns)
    Tools->>FS: Read diff file / list files
    FS-->>Tools: Return diff content / file list
    Tools-->>FastMCP: Return JSON or raw string result
    FastMCP-->>Client: Return tool response (success or error)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Poem

🐇 I hopped from classes to tools so spry,
FastMCP hums while chunks neatly fly,
Uppercase and lowercase dance in a line,
Timers tick, logs sparkle — all working fine,
I nibble diffs and bound away ✨

🚥 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' directly reflects the main objective of replacing the class-based MCP server with a FastMCP-based, function-driven implementation across multiple files.
Docstring Coverage ✅ Passed Docstring coverage is 90.32% 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.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (3)
tests/test_case_insensitive.py (2)

49-56: Test doesn't verify uppercase directory behavior as intended.

Both all_chunks and upper_all use the identical pattern "*". This test effectively verifies that the same pattern returns the same result, not that uppercase patterns work correctly.

Consider using a directory-based pattern like "SRC/*" vs "src/*" to actually test case-insensitive directory matching.

♻️ Proposed fix
     def test_find_chunks_uppercase_directory(self, tools, react_diff_file):
         """find_chunks_for_files with uppercase dir pattern matches."""
         tools.load_diff(react_diff_file)
-        all_chunks = tools.find_chunks_for_files(react_diff_file, "*")
-        assert len(all_chunks) > 0
-        # Uppercase wildcard should match the same set
-        upper_all = tools.find_chunks_for_files(react_diff_file, "*")
-        assert all_chunks == upper_all
+        # Test case-insensitive directory matching if applicable
+        lower_chunks = tools.find_chunks_for_files(react_diff_file, "packages/*")
+        upper_chunks = tools.find_chunks_for_files(react_diff_file, "PACKAGES/*")
+        assert lower_chunks == upper_chunks
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/test_case_insensitive.py` around lines 49 - 56, The test
test_find_chunks_uppercase_directory currently calls tools.find_chunks_for_files
twice with the same pattern "*", so it doesn't verify case-insensitive directory
matching; update the second call to use an uppercase directory pattern (e.g.,
"SRC/*" or the uppercase variant of the directory in react_diff_file) when
invoking tools.find_chunks_for_files so the assertion all_chunks == upper_all
actually verifies that an uppercase directory pattern matches the same set of
chunks as the lowercase pattern.

80-93: Potential test fragility if first file has no extension.

The test assumes chunks[0]["files"][0] contains a file with an extension. If the first file lacks an extension, the test silently skips the assertion without validating case-insensitive glob behavior.

Additionally, if the uppercase pattern matches multiple files, get_file_diff will raise a ValueError for ambiguous matches.

♻️ Proposed fix to make the test more robust
     def test_get_file_diff_case_insensitive_glob(self, tools, react_diff_file):
         """get_file_diff glob matching is case-insensitive."""
         tools.load_diff(react_diff_file)

         chunks = tools.list_chunks(react_diff_file)
-        # Find a file that has a unique extension to use as glob pattern
-        file_name = chunks[0]["files"][0]
+        # Find a file with an extension for the test
+        file_name = None
+        for chunk in chunks:
+            for f in chunk["files"]:
+                if "." in f:
+                    file_name = f
+                    break
+            if file_name:
+                break
+        
+        if not file_name:
+            pytest.skip("No file with extension found in diff")

         # If the file has an extension, try matching with different case
-        if "." in file_name:
-            base, ext = file_name.rsplit(".", 1)
-            upper_pattern = f"{base.upper()}.{ext.upper()}"
-            result = tools.get_file_diff(react_diff_file, upper_pattern)
-            assert "diff --git" in result
+        base, ext = file_name.rsplit(".", 1)
+        upper_pattern = f"{base.upper()}.{ext.upper()}"
+        result = tools.get_file_diff(react_diff_file, upper_pattern)
+        assert "diff --git" in result
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/test_case_insensitive.py` around lines 80 - 93, The test assumes the
first file has an extension and is unique; make it robust by scanning all files
from tools.list_chunks(react_diff_file) (use chunks = tools.list_chunks(...) and
iterate chunks[*]["files"]) to find a file_name that contains a "." and whose
uppercase pattern is unique among all files when uppercased, then build
upper_pattern = f"{base.upper()}.{ext.upper()}" and call
tools.get_file_diff(react_diff_file, upper_pattern) and assert "diff --git" in
the result; if no such uniquely-matchable file is found, explicitly fail the
test (raise AssertionError) so the test doesn't silently skip.
src/server.py (1)

53-53: Consider shortening the docstring.

The docstring is quite lengthy (single line with ~500+ characters). While comprehensive guidance for LLMs is valuable, this might be better structured as a shorter docstring with key points, potentially moving detailed usage notes to the design documentation.

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

In `@src/server.py` at line 53, Replace the overly long triple-quoted docstring
that begins "Parse and load a diff file with custom chunking settings..." with a
concise 1–2 sentence summary stating the function's purpose and the critical
constraints (e.g., must use absolute path; use diffchunk tools for large diffs);
move the detailed usage notes and examples into the project design/README docs
and update the docstring to end with a short "See design docs for details"
pointer so callers get the essentials quickly while preserving full guidance
elsewhere.
🤖 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/server.py`:
- Line 30: Import ToolAnnotations from mcp.types and replace the five
occurrences of annotations={"readOnlyHint": True} (the annotations argument in
the `@mcp.tool` decorator usages in this module) with a ToolAnnotations instance,
e.g. annotations=ToolAnnotations(readOnlyHint=True), so the decorator argument
matches the declared type; ensure you add the import line (from mcp.types import
ToolAnnotations) and update each `@mcp.tool`(...) decorator accordingly.

---

Nitpick comments:
In `@src/server.py`:
- Line 53: Replace the overly long triple-quoted docstring that begins "Parse
and load a diff file with custom chunking settings..." with a concise 1–2
sentence summary stating the function's purpose and the critical constraints
(e.g., must use absolute path; use diffchunk tools for large diffs); move the
detailed usage notes and examples into the project design/README docs and update
the docstring to end with a short "See design docs for details" pointer so
callers get the essentials quickly while preserving full guidance elsewhere.

In `@tests/test_case_insensitive.py`:
- Around line 49-56: The test test_find_chunks_uppercase_directory currently
calls tools.find_chunks_for_files twice with the same pattern "*", so it doesn't
verify case-insensitive directory matching; update the second call to use an
uppercase directory pattern (e.g., "SRC/*" or the uppercase variant of the
directory in react_diff_file) when invoking tools.find_chunks_for_files so the
assertion all_chunks == upper_all actually verifies that an uppercase directory
pattern matches the same set of chunks as the lowercase pattern.
- Around line 80-93: The test assumes the first file has an extension and is
unique; make it robust by scanning all files from
tools.list_chunks(react_diff_file) (use chunks = tools.list_chunks(...) and
iterate chunks[*]["files"]) to find a file_name that contains a "." and whose
uppercase pattern is unique among all files when uppercased, then build
upper_pattern = f"{base.upper()}.{ext.upper()}" and call
tools.get_file_diff(react_diff_file, upper_pattern) and assert "diff --git" in
the result; if no such uniquely-matchable file is found, explicitly fail the
test (raise AssertionError) so the test doesn't silently skip.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 05e40a3c-7fa2-4922-909a-45d15c6a180a

📥 Commits

Reviewing files that changed from the base of the PR and between c8384d4 and 2810fe2.

⛔ Files ignored due to path filters (1)
  • uv.lock is excluded by !**/*.lock
📒 Files selected for processing (16)
  • .gitattributes
  • docs/design.md
  • pyproject.toml
  • src/chunker.py
  • src/main.py
  • src/models.py
  • src/parser.py
  • src/server.py
  • src/tools.py
  • tests/test_case_insensitive.py
  • tests/test_filesystem_edge_cases.py
  • tests/test_get_file_diff.py
  • tests/test_handle_call_tool.py
  • tests/test_integration.py
  • tests/test_mcp_components.py
  • tests/test_server_error_handling.py
💤 Files with no reviewable changes (3)
  • tests/test_server_error_handling.py
  • tests/test_mcp_components.py
  • tests/test_handle_call_tool.py

Use ToolAnnotations model instead of plain dicts for the annotations
parameter on @mcp.tool decorators.
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 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/server.py`:
- Line 22: The global instantiation tools = DiffChunkTools() creates shared
mutable state across requests; instead instantiate DiffChunkTools per
client/session and remove the module-global tools. Locate where request handling
or session lifecycle is created (the server request handler or session
initializer) and create a new DiffChunkTools() there, pass that instance into
handlers/functions that currently reference the global tools (or attach it to
the request/session context), and ensure any code using current_overview/tool
calls reads from the per-session instance rather than the removed global
variable.
- Line 54: The docstrings that state "CRITICAL: You must use an absolute
directory path - relative paths will fail." should be changed to recommend
absolute paths instead of requiring them; update the occurrences matching the
shown docstring text (the long diff-file parsing description) and the other
docstrings at the same wording (lines referenced) to read something like
"absolute path recommended" or "an absolute directory path is recommended;
relative paths may still work." Keep the rest of the guidance intact and, if you
prefer stronger enforcement instead of wording changes, add an explicit runtime
check (os.path.isabs) in the relevant loader/parsing functions and raise a clear
ValueError to match documentation—otherwise only change the docstring text in
each affected docstring occurrence.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 3493f399-b1d7-41a8-bcf7-478ad40b0157

📥 Commits

Reviewing files that changed from the base of the PR and between 2810fe2 and 155dffa.

📒 Files selected for processing (1)
  • src/server.py

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 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/chunker.py`:
- Around line 23-26: The current assignment "max_chunk_lines = max_chunk_lines
or self.max_chunk_lines" treats 0 as falsey and incorrectly falls back to
self.max_chunk_lines; change it to use an explicit None check (if
max_chunk_lines is None: max_chunk_lines = self.max_chunk_lines) and then
validate the resulting value (ensure it's an int and greater than 0, otherwise
raise a ValueError) for the method that accepts the parameter max_chunk_lines so
per-call 0 is not silently ignored.

In `@src/tools.py`:
- Around line 109-115: The logger.info call currently logs the full
absolute_file_path which can leak local paths; change the info-level message in
the function that calls logger.info (the block using absolute_file_path and
session.stats) to log a sanitized identifier instead (e.g.,
os.path.basename(absolute_file_path) or session.id) and move the full
absolute_file_path to a logger.debug message; update the info call text to
include basename/session id and keep session.stats.chunks_count,
session.stats.total_files and elapsed unchanged, and add a separate logger.debug
that logs the full absolute_file_path for troubleshooting.
- Around line 221-240: The current matching logic loses case-distinct exact
filenames; change the sequence so you first try a case-sensitive exact match
(compare f == file_path) and if that yields results use it, otherwise fall back
to the existing case-insensitive exact match (f.lower() == file_path.lower())
and then the case-insensitive glob (fnmatch.fnmatch(f.lower(),
file_path.lower())). Update the block that builds matches (the variables
matches, all_files, file_path and the fnmatch call) so a true exact
(case-sensitive) match is preserved before any case-insensitive fallback.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 25ddbbdb-6fec-4b2b-8bd0-2c500b6f6167

📥 Commits

Reviewing files that changed from the base of the PR and between 155dffa and f44381c.

📒 Files selected for processing (3)
  • src/chunker.py
  • src/tools.py
  • tests/test_case_insensitive.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • tests/test_case_insensitive.py

@codecov
Copy link

codecov bot commented Mar 14, 2026

Codecov Report

❌ Patch coverage is 69.73684% with 23 lines in your changes missing coverage. Please review.
✅ Project coverage is 91.54%. Comparing base (c8384d4) to head (95d84e1).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main      #11      +/-   ##
==========================================
- Coverage   94.11%   91.54%   -2.58%     
==========================================
  Files           7        7              
  Lines         459      461       +2     
==========================================
- Hits          432      422      -10     
- Misses         27       39      +12     
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

…le matching

- Use explicit None check for max_chunk_lines instead of truthy check that swallows 0
- Add case-sensitive exact match before case-insensitive fallback in get_file_diff
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

♻️ Duplicate comments (1)
src/tools.py (1)

109-115: ⚠️ Potential issue | 🟡 Minor

Avoid logging full local paths at INFO level.

Line 111 logs the caller-supplied absolute_file_path at INFO level on every load. For an MCP service, this can expose usernames and workspace structure from local absolute paths. Consider logging a sanitized identifier (e.g., basename) at INFO and keeping the full path at DEBUG.

Suggested fix
         logger.info(
             "Parsed and chunked %s: %d chunks, %d files in %.2fs",
-            absolute_file_path,
+            os.path.basename(resolved_file_path),
             session.stats.chunks_count,
             session.stats.total_files,
             elapsed,
         )
+        logger.debug("Full path: %s", resolved_file_path)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/tools.py` around lines 109 - 115, The info-level log in logger.info
currently prints the caller-supplied absolute_file_path (and may leak local
usernames/paths); change it to log a sanitized identifier (e.g., the basename)
instead and move the full absolute_file_path to a debug-level log. Concretely,
replace usage of absolute_file_path in the info message with a sanitized name
derived from absolute_file_path (e.g., os.path.basename or Path(...).name) and
add a separate logger.debug that includes the full absolute_file_path for
troubleshooting; keep the existing session.stats and elapsed variables unchanged
in the messages.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@src/tools.py`:
- Around line 109-115: The info-level log in logger.info currently prints the
caller-supplied absolute_file_path (and may leak local usernames/paths); change
it to log a sanitized identifier (e.g., the basename) instead and move the full
absolute_file_path to a debug-level log. Concretely, replace usage of
absolute_file_path in the info message with a sanitized name derived from
absolute_file_path (e.g., os.path.basename or Path(...).name) and add a separate
logger.debug that includes the full absolute_file_path for troubleshooting; keep
the existing session.stats and elapsed variables unchanged in the messages.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a0e9fff8-7df1-49f0-b7e8-3725c25d65b1

📥 Commits

Reviewing files that changed from the base of the PR and between f44381c and 785c47e.

📒 Files selected for processing (2)
  • src/chunker.py
  • src/tools.py

Flush stderr prints before mcp.run() to ensure startup messages are
captured on Windows. Increase test timeouts for slower CI environments.
Log only basename at INFO level to avoid leaking user paths.
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (2)
src/server.py (1)

22-29: ⚠️ Potential issue | 🟠 Major

Process-global DiffChunkTools still shares one cache across all clients.

current_overview() and every tool use the same DiffChunkTools.sessions map, so loaded diffs can leak between MCP clients and concurrent requests mutate shared state. Scope DiffChunkTools to the connection/session unless this server is explicitly single-tenant.

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

In `@src/server.py` around lines 22 - 29, The issue is that a module-level
DiffChunkTools instance (tools) shares DiffChunkTools.sessions across all
clients causing state leakage; remove the global "tools" and instead create or
attach a DiffChunkTools per connection/session: either instantiate
DiffChunkTools inside the handler (current_overview) or, better, create it
during connection setup and store it on the MCP connection/context (use FastMCP
connection/session hook or attach to the mcp object) and then reference that
per-connection instance in current_overview and all resource handlers so
DiffChunkTools.sessions is scoped to each client rather than shared globally.
src/tools.py (1)

77-80: ⚠️ Potential issue | 🟡 Minor

Don't require absolute paths in the error text unless the loader enforces it.

Line 69 already normalizes relative inputs with expanduser() and realpath(), so this message currently tells users a supported path form is invalid. Either add an explicit os.path.isabs() check or soften the wording to “absolute path recommended.”

Suggested wording
-                f"Diff file not found: {absolute_file_path}. Verify the file exists and the path is absolute."
+                f"Diff file not found: {absolute_file_path}. Verify the file exists and the path is correct."
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/tools.py` around lines 77 - 80, The error message incorrectly demands an
absolute path despite normalizing inputs with expanduser()/realpath(); update
the ValueError raised where resolved_file_path and absolute_file_path are used
to either (a) first check os.path.isabs(absolute_file_path) and raise a
distinct, explicit error about requiring an absolute path, or (b) more simply
soften the existing message to something like "Diff file not found:
{absolute_file_path}. Verify the file exists (absolute path recommended)."
Modify the ValueError text accordingly and keep the check on resolved_file_path
the same.
🧹 Nitpick comments (1)
src/server.py (1)

15-19: Avoid configuring the root logger when this module is imported.

src.main imports src.server before parsing args, so every CLI path—and any embedding consumer—gets this global logging setup as a side effect. Move it into the CLI entry point, or only configure logging when no handlers are already attached.

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

In `@src/server.py` around lines 15 - 19, The module currently calls
logging.basicConfig at import time which configures the root logger as a side
effect; remove or guard that call in src.server so importing the module doesn't
change global logging: either move the logging.basicConfig invocation into the
CLI entry point (where args are parsed) or wrap it so it only runs when no
handlers exist (e.g., check logging.getLogger().handlers or use if not
logging.getLogger().hasHandlers()) before calling logging.basicConfig; update
any tests or startup code that relied on the import-time configuration
accordingly.
🤖 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/server.py`:
- Line 95: The file has unformatted long logger.info calls (e.g.,
logger.info("get_chunk: %s chunk=%d", os.path.basename(absolute_file_path),
chunk_number) and similar calls at the other locations) causing the ruff format
check to fail; run ruff format (or your project's formatter) on src/server.py
and rewrap/format the long logger.info calls so they conform to the project's
line-length/formatting rules (ensure the calls in the get_chunk logging and the
two other logger.info occurrences are line-broken or reformatted by the
formatter).

---

Duplicate comments:
In `@src/server.py`:
- Around line 22-29: The issue is that a module-level DiffChunkTools instance
(tools) shares DiffChunkTools.sessions across all clients causing state leakage;
remove the global "tools" and instead create or attach a DiffChunkTools per
connection/session: either instantiate DiffChunkTools inside the handler
(current_overview) or, better, create it during connection setup and store it on
the MCP connection/context (use FastMCP connection/session hook or attach to the
mcp object) and then reference that per-connection instance in current_overview
and all resource handlers so DiffChunkTools.sessions is scoped to each client
rather than shared globally.

In `@src/tools.py`:
- Around line 77-80: The error message incorrectly demands an absolute path
despite normalizing inputs with expanduser()/realpath(); update the ValueError
raised where resolved_file_path and absolute_file_path are used to either (a)
first check os.path.isabs(absolute_file_path) and raise a distinct, explicit
error about requiring an absolute path, or (b) more simply soften the existing
message to something like "Diff file not found: {absolute_file_path}. Verify the
file exists (absolute path recommended)." Modify the ValueError text accordingly
and keep the check on resolved_file_path the same.

---

Nitpick comments:
In `@src/server.py`:
- Around line 15-19: The module currently calls logging.basicConfig at import
time which configures the root logger as a side effect; remove or guard that
call in src.server so importing the module doesn't change global logging: either
move the logging.basicConfig invocation into the CLI entry point (where args are
parsed) or wrap it so it only runs when no handlers exist (e.g., check
logging.getLogger().handlers or use if not logging.getLogger().hasHandlers())
before calling logging.basicConfig; update any tests or startup code that relied
on the import-time configuration accordingly.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b7f24515-331a-49e6-994b-0a71f3f929a3

📥 Commits

Reviewing files that changed from the base of the PR and between 785c47e and c76188f.

📒 Files selected for processing (4)
  • src/main.py
  • src/server.py
  • src/tools.py
  • tests/test_cli_integration.py

Replace bash script with minimal sh-compatible hook targeting src/ and tests/ directories.
@peteretelej peteretelej merged commit b75d40c into main Mar 15, 2026
7 checks passed
@peteretelej peteretelej deleted the modernize-mcp branch March 15, 2026 07:49
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