Skip to content

Conversation

@niechen
Copy link
Contributor

@niechen niechen commented Sep 17, 2025

PR Type

Enhancement


Description

  • Remove automatic v1 migration prompt from CLI startup

  • Improve cross-platform keypress handling in migration utility

  • Simplify test setup by removing migration mocks


Diagram Walkthrough

flowchart LR
  CLI["CLI Main"] -- "removed" --> Migration["Auto Migration Check"]
  Migration -- "enhanced" --> Keypress["Cross-platform Keypress"]
  Tests["Test Suite"] -- "simplified" --> Mocks["Migration Mocks"]
Loading

File Walkthrough

Relevant files
Enhancement
cli.py
Remove automatic migration prompt logic                                   

src/mcpm/cli.py

  • Remove import of V1ConfigDetector and V1ToV2Migrator
  • Delete automatic v1 configuration detection and migration prompt logic
  • Simplify main function by removing migration workflow
+0/-14   
v1_migrator.py
Enhance cross-platform keypress handling                                 

src/mcpm/migration/v1_migrator.py

  • Add cross-platform compatibility for keypress handling
  • Implement Windows-specific msvcrt.getch() fallback
  • Add proper error handling for terminal operations
  • Improve import error handling for Unix/Linux modules
+25/-13 
Tests
test_global_config.py
Simplify tests by removing migration mocks                             

tests/test_global_config.py

  • Remove unittest.mock patch for v1 config detection
  • Simplify test by removing migration prompt mocking
  • Clean up test setup for help command testing
+8/-12   

Summary by CodeRabbit

  • New Features

    • Added SSE and host options and clarified run command usage/help (stdio/HTTP/SSE modes).
  • Bug Fixes

    • Help output avoids duplicated footer when no subcommand is given.
    • More reliable single-key input handling across platforms and non-interactive contexts.
  • Refactor

    • Removed legacy v1 migration flow for a streamlined startup experience.
  • Documentation

    • Removed an internal AI-agent CLI implementation plan document.
  • Tests

    • Updated help-related tests to match the simplified CLI flow.

@coderabbitai
Copy link

coderabbitai bot commented Sep 17, 2025

Walkthrough

Removed interactive v1 migration from the CLI, hardened cross-platform single-key input in the v1 migrator, expanded run command help and execution-mode options, deleted the AI-agent CLI design doc, and updated a test to call CLI help directly.

Changes

Cohort / File(s) Summary of modifications
CLI migration removal & help handling
src/mcpm/cli.py
Removed imports and the interactive v1 migration flow; when no subcommand is provided, prints header and help with the global footer temporarily disabled to avoid duplicate footers.
Cross-platform keypress handling
src/mcpm/migration/v1_migrator.py
Rewrote _wait_for_keypress to attempt Unix raw-mode via termios/tty, use msvcrt.getch() on Windows, early-exit non-tty stdin, and fall back to input() with broader exception handling and explicit flush/newline behavior.
Run command docs & CLI options
src/mcpm/commands/run.py, src/mcpm/utils/rich_click_config.py
Rewrote run command docstring/help to document STDIO/HTTP/SSE modes and tips; updated option group to include --http, --sse, --port, and --host (help text and usage improvements only).
Tests updated for help behavior
tests/test_global_config.py
Removed mocking of v1 migration detector; test now invokes the CLI with ["--help"] directly and asserts help output strings.
Deleted design doc
AI_AGENT_FRIENDLY_CLI_PLAN.md
Deleted the AI-agent-friendly CLI implementation plan document.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant User
  participant CLI as mcpm CLI
  participant Help as Help Renderer
  participant Migrator as v1_migrator

  User->>CLI: run `mcpm` or `mcpm --help`
  activate CLI
  Note over CLI: v1 migration detection/prompt removed
  CLI->>Help: print header
  CLI->>Help: print help text (global footer suppressed)
  Help-->>CLI: composed help output
  CLI-->>User: display help
  deactivate CLI

  Note right of Migrator: `_wait_for_keypress` now:\n- tries Unix `termios`/`tty` raw read\n- tries Windows `msvcrt.getch()`\n- falls back to `input()` for non-tty/errors
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

I twitch, I hop, I tidy leaves away—
The old prompt gone, help greets the day.
One-key waits on Linux, Windows, shore—
Docs refreshed, more flags to explore.
A rabbit nods and scampers off to code 🐇✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title "fix: remove auto v1 migration prompt" succinctly and accurately captures the primary change in the patch—the removal of the automatic v1 migration prompt from CLI startup—as reflected by deletions in src/mcpm/cli.py and related test updates, and it is a clear, single-sentence summary appropriate for a PR title.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch remove-auto-v1-migration

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 49135e6 and a713b30.

📒 Files selected for processing (2)
  • src/mcpm/cli.py (0 hunks)
  • src/mcpm/migration/v1_migrator.py (1 hunks)
💤 Files with no reviewable changes (1)
  • src/mcpm/cli.py
🧰 Additional context used
📓 Path-based instructions (1)
**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

Always format Python code with ruff.

Files:

  • src/mcpm/migration/v1_migrator.py
🔇 Additional comments (1)
src/mcpm/migration/v1_migrator.py (1)

59-79: Cross‑platform keypress handling looks solid

The layered approach (termios/tty → msvcrt → safe input fallback) with TTY early‑out covers CI/non‑interactive scenarios well.


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.

@qodo-merge-pro
Copy link
Contributor

PR Reviewer Guide 🔍

Here are some key observations to aid the review process:

⏱️ Estimated effort to review: 2 🔵🔵⚪⚪⚪
🧪 PR contains tests
🔒 No security concerns identified
⚡ Recommended focus areas for review

Possible Issue

The Unix keypress branch swallows multiple exception types and falls back to input(), but the except tuple references termios.error which may not exist if termios import failed earlier; ensure exception classes are available in that scope or adjust the except to avoid NameError.

if termios and tty:
    try:
        # Unix/Linux/macOS
        fd = sys.stdin.fileno()
        old_settings = termios.tcgetattr(fd)
        try:
            tty.setraw(fd)
            sys.stdin.read(1)
        finally:
            termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
    except (AttributeError, termios.error, ValueError, OSError):
        input()
Behavior Change

Removing the automatic v1 migration prompt alters startup behavior for users with v1 configs; confirm there is a documented/manual migration path and that commands won’t fail silently without guidance.

    console.print(get_header_text())
    # Temporarily disable global footer to avoid duplication
    original_footer = click.rich_click.FOOTER_TEXT
    click.rich_click.FOOTER_TEXT = None
    click.echo(ctx.get_help())
    click.rich_click.FOOTER_TEXT = original_footer
    return

# If no command was invoked, show help with header and footer
if ctx.invoked_subcommand is None:
    console.print(get_header_text())
    # Temporarily disable global footer to avoid duplication

@qodo-merge-pro
Copy link
Contributor

qodo-merge-pro bot commented Sep 17, 2025

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
Possible issue
Handle potential crash on Windows
Suggestion Impact:The commit implemented the suggested error handling by calling msvcrt.getch() inside a try block and falling back to input() on OSError, while still catching ImportError to use input() on non-Windows.

code diff:

             try:
                 import msvcrt
+                try:
+                    msvcrt.getch()
+                except OSError:
+                    input()
             except ImportError:
                 input()

To prevent a crash on Windows when standard input is redirected, wrap the
msvcrt.getch() call in a try...except block to catch OSError and fall back to
input().

src/mcpm/migration/v1_migrator.py [60-66]

 else:
     try:
         import msvcrt
-    except ImportError:
+        msvcrt.getch()
+    except (ImportError, OSError):
+        # Fallback for non-Windows or when stdin is redirected on Windows
         input()
-    else:
-        msvcrt.getch()

[Suggestion processed]

Suggestion importance[1-10]: 7

__

Why: The suggestion correctly identifies a potential OSError crash on Windows with redirected stdin and proposes a robust fix, which aligns with the PR's goal of improving cross-platform compatibility in this function.

Medium
  • Update

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

🧹 Nitpick comments (3)
tests/test_global_config.py (1)

43-50: Stabilize help assertions (case-insensitive) to reduce brittleness.

Lowercase once and assert against that to avoid future styling/casing flakes.

-    assert result.exit_code == 0
-    assert "global configuration" in result.output.lower()
-    assert "profile" in result.output.lower()
-    assert "install" in result.output
-    assert "run" in result.output
+    assert result.exit_code == 0
+    out = result.output.lower()
+    assert "global configuration" in out
+    assert "profile" in out
+    assert "install" in out
+    assert "run" in out

Additionally, consider adding a separate test invoking main with no args ([]) to assert header shows once and the global footer isn’t duplicated. I can draft it if helpful.

src/mcpm/migration/v1_migrator.py (2)

46-67: Don’t block in non‑interactive contexts; flush prompt first.

Without a TTY (CI, piped input), this can hang waiting for input. Flush the prompt and short‑circuit when stdin isn’t a TTY.

-        console.print(message, end="")
+        console.print(message, end="")
+        # Ensure prompt is visible before blocking
+        try:
+            console.file.flush()
+        except Exception:
+            pass
+        # In non-interactive contexts (e.g., CI/pipes), don't wait
+        try:
+            is_tty = sys.stdin.isatty()
+        except Exception:
+            is_tty = False
+        if not is_tty:
+            console.print()
+            return

48-66: Leverage Click’s cross‑platform pause to simplify.

You can replace the platform branches with click.pause() which already handles Windows/Unix, echo, and TTY checks.

Example replacement inside this method:

import click  # at top of file

def _wait_for_keypress(self, message: str):
    console.print(message, end="")
    try:
        console.file.flush()
    except Exception:
        pass
    try:
        click.pause("")  # empty string to avoid duplicate message
    except (EOFError, KeyboardInterrupt):
        pass
    console.print()
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 361c6f6 and 0200347.

📒 Files selected for processing (3)
  • src/mcpm/cli.py (0 hunks)
  • src/mcpm/migration/v1_migrator.py (1 hunks)
  • tests/test_global_config.py (1 hunks)
💤 Files with no reviewable changes (1)
  • src/mcpm/cli.py
🧰 Additional context used
📓 Path-based instructions (1)
**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

Always format Python code with ruff.

Files:

  • tests/test_global_config.py
  • src/mcpm/migration/v1_migrator.py
🧬 Code graph analysis (1)
tests/test_global_config.py (1)
src/mcpm/cli.py (1)
  • main (80-103)

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

Caution

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

⚠️ Outside diff range comments (1)
src/mcpm/commands/run.py (1)

66-71: Port auto-discovery ignores --host; can mis-detect availability

Binding check is hardcoded to 127.0.0.1. If users pass --host 0.0.0.0 (or another IP/IPv6), a port may be reported “free” yet fail on uvicorn bind (or vice versa). Bind against the requested host (and support IPv6) to avoid false positives/negatives.

Apply this diff:

-            actual_port = await find_available_port(port)
+            actual_port = await find_available_port(port, host)
-async def find_available_port(preferred_port, max_attempts=10):
-    """Find an available port starting from preferred_port."""
-    import socket
+async def find_available_port(preferred_port, host, max_attempts=10):
+    """Find an available port for the given host starting from preferred_port."""
+    import socket, ipaddress
 
     for attempt in range(max_attempts):
         port_to_try = preferred_port + attempt
 
-        # Check if port is available
+        # Check if port is available for the specified host (IPv4/IPv6 aware)
         try:
-            with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
-                s.bind(("127.0.0.1", port_to_try))
+            try:
+                is_ipv6 = ipaddress.ip_address(host).version == 6
+            except ValueError:
+                is_ipv6 = ":" in host  # simple fallback for hostnames with IPv6 literals
+            family = socket.AF_INET6 if is_ipv6 else socket.AF_INET
+            bind_host = host
+            with socket.socket(family, socket.SOCK_STREAM) as s:
+                # For detection we only need to bind; the context manager closes immediately
+                s.bind((bind_host, port_to_try))
                 return port_to_try
         except OSError:
             continue  # Port is busy, try next one

Also applies to: 113-129

🧹 Nitpick comments (2)
src/mcpm/utils/rich_click_config.py (1)

167-169: Run option group updated with --sse/--host — alignment looks good

The option group now mirrors the run command’s flags.

Optional: rename the group to “Execution & Network” (or “Serving Options”) since it now includes network params, not just “mode”.

-        {
-            "name": "Execution Mode",
+        {
+            "name": "Execution & Network",
             "options": ["--http", "--sse", "--port", "--host"],
         },
src/mcpm/commands/run.py (1)

73-82: Friendlier URL when binding to all interfaces

When host is 0.0.0.0 or ::, the printed URL isn’t directly reachable. Show localhost in the hint to reduce confusion.

-            if sse_mode:
-                server_url = f"http://{host}:{actual_port}/sse/"
+            display_host = "localhost" if host in {"0.0.0.0", "::"} else host
+            if sse_mode:
+                server_url = f"http://{display_host}:{actual_port}/sse/"
                 title = "📡 SSE Server Running"
             else:
-                server_url = f"http://{host}:{actual_port}/mcp/"
+                server_url = f"http://{display_host}:{actual_port}/mcp/"
                 title = "🌐 Local Server Running"
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0200347 and 034bd3a.

📒 Files selected for processing (3)
  • AI_AGENT_FRIENDLY_CLI_PLAN.md (0 hunks)
  • src/mcpm/commands/run.py (1 hunks)
  • src/mcpm/utils/rich_click_config.py (1 hunks)
💤 Files with no reviewable changes (1)
  • AI_AGENT_FRIENDLY_CLI_PLAN.md
🧰 Additional context used
📓 Path-based instructions (1)
**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

Always format Python code with ruff.

Files:

  • src/mcpm/utils/rich_click_config.py
  • src/mcpm/commands/run.py
🧬 Code graph analysis (1)
src/mcpm/commands/run.py (1)
src/mcpm/commands/profile/run.py (1)
  • run (141-207)
🔇 Additional comments (2)
src/mcpm/commands/run.py (2)

145-177: Reworked usage doc is clear and actionable

Examples and tips read well; defaults and exclusivity are obvious.


134-143: New flags (--sse, --host) and clearer help — LGTM

Options --http, --sse, --port, --host and -h are present in src/mcpm/commands/run.py and the mutual-exclusivity/help text is explicit.

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

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 034bd3a and 49135e6.

📒 Files selected for processing (1)
  • src/mcpm/migration/v1_migrator.py (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

Always format Python code with ruff.

Files:

  • src/mcpm/migration/v1_migrator.py

@niechen niechen changed the title Remove auto v1 migration prompt fix: remove auto v1 migration prompt Sep 17, 2025
@niechen niechen merged commit 8630fc8 into main Sep 17, 2025
8 checks passed
@niechen niechen deleted the remove-auto-v1-migration branch September 17, 2025 14:12
mcpm-semantic-release bot pushed a commit that referenced this pull request Sep 18, 2025
## [2.8.2](v2.8.1...v2.8.2) (2025-09-18)

### Bug Fixes

* remove auto v1 migration prompt ([#265](#265)) ([8630fc8](8630fc8))
@mcpm-semantic-release
Copy link

🎉 This PR is included in version 2.8.2 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants