Skip to content

mcp-hmr#39

Merged
CNSeniorious000 merged 9 commits intoreadmefrom
mcp
Oct 18, 2025
Merged

mcp-hmr#39
CNSeniorious000 merged 9 commits intoreadmefrom
mcp

Conversation

@CNSeniorious000
Copy link
Copy Markdown
Member

@CNSeniorious000 CNSeniorious000 commented Oct 17, 2025

Summary by CodeRabbit

  • New Features

    • Hot-module-reload (HMR) for MCP/FastMCP servers to auto-reload on code changes without dropping connections.
    • Command‑line tool to run MCP servers with HMR enabled.
  • Documentation

    • README with usage instructions, compatibility notes, and examples for running servers with HMR.
  • Chores

    • Packaging and project configuration added to publish and install the HMR tool; workspace and CI matrix updated to include the new package.

@hyperlint-ai-deprecated
Copy link
Copy Markdown

PR Change Summary

Added documentation for the mcp-hmr package.

  • Introduced a new README file for the mcp-hmr package
  • Provided an overview of the package functionality
  • Included installation and usage instructions

Added Files

  • packages/mcp-hmr/README.md

How can I customize these reviews?

Check out the Hyperlint AI Reviewer docs for more information on how to customize the review.

If you just want to ignore it on this PR, you can add the hyperlint-ignore label to the PR. Future changes won't trigger a Hyperlint review.

Note specifically for link checks, we only check the first 30 links in a file and we cache the results for several hours (for instance, if you just added a page, you might experience this). Our recommendation is to add hyperlint-ignore to the PR to ignore the link check for this PR.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Oct 17, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

📝 Walkthrough

Walkthrough

Adds a new mcp-hmr package that provides hot-module-reload for MCP/FastMCP servers: new HMR runtime module with runner and CLI, package metadata and CLI entry, README, workspace registration, and CI publish matrix inclusion.

Changes

Cohort / File(s) Summary
HMR Module Implementation
packages/mcp-hmr/mcp_hmr.py
New module implementing HMR runtime: `run_with_hmr(target: str, log_level: str
Package Configuration
packages/mcp-hmr/pyproject.toml
New pyproject declaring project metadata, dynamic versioning via PDM, Python requirement, dependencies (fastmcp >=2.2.0,<3, hmr ~=0.7.0), pdm version tool pointing to mcp_hmr.py, pdm-backend build-system, and CLI entry point mcp-hmr = mcp_hmr:cli.
Package README
packages/mcp-hmr/README.md
New README describing purpose, compatibility, usage (mcp-hmr path.to.main:app), and HMR behavior for MCP/FastMCP servers.
Repository config
pyproject.toml
Root pyproject.toml updated to add mcp-hmr to project dependencies and register it as a workspace/source under [tool.uv.sources].
CI matrix
.github/workflows/ci.yml
CI publish matrix extended to include mcp-hmr as a publish target.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

✨ A watcher wakes when source files sing,
It mounts a proxy, then tugs at each string.
Async signals hush, then blossom bright,
Old mounts step down — new code takes flight.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title Check ❓ Inconclusive The pull request title is simply "mcp-hmr," which is the name of the new package being introduced. While the title is directly related to the changeset content—the PR introduces this new module—it lacks meaningful descriptive information about what changed. A teammate scanning the history would only see a package name without understanding whether this is an addition, modification, removal, or something else. The title is too vague to convey the primary nature of the change.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch mcp

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between baeb813 and fad2b48.

📒 Files selected for processing (1)
  • packages/mcp-hmr/mcp_hmr.py (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/mcp-hmr/mcp_hmr.py
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Link Check
  • GitHub Check: Sourcery review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Copy link
Copy Markdown

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

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

Hey there - I've reviewed your changes - here's some feedback:

  • Verify that the hmr~=0.7.0 dependency actually provides the reactivity and reactivity.hmr modules you import (or add the correct package name).
  • Rather than mutating private _mounted_servers lists in mount(), see if there’s a public unmount API to reduce fragility if internals change.
  • Make sure your pyproject.toml explicitly includes the mcp_hmr module (via packages or modules) so it isn’t left out of the published distribution.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- Verify that the hmr~=0.7.0 dependency actually provides the reactivity and reactivity.hmr modules you import (or add the correct package name).
- Rather than mutating private `_mounted_servers` lists in mount(), see if there’s a public unmount API to reduce fragility if internals change.
- Make sure your pyproject.toml explicitly includes the mcp_hmr module (via `packages` or `modules`) so it isn’t left out of the published distribution.

## Individual Comments

### Comment 1
<location> `packages/mcp-hmr/mcp_hmr.py:22-27` </location>
<code_context>
+
+    base_app = FastMCP(include_fastmcp_meta=False)
+
+    @contextmanager
+    def mount(app: FastMCP | mcp.server.FastMCP):
+        base_app.mount(proxy := FastMCP.as_proxy(ProxyClient(app)), as_proxy=False)
+        try:
+            yield
+        finally:  # unmount
+            for mounted_server in base_app._mounted_servers:  # noqa: SLF001
+                if mounted_server.server is proxy:
</code_context>

<issue_to_address>
**issue:** Direct manipulation of private attributes may be fragile.

Accessing private attributes like _mounted_servers and _tool_manager._mounted_servers may lead to breakage if FastMCP's internals change. Please check for a public API for unmounting, or document this risk if direct access is necessary.
</issue_to_address>

### Comment 2
<location> `packages/mcp-hmr/mcp_hmr.py:48` </location>
<code_context>
+        return getattr(import_module(module), attr)
+
+    stop_event: Event | None = None
+    finish_event: Event = ...  # type: ignore
+
+    @async_effect(context=HMR_CONTEXT, call_immediately=False)
</code_context>

<issue_to_address>
**suggestion (bug_risk):** Use of '...' as a placeholder for Event may be confusing.

Using '...' with 'type: ignore' for finish_event may cause runtime errors if accessed before assignment. Initialize finish_event to None and update type hints, or guarantee it is set before use.

Suggested implementation:

```python
    stop_event: Event | None = None
    finish_event: Event | None = None

```

```python
                await stop_event.wait()
                if finish_event is not None:
                    finish_event.set()

```

```python
            if finish_event is not None:
                await finish_event.wait()

```

```python
        stop_event = Event()
        finish_event = Event()
        create_task(using(app, stop_event, finish_event))  # noqa: RUF006

```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread packages/mcp-hmr/mcp_hmr.py
Comment thread packages/mcp-hmr/mcp_hmr.py
Copy link
Copy Markdown
Contributor

@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: 5

🧹 Nitpick comments (2)
packages/mcp-hmr/mcp_hmr.py (2)

43-46: Harden get_app() error reporting.

Emit a clear message when module/attr is invalid.

-    def get_app():
-        return getattr(import_module(module), attr)
+    def get_app():
+        try:
+            mod = import_module(module)
+        except Exception as e:  # narrow if desired
+            raise ImportError(f"Failed to import module '{module}': {e}") from e
+        try:
+            return getattr(mod, attr)
+        except AttributeError as e:
+            raise AttributeError(f"Module '{module}' has no attribute '{attr}'") from e

63-66: Consider passing an explicit watch root to AsyncReloader.

"" relies on internal defaults; using CWD is clearer and may avoid edge cases.

-        def __init__(self):
-            super().__init__("")
+        def __init__(self):
+            from pathlib import Path
+            super().__init__(str(Path.cwd()))
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 2657190 and c267517.

📒 Files selected for processing (2)
  • packages/mcp-hmr/mcp_hmr.py (1 hunks)
  • packages/mcp-hmr/pyproject.toml (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Link Check
  • GitHub Check: Sourcery review
🔇 Additional comments (3)
packages/mcp-hmr/pyproject.toml (3)

15-15: fastmcp version range looks good.

Allowing v2 minors while capping <3 aligns with current v2 line.

Based on learnings


4-4: No action required — README.md exists.

The verification confirms that packages/mcp-hmr/README.md is present, so the build configuration is correct.


20-23: PDM version extraction verified—__version__ present.

The configuration is correct. __version__ = "0.0.1" exists at line 3 of mcp_hmr.py, and pdm-backend will successfully extract it.

Comment thread packages/mcp-hmr/mcp_hmr.py
Comment thread packages/mcp-hmr/mcp_hmr.py Outdated
Comment thread packages/mcp-hmr/mcp_hmr.py
Comment thread packages/mcp-hmr/pyproject.toml Outdated
Comment thread packages/mcp-hmr/pyproject.toml
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR introduces a new package mcp-hmr that enables hot module reloading for MCP (Model Context Protocol) servers, allowing automatic server restarts when code changes are detected during development.

Key Changes:

  • Added hot-module-reload functionality for MCP servers with automatic restart on file changes
  • Implemented CLI interface for running MCP servers with HMR enabled
  • Created package configuration with dependencies on fastmcp and hmr libraries

Reviewed Changes

Copilot reviewed 2 out of 3 changed files in this pull request and generated 3 comments.

File Description
packages/mcp-hmr/pyproject.toml Package configuration defining project metadata, dependencies (fastmcp, hmr), and CLI entry point
packages/mcp-hmr/mcp_hmr.py Core implementation of HMR functionality including server mounting/unmounting, reloader class, and CLI interface

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

Comment thread packages/mcp-hmr/mcp_hmr.py
Comment thread packages/mcp-hmr/mcp_hmr.py
Comment thread packages/mcp-hmr/mcp_hmr.py Outdated
CNSeniorious000 and others added 3 commits October 18, 2025 02:34
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

@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: 0

🧹 Nitpick comments (1)
packages/mcp-hmr/mcp_hmr.py (1)

44-46: Consider explicit error handling for import failures.

import_module and getattr can raise ModuleNotFoundError or AttributeError if the target doesn't exist. While the reloader will catch these, explicit validation with clearer error messages would improve developer experience.

Example:

@derived(context=HMR_CONTEXT)
def get_app():
    try:
        mod = import_module(module)
    except ModuleNotFoundError as e:
        raise RuntimeError(f"Cannot import module '{module}': {e}") from e
    
    try:
        return getattr(mod, attr)
    except AttributeError as e:
        raise RuntimeError(f"Module '{module}' has no attribute '{attr}'") from e
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between adeb32a and baeb813.

📒 Files selected for processing (2)
  • .github/workflows/ci.yml (1 hunks)
  • packages/mcp-hmr/mcp_hmr.py (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Link Check
  • GitHub Check: Sourcery review
🔇 Additional comments (3)
.github/workflows/ci.yml (1)

46-46: LGTM! Publish matrix entry added correctly.

The addition of mcp-hmr to the publish matrix is consistent with the existing package structure and enables automated publishing for the new package.

packages/mcp-hmr/mcp_hmr.py (2)

63-79: Well-structured reloader lifecycle management.

The custom Reloader class appropriately excludes the current file from watching, coordinates reload hooks, and manages the watching task lifecycle. The design fits the HMR use case well.


85-111: Clean CLI implementation with proper validation.

The CLI correctly validates the module:attr format, ensures the current directory is importable, and gracefully handles keyboard interrupts. The argument parsing and error messages are clear.

@CNSeniorious000 CNSeniorious000 merged commit eea47b0 into readme Oct 18, 2025
15 checks passed
@CNSeniorious000 CNSeniorious000 deleted the mcp branch October 18, 2025 10:14
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.

2 participants