|
5 | 5 | import json |
6 | 6 | import os |
7 | 7 | import re |
| 8 | +import shutil |
8 | 9 | from enum import Enum |
9 | 10 |
|
10 | 11 | from prompt_toolkit import PromptSession |
@@ -95,9 +96,7 @@ def prompt_with_default(prompt_text, default="", hide_input=False, required=Fals |
95 | 96 | return default |
96 | 97 | if required: |
97 | 98 | # Cannot fulfill required argument without default in non-interactive mode |
98 | | - raise click.UsageError( |
99 | | - "A required value has no default and cannot be prompted in non-interactive mode." |
100 | | - ) |
| 99 | + raise click.UsageError("A required value has no default and cannot be prompted in non-interactive mode.") |
101 | 100 | return "" |
102 | 101 |
|
103 | 102 | # if default: |
@@ -178,7 +177,9 @@ def install(server_name, force=False, alias=None): |
178 | 177 |
|
179 | 178 | # Confirm addition |
180 | 179 | alias_text = f" as '{alias}'" if alias else "" |
181 | | - if not should_force_operation(force) and not Confirm.ask(f"Install this server to global configuration{alias_text}?"): |
| 180 | + if not should_force_operation(force) and not Confirm.ask( |
| 181 | + f"Install this server to global configuration{alias_text}?" |
| 182 | + ): |
182 | 183 | console.print("[yellow]Operation cancelled.[/]") |
183 | 184 | return |
184 | 185 |
|
@@ -428,6 +429,40 @@ def install(server_name, force=False, alias=None): |
428 | 429 | mcp_command = install_command |
429 | 430 | mcp_args = processed_args |
430 | 431 |
|
| 432 | + # --- Auto-UVX Injection Logic --- |
| 433 | + # If 'uv' is available and we are using python/pip, try to upgrade to 'uv run' for isolation. |
| 434 | + # This solves the "Pydantic Versioning" dependency hell by isolating servers. |
| 435 | + if mcp_command in ["python", "python3", "pip"] and shutil.which("uv"): |
| 436 | + # We need to determine the package name to run 'uv run --with <package>' |
| 437 | + # If package_name was defined in the installation method, use it. |
| 438 | + # If not, check if we are running 'python -m <module>' and guess package name from module? |
| 439 | + # Or default to the server name if reasonable? |
| 440 | + target_package = package_name |
| 441 | + |
| 442 | + # If args start with '-m', the next arg is the module. |
| 443 | + # Often module == package (e.g. mcp_server_time -> mcp-server-time? No, dashes vs underscores). |
| 444 | + # But 'uv run --with <module> python -m <module>' usually works if PyPI name matches. |
| 445 | + |
| 446 | + if not target_package and mcp_args and mcp_args[0] == "-m" and len(mcp_args) > 1: |
| 447 | + # Heuristic: Assume package name matches module name (with _ -> - maybe?) |
| 448 | + # Ideally, the registry should provide 'package'. |
| 449 | + # For now, we only auto-upgrade if we have a package name OR if we are brave. |
| 450 | + # Let's rely on package_name variable extracted earlier from selected_method.get("package") |
| 451 | + pass |
| 452 | + |
| 453 | + if target_package: |
| 454 | + console.print(f"[bold blue]🚀 Auto-upgrading to 'uv run' for isolation (package: {target_package})[/]") |
| 455 | + # Old: python -m module ... |
| 456 | + # New: uv run --with package python -m module ... |
| 457 | + |
| 458 | + # We prepend 'run --with package' to the command execution |
| 459 | + # mcp_command becomes 'uv' |
| 460 | + # mcp_args becomes ['run', '--with', target_package, original_command] + mcp_args |
| 461 | + |
| 462 | + new_args = ["run", "--with", target_package, mcp_command] + mcp_args |
| 463 | + mcp_command = "uv" |
| 464 | + mcp_args = new_args |
| 465 | + |
431 | 466 | # Create server configuration using FullServerConfig |
432 | 467 | full_server_config = FullServerConfig( |
433 | 468 | name=config_name, |
|
0 commit comments