From 847665e50eaefc4333f113bd93b4631ca7c0cf11 Mon Sep 17 00:00:00 2001 From: Eliott Jacopin Date: Wed, 1 Apr 2026 20:23:15 +0900 Subject: [PATCH 1/2] feat(cli): add filter_name positional argument to MCP discovery and list Agent-Id: agent-3e85a26f-f7c9-4ec3-8893-1a050ed9dcbb Linked-Note-Id: 20e46d61-979f-46f8-a102-49599be121ea --- hatch/cli/__main__.py | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/hatch/cli/__main__.py b/hatch/cli/__main__.py index 746ada7..faddcee 100644 --- a/hatch/cli/__main__.py +++ b/hatch/cli/__main__.py @@ -425,6 +425,11 @@ def _setup_mcp_commands(subparsers): mcp_discover_hosts_parser = mcp_discover_subparsers.add_parser( "hosts", help="Discover available MCP host platforms" ) + mcp_discover_hosts_parser.add_argument( + "filter_name", + nargs="?", + help="Filter by host name", + ) mcp_discover_hosts_parser.add_argument( "--json", action="store_true", help="Output in JSON format" ) @@ -433,6 +438,11 @@ def _setup_mcp_commands(subparsers): mcp_discover_servers_parser = mcp_discover_subparsers.add_parser( "servers", help="Discover configured MCP servers" ) + mcp_discover_servers_parser.add_argument( + "filter_name", + nargs="?", + help="Filter by server name", + ) mcp_discover_servers_parser.add_argument( "--env", "-e", @@ -449,6 +459,11 @@ def _setup_mcp_commands(subparsers): mcp_list_hosts_parser = mcp_list_subparsers.add_parser( "hosts", help="List host/server pairs from host configuration files" ) + mcp_list_hosts_parser.add_argument( + "filter_name", + nargs="?", + help="Filter by host name", + ) mcp_list_hosts_parser.add_argument( "--server", help="Filter by server name using regex pattern", @@ -461,6 +476,11 @@ def _setup_mcp_commands(subparsers): mcp_list_servers_parser = mcp_list_subparsers.add_parser( "servers", help="List server/host pairs from host configuration files" ) + mcp_list_servers_parser.add_argument( + "filter_name", + nargs="?", + help="Filter by server name", + ) mcp_list_servers_parser.add_argument( "--host", help="Filter by host name using regex pattern", @@ -478,6 +498,11 @@ def _setup_mcp_commands(subparsers): mcp_show_hosts_parser = mcp_show_subparsers.add_parser( "hosts", help="Show detailed host configurations" ) + mcp_show_hosts_parser.add_argument( + "filter_name", + nargs="?", + help="Filter by host name", + ) mcp_show_hosts_parser.add_argument( "--server", help="Filter by server name using regex pattern", @@ -490,6 +515,11 @@ def _setup_mcp_commands(subparsers): mcp_show_servers_parser = mcp_show_subparsers.add_parser( "servers", help="Show detailed server configurations across hosts" ) + mcp_show_servers_parser.add_argument( + "filter_name", + nargs="?", + help="Filter by server name", + ) mcp_show_servers_parser.add_argument( "--host", help="Filter by host name using regex pattern", From 893082f3d4177190e355cec837ce9fe336bfbae5 Mon Sep 17 00:00:00 2001 From: Eliott Jacopin Date: Wed, 1 Apr 2026 20:08:09 +0900 Subject: [PATCH 2/2] docs: update to match new positional argument docs: document filter_name parameter for MCP discovery and listing funct docs: correct MCP command examples and argument order for filters docs(mcp): document filter_name parameter for discover_servers and list_ docs: correct regex pattern matching to case-sensitive in MCP discovery docs(mcp): add example for filtering servers by name docs(mcp): simplify server show command syntax docs(mcp): correct list servers example to use --host instead of --env-v docs(mcp): update examples to use sync command for multi-host configurat docs(mcp): update backup command syntax to remove --host flag and simpli --- README.md | 10 +- docs/articles/api/cli/mcp.md | 19 +- .../devs/architecture/mcp_backup_system.md | 7 +- docs/articles/users/CLIReference.md | 160 ++++++++++++-- docs/articles/users/GettingStarted.md | 30 ++- docs/articles/users/MCPHostConfiguration.md | 26 +-- docs/index.md | 6 +- hatch/cli/cli_mcp.py | 195 ++++++++++++++++-- 8 files changed, 389 insertions(+), 64 deletions(-) diff --git a/README.md b/README.md index 18fa1b3..5542672 100644 --- a/README.md +++ b/README.md @@ -54,9 +54,10 @@ hatch mcp configure github-mcp --host gemini \ --httpUrl https://api.github.com/mcp \ --header Authorization="Bearer $GIT_PAT_TOKEN" -# Register the same server on multiple hosts at once -hatch mcp configure my-server --host claude-desktop,cursor,vscode \ +# Register the same server on multiple hosts using sync +hatch mcp configure my-server --host claude-desktop \ --command python --args "-m my_server" +hatch mcp sync --from-host claude-desktop --to-host cursor,vscode ``` ### Inspect what is configured @@ -65,8 +66,11 @@ hatch mcp configure my-server --host claude-desktop,cursor,vscode \ # See all servers across all hosts hatch mcp list servers +# Filter servers by name +hatch mcp list servers weather + # See all hosts a specific server is registered on -hatch mcp show servers --server "context7" +hatch mcp show servers context7 # Detect which MCP host platforms are installed hatch mcp discover hosts diff --git a/docs/articles/api/cli/mcp.md b/docs/articles/api/cli/mcp.md index 1162c74..d4f7141 100644 --- a/docs/articles/api/cli/mcp.md +++ b/docs/articles/api/cli/mcp.md @@ -31,16 +31,22 @@ This module provides handlers for: ## Handler Functions ### Discovery -- `handle_mcp_discover_hosts()`: Detect available MCP host platforms -- `handle_mcp_discover_servers()`: Find MCP servers in packages (deprecated) +- `handle_mcp_discover_hosts(args)`: Detect available MCP host platforms + - `filter_name`: Optional positional argument to filter by host name (regex pattern) +- `handle_mcp_discover_servers(args)`: Find MCP servers in packages (deprecated) + - `filter_name`: Optional positional argument to filter by server name (regex pattern) ### Listing -- `handle_mcp_list_hosts()`: Host-centric server listing (shows all servers on hosts) -- `handle_mcp_list_servers()`: Server-centric host listing (shows all hosts for servers) +- `handle_mcp_list_hosts(args)`: Host-centric server listing (shows all servers on hosts) + - `filter_name`: Optional positional argument to filter by host name (regex pattern) +- `handle_mcp_list_servers(args)`: Server-centric host listing (shows all hosts for servers) + - `filter_name`: Optional positional argument to filter by server name (regex pattern) ### Show Commands -- `handle_mcp_show_hosts()`: Detailed hierarchical view of host configurations -- `handle_mcp_show_servers()`: Detailed hierarchical view of server configurations +- `handle_mcp_show_hosts(args)`: Detailed hierarchical view of host configurations + - `filter_name`: Optional positional argument to filter by host name (regex pattern) +- `handle_mcp_show_servers(args)`: Detailed hierarchical view of server configurations + - `filter_name`: Optional positional argument to filter by server name (regex pattern) ### Configuration - `handle_mcp_configure()`: Configure MCP server on host with all host-specific arguments @@ -69,6 +75,7 @@ def handle_mcp_command(args: Namespace) -> int: args: Namespace with: - env_manager: HatchEnvironmentManager instance - mcp_manager: MCPHostConfigurationManager instance + - filter_name: Optional positional argument to filter by name (regex pattern) - Returns: diff --git a/docs/articles/devs/architecture/mcp_backup_system.md b/docs/articles/devs/architecture/mcp_backup_system.md index 34f167f..d66aacc 100644 --- a/docs/articles/devs/architecture/mcp_backup_system.md +++ b/docs/articles/devs/architecture/mcp_backup_system.md @@ -192,10 +192,9 @@ Designed for future CLI command integration: ```bash # Future CLI commands -hatch mcp backup create --host vscode -hatch mcp backup restore --host vscode --timestamp 20250921_100000_123456 -hatch mcp backup list --host cursor -hatch mcp backup clean --host claude-desktop --older-than-days 30 +hatch mcp backup restore vscode --backup-file backup_20250921_100000_123456.json +hatch mcp backup list cursor +hatch mcp backup clean claude-desktop --older-than-days 30 ``` ## Testing Architecture diff --git a/docs/articles/users/CLIReference.md b/docs/articles/users/CLIReference.md index 527c61c..61b02a0 100644 --- a/docs/articles/users/CLIReference.md +++ b/docs/articles/users/CLIReference.md @@ -518,25 +518,29 @@ Discover available MCP host platforms on the system. Syntax: -`hatch mcp discover hosts [--json]` +`hatch mcp discover hosts [filter_name] [--json]` -| Flag | Type | Description | Default | +| Argument / Flag | Type | Description | Default | |---:|---|---|---| +| `filter_name` | string (positional, optional) | Filter by host name using regex pattern | none | | `--json` | flag | Output in JSON format | false | -**Example Output**: +**Usage Examples**: ```bash +# Show all available host platforms $ hatch mcp discover hosts -Available MCP Host Platforms: - Host Status Config Path - ───────────────────────────────────────────────────────────────── - claude-desktop ✓ Available /Users/user/.config/claude/... - cursor ✓ Available /Users/user/.cursor/mcp.json - vscode ✗ Not Found - - mistral-vibe ✓ Available /Users/user/.config/mistral/mcp.toml + +# Filter to only Claude Desktop +$ hatch mcp discover hosts claude-desktop + +# Filter with regex pattern (case-sensitive) +$ hatch mcp discover hosts "^cursor|^vscode" + +# JSON output with filter +$ hatch mcp discover hosts cursor --json ``` **Key Details**: @@ -544,6 +548,7 @@ Available MCP Host Platforms: - Columns: Host (width 18), Status (width 15), Config Path (width "auto") - Status: `"✓ Available"` or `"✗ Not Found"` - Shows ALL host types (MCPHostType enum), not just available ones +- `filter_name` accepts Python regex patterns for flexible matching --- @@ -555,13 +560,35 @@ Discover MCP servers in Hatch environments. Syntax: -`hatch mcp discover servers [--env ENV]` +`hatch mcp discover servers [filter_name] [--env ENV]` -| Flag | Type | Description | Default | +| Argument / Flag | Type | Description | Default | |---:|---|---|---| +| `filter_name` | string (positional, optional) | Filter by server name using regex pattern | none | | `--env` | string | Specific environment to discover servers in | current environment | +**Usage Examples**: + +```bash +# List all MCP servers in current environment +$ hatch mcp discover servers + +# Filter to specific server by name +$ hatch mcp discover servers my-server + +# Filter with regex pattern +$ hatch mcp discover servers "^my-.*server$" + +# Discover servers in specific environment +$ hatch mcp discover servers --env test-env + +# Combined: filter + specific environment +$ hatch mcp discover servers hatch-mcp-server --env prod-env +``` + +**Note**: This command is deprecated. Use `hatch mcp list servers` instead for more detailed information. + --- #### `hatch mcp list hosts` @@ -575,15 +602,38 @@ List host/server pairs from host configuration files. Syntax: -`hatch mcp list hosts [--server PATTERN] [--json]` +`hatch mcp list hosts [filter_name] [--server PATTERN] [--json]` -| Flag | Type | Description | Default | +| Argument / Flag | Type | Description | Default | |---:|---|---|---| +| `filter_name` | string (positional, optional) | Filter by host name using regex pattern | none | | `--server` | string | Filter by server name using regex pattern | none | | `--json` | flag | Output in JSON format | false | +**Usage Examples**: + +```bash +# List all hosts and their servers +$ hatch mcp list hosts + +# Filter by specific host +$ hatch mcp list hosts claude-desktop + +# Filter hosts by regex pattern +$ hatch mcp list hosts "^claude" + +# Filter by server (works with or without host filter) +$ hatch mcp list hosts --server weather + +# Combine host and server filters +$ hatch mcp list hosts claude-desktop --server weather + +# JSON output +$ hatch mcp list hosts cursor --json +``` + **Example Output**: ```bash @@ -601,6 +651,7 @@ MCP Hosts: - Columns: Host (width 18), Server (width 18), Hatch (width 8), Environment (width 15) - Hatch column: `"✅"` for Hatch-managed, `"❌"` for third-party - Shows ALL servers on hosts (both Hatch-managed and third-party) +- `filter_name` is positional and filters hosts; `--server` filters servers separately - Environment column: environment name if Hatch-managed, `"-"` otherwise - Sorted by: host (alphabetically), then server @@ -615,14 +666,37 @@ List server/host pairs from host configuration files. Syntax: -`hatch mcp list servers [--host PATTERN] [--json]` +`hatch mcp list servers [filter_name] [--host PATTERN] [--json]` -| Flag | Type | Description | Default | +| Argument / Flag | Type | Description | Default | |---:|---|---|---| +| `filter_name` | string (positional, optional) | Filter by server name using regex pattern | none | | `--host` | string | Filter by host name using regex pattern | none | | `--json` | flag | Output in JSON format | false | +**Usage Examples**: + +```bash +# List all servers and their hosts +$ hatch mcp list servers + +# Filter by specific server +$ hatch mcp list servers weather-server + +# Filter servers by regex pattern +$ hatch mcp list servers "^weather" + +# Filter by host (works with or without server filter) +$ hatch mcp list servers --host claude-desktop + +# Combine server and host filters +$ hatch mcp list servers weather --host cursor + +# JSON output +$ hatch mcp list servers hatch-mcp --json +``` + **Example Output**: ```bash @@ -654,14 +728,37 @@ Show detailed hierarchical view of all MCP host configurations. Syntax: -`hatch mcp show hosts [--server PATTERN] [--json]` +`hatch mcp show hosts [filter_name] [--server PATTERN] [--json]` -| Flag | Type | Description | Default | +| Argument / Flag | Type | Description | Default | |---:|---|---|---| +| `filter_name` | string (positional, optional) | Filter by host name using regex pattern | none | | `--server` | string | Filter by server name using regex pattern | none | | `--json` | flag | Output in JSON format | false | +**Usage Examples**: + +```bash +# Show detailed configuration for all hosts +$ hatch mcp show hosts + +# Show configuration for specific host +$ hatch mcp show hosts claude-desktop + +# Show hosts matching regex pattern +$ hatch mcp show hosts "^cursor|^vscode" + +# Filter by server name +$ hatch mcp show hosts --server weather + +# Combine host and server filters +$ hatch mcp show hosts claude --server weather-server + +# JSON output with filter +$ hatch mcp show hosts cursor --json +``` + **Example Output**: ```bash @@ -719,14 +816,37 @@ Show detailed hierarchical view of all MCP server configurations across hosts. Syntax: -`hatch mcp show servers [--host PATTERN] [--json]` +`hatch mcp show servers [filter_name] [--host PATTERN] [--json]` -| Flag | Type | Description | Default | +| Argument / Flag | Type | Description | Default | |---:|---|---|---| +| `filter_name` | string (positional, optional) | Filter by server name using regex pattern | none | | `--host` | string | Filter by host name using regex pattern | none | | `--json` | flag | Output in JSON format | false | +**Usage Examples**: + +```bash +# Show detailed configuration for all servers +$ hatch mcp show servers + +# Show configuration for specific server +$ hatch mcp show servers weather-server + +# Show servers matching regex pattern +$ hatch mcp show servers "^hatch-.*" + +# Filter by host name +$ hatch mcp show servers --host claude-desktop + +# Combine server and host filters +$ hatch mcp show servers weather --host cursor + +# JSON output with filter +$ hatch mcp show servers "^my-" --json +``` + **Example Output**: ```bash diff --git a/docs/articles/users/GettingStarted.md b/docs/articles/users/GettingStarted.md index 034337d..c03606a 100644 --- a/docs/articles/users/GettingStarted.md +++ b/docs/articles/users/GettingStarted.md @@ -174,16 +174,36 @@ Hatch provides multiple commands for viewing your environments, packages, and ho - `hatch mcp discover hosts`: Detect available MCP host platforms -**Filtering**: All list and show commands support regex filtering: +**Filtering**: All list and show commands support regex filtering using positional arguments and flags: + +**Positional Filter (by position - simple syntax)**: ```bash -# Filter by server name +# Filter by host name (positional) +hatch mcp list hosts claude-desktop + +# Filter by server name (positional) +hatch mcp list servers weather-server + +# Filter discovery results +hatch mcp discover hosts claude +``` + +**Flag-Based Filtering (regex patterns)**: +```bash +# Filter by server name using regex hatch mcp list hosts --server "weather.*" -# Filter by host name +# Filter by host name using regex hatch mcp show servers --host "claude.*" +``` + +**Compound Filtering (positional + flags together)**: +```bash +# Positional filter + server flag +hatch mcp list servers weather --host ".*desktop" -# Filter by environment -hatch env list hosts --env "my-project" +# Positional filter + multiple conditions +hatch mcp show hosts claude --server "api.*" ``` ## Understanding Hatch Concepts diff --git a/docs/articles/users/MCPHostConfiguration.md b/docs/articles/users/MCPHostConfiguration.md index 9af7204..6429051 100644 --- a/docs/articles/users/MCPHostConfiguration.md +++ b/docs/articles/users/MCPHostConfiguration.md @@ -67,8 +67,8 @@ hatch mcp list hosts # List configured servers from current environment hatch mcp list servers -# List servers from specific environment -hatch mcp list servers --env-var production +# List servers from specific host +hatch mcp list servers --host claude-desktop ``` ### Viewing Host Configurations @@ -182,35 +182,35 @@ hatch mcp configure authenticated-api \ ### Configure Across Multiple Hosts -Set up the same server on multiple host platforms: +Set up the same server on multiple host platforms using the `sync` command: ```bash -# Configure on multiple hosts at once +# Configure on the primary host first hatch mcp configure weather_server \ - --hosts claude-desktop,cursor,vscode \ + --host claude-desktop \ --command python \ --args weather_server.py -# Configure on all available hosts -hatch mcp configure weather_server \ - --hosts all \ - --command python \ - --args weather_server.py +# Then sync to other hosts +hatch mcp sync --from-host claude-desktop --to-host cursor,vscode + +# Or sync from an environment to multiple hosts +hatch mcp sync --from-env default --to-host all ``` #### Quick Examples ```bash -# Sync environment to hosts +# Sync environment to specific hosts hatch mcp sync --from-env production --to-host claude-desktop,cursor # Copy configuration between hosts hatch mcp sync --from-host claude-desktop --to-host cursor -# Sync with filtering +# Sync with filtering (only servers matching pattern) hatch mcp sync --from-env dev --to-host all --pattern ".*api.*" -# Preview changes +# Preview changes without applying them hatch mcp sync --from-env prod --to-host all --dry-run ``` diff --git a/docs/index.md b/docs/index.md index 379db89..88374bf 100644 --- a/docs/index.md +++ b/docs/index.md @@ -5,8 +5,12 @@ Hatch is a CLI tool for configuring MCP servers across AI host platforms. Instead of editing JSON config files for each tool separately, you register servers from the command line — once, on as many hosts as you need. ```bash -hatch mcp configure context7 --host claude-desktop,cursor,vscode \ +# Configure on the primary host +hatch mcp configure context7 --host claude-desktop \ --command npx --args "-y @upstash/context7-mcp" + +# Then sync to other hosts +hatch mcp sync --from-host claude-desktop --to-host cursor,vscode ``` Hatch also has a package system for installing MCP servers with dependency isolation (Python, system packages, Docker). That part is still being developed and will eventually integrate with MCP registries. diff --git a/hatch/cli/cli_mcp.py b/hatch/cli/cli_mcp.py index a5c1fc3..8c7f0c9 100644 --- a/hatch/cli/cli_mcp.py +++ b/hatch/cli/cli_mcp.py @@ -11,9 +11,11 @@ - vscode: Visual Studio Code with Copilot - kiro: Kiro IDE - codex: OpenAI Codex - - lm-studio: LM Studio + - lmstudio: LM Studio - gemini: Google Gemini - - mistral-vibe: Mistral Vibe CLI + - mistral-vibe: Mistral Vibe CLI coding agent + - opencode: OpenCode AI coding assistant + - augment: Augment Code AI assistant Command Groups: Discovery: @@ -24,16 +26,21 @@ - hatch mcp list hosts: Show configured hosts in environment - hatch mcp list servers: Show configured servers + Show: + - hatch mcp show hosts: Detailed hierarchical view of host configurations + - hatch mcp show servers: Detailed hierarchical view of server configurations + Backup: - hatch mcp backup restore: Restore configuration from backup - hatch mcp backup list: List available backups - hatch mcp backup clean: Clean old backups Configuration: - - hatch mcp configure: Add or update MCP server configuration - - hatch mcp remove: Remove server from specific host - - hatch mcp remove-server: Remove server from multiple hosts - - hatch mcp remove-host: Remove all servers from a host + - hatch mcp configure: Add or update MCP server configuration on a host + + Removal: + - hatch mcp remove server: Remove MCP server from hosts + - hatch mcp remove host: Remove entire host configuration Synchronization: - hatch mcp sync: Sync package servers to hosts @@ -44,7 +51,7 @@ Example: $ hatch mcp discover hosts - $ hatch mcp configure claude-desktop my-server --command python --args server.py + $ hatch mcp configure my-server --host claude-desktop --command python --args server.py $ hatch mcp backup list claude-desktop --detailed """ @@ -145,6 +152,7 @@ def handle_mcp_discover_hosts(args: Namespace) -> int: Args: args: Parsed command-line arguments containing: + - filter_name: Optional positional argument to filter by host name - json: Optional flag for JSON output Returns: @@ -152,16 +160,38 @@ def handle_mcp_discover_hosts(args: Namespace) -> int: """ try: import json as json_module + import re # Import strategies to trigger registration + filter_name: Optional[str] = getattr(args, "filter_name", None) json_output: bool = getattr(args, "json", False) + + # Compile host filter pattern if provided + filter_re = None + if filter_name: + try: + filter_re = re.compile(filter_name) + except re.error as e: + format_validation_error( + ValidationError( + f"Invalid regex pattern '{filter_name}': {e}", + field="filter_name", + suggestion="Use a valid Python regex pattern", + ) + ) + return EXIT_ERROR + available_hosts = MCPHostRegistry.detect_available_hosts() if json_output: # JSON output hosts_data = [] for host_type in MCPHostType: + # Apply host filter if specified + if filter_re and not filter_re.search(host_type.value): + continue + try: strategy = MCPHostRegistry.get_strategy(host_type) config_path = strategy.get_config_path() @@ -194,6 +224,10 @@ def handle_mcp_discover_hosts(args: Namespace) -> int: formatter = TableFormatter(columns) for host_type in MCPHostType: + # Apply host filter if specified + if filter_re and not filter_re.search(host_type.value): + continue + try: strategy = MCPHostRegistry.get_strategy(host_type) config_path = strategy.get_config_path() @@ -225,11 +259,13 @@ def handle_mcp_discover_servers(args: Namespace) -> int: args: Parsed command-line arguments containing: - env_manager: HatchEnvironmentManager instance - env: Optional environment name (uses current if not specified) + - filter_name: Optional positional argument to filter by server name Returns: int: EXIT_SUCCESS (0) on success, EXIT_ERROR (1) on failure """ import sys + import re # Emit deprecation warning to stderr print( @@ -241,6 +277,7 @@ def handle_mcp_discover_servers(args: Namespace) -> int: try: env_manager: HatchEnvironmentManager = args.env_manager env_name: Optional[str] = getattr(args, "env", None) + filter_name: Optional[str] = getattr(args, "filter_name", None) env_name = env_name or env_manager.get_current_environment() @@ -254,6 +291,21 @@ def handle_mcp_discover_servers(args: Namespace) -> int: ) return EXIT_ERROR + # Compile server filter pattern if provided + filter_re = None + if filter_name: + try: + filter_re = re.compile(filter_name) + except re.error as e: + format_validation_error( + ValidationError( + f"Invalid regex pattern '{filter_name}': {e}", + field="filter_name", + suggestion="Use a valid Python regex pattern", + ) + ) + return EXIT_ERROR + packages = env_manager.list_packages(env_name) mcp_packages = [] @@ -263,6 +315,11 @@ def handle_mcp_discover_servers(args: Namespace) -> int: server_config = get_package_mcp_server_config( env_manager, env_name, package["name"] ) + + # Apply server filter if specified + if filter_re and not filter_re.search(server_config.name): + continue + mcp_packages.append( {"package": package, "server_config": server_config} ) @@ -271,7 +328,12 @@ def handle_mcp_discover_servers(args: Namespace) -> int: continue if not mcp_packages: - print(f"No MCP servers found in environment '{env_name}'") + if filter_name: + print( + f"No MCP servers matching '{filter_name}' found in environment '{env_name}'" + ) + else: + print(f"No MCP servers found in environment '{env_name}'") return EXIT_SUCCESS print(f"MCP servers in environment '{env_name}':") @@ -306,6 +368,7 @@ def handle_mcp_list_hosts(args: Namespace) -> int: args: Parsed command-line arguments containing: - env_manager: HatchEnvironmentManager instance - server: Optional regex pattern to filter by server name + - filter_name: Optional positional argument to filter by host name - json: Optional flag for JSON output Returns: @@ -321,6 +384,7 @@ def handle_mcp_list_hosts(args: Namespace) -> int: env_manager: HatchEnvironmentManager = args.env_manager server_pattern: Optional[str] = getattr(args, "server", None) + filter_name: Optional[str] = getattr(args, "filter_name", None) json_output: bool = getattr(args, "json", False) # Compile regex pattern if provided @@ -338,6 +402,21 @@ def handle_mcp_list_hosts(args: Namespace) -> int: ) return EXIT_ERROR + # Compile host filter pattern if provided + filter_re = None + if filter_name: + try: + filter_re = re.compile(filter_name) + except re.error as e: + format_validation_error( + ValidationError( + f"Invalid regex pattern '{filter_name}': {e}", + field="filter_name", + suggestion="Use a valid Python regex pattern", + ) + ) + return EXIT_ERROR + # Build Hatch management lookup: {server_name: {host: env_name}} hatch_managed = {} for env_info in env_manager.list_environments(): @@ -387,6 +466,10 @@ def handle_mcp_list_hosts(args: Namespace) -> int: host_config = strategy.read_configuration() host_name = host_type.value + # Apply host filter if specified + if filter_re and not filter_re.search(host_name): + continue + for server_name, server_config in host_config.servers.items(): # Apply server pattern filter if specified if pattern_re and not pattern_re.search(server_name): @@ -429,8 +512,14 @@ def handle_mcp_list_hosts(args: Namespace) -> int: # Display results if not host_rows: + filters = [] + if filter_name: + filters.append(f"host '{filter_name}'") if server_pattern: - print(f"No MCP servers matching '{server_pattern}' on any host") + filters.append(f"server '{server_pattern}'") + + if filters: + print(f"No MCP servers found matching {' and '.join(filters)}") else: print("No MCP servers found on any available hosts") return EXIT_SUCCESS @@ -469,6 +558,7 @@ def handle_mcp_list_servers(args: Namespace) -> int: args: Parsed command-line arguments containing: - env_manager: HatchEnvironmentManager instance - host: Optional regex pattern to filter by host name + - filter_name: Optional positional argument to filter by server name - json: Optional flag for JSON output Returns: @@ -484,6 +574,7 @@ def handle_mcp_list_servers(args: Namespace) -> int: env_manager: HatchEnvironmentManager = args.env_manager host_pattern: Optional[str] = getattr(args, "host", None) + filter_name: Optional[str] = getattr(args, "filter_name", None) json_output: bool = getattr(args, "json", False) # Compile host regex pattern if provided @@ -501,6 +592,21 @@ def handle_mcp_list_servers(args: Namespace) -> int: ) return EXIT_ERROR + # Compile server filter pattern if provided + filter_re = None + if filter_name: + try: + filter_re = re.compile(filter_name) + except re.error as e: + format_validation_error( + ValidationError( + f"Invalid regex pattern '{filter_name}': {e}", + field="filter_name", + suggestion="Use a valid Python regex pattern", + ) + ) + return EXIT_ERROR + # Get all available hosts available_hosts = MCPHostRegistry.detect_available_hosts() @@ -560,6 +666,10 @@ def handle_mcp_list_servers(args: Namespace) -> int: continue for server_name, server_config in host_config.servers.items(): + # Apply server filter if specified + if filter_re and not filter_re.search(server_name): + continue + # Check if Hatch-managed is_hatch_managed = False env_name = "-" @@ -597,8 +707,14 @@ def handle_mcp_list_servers(args: Namespace) -> int: return EXIT_SUCCESS if not server_rows: + filters = [] + if filter_name: + filters.append(f"server '{filter_name}'") if host_pattern: - print(f"No MCP servers on hosts matching '{host_pattern}'") + filters.append(f"host '{host_pattern}'") + + if filters: + print(f"No MCP servers found matching {' and '.join(filters)}") else: print("No MCP servers found on any available hosts") return EXIT_SUCCESS @@ -637,6 +753,7 @@ def handle_mcp_show_hosts(args: Namespace) -> int: args: Parsed command-line arguments containing: - env_manager: HatchEnvironmentManager instance - server: Optional regex pattern to filter by server name + - filter_name: Optional positional argument to filter by host name - json: Optional flag for JSON output Returns: @@ -656,6 +773,7 @@ def handle_mcp_show_hosts(args: Namespace) -> int: env_manager: HatchEnvironmentManager = args.env_manager server_pattern: Optional[str] = getattr(args, "server", None) + filter_name: Optional[str] = getattr(args, "filter_name", None) json_output: bool = getattr(args, "json", False) # Compile regex pattern if provided @@ -673,6 +791,21 @@ def handle_mcp_show_hosts(args: Namespace) -> int: ) return EXIT_ERROR + # Compile host filter pattern if provided + filter_re = None + if filter_name: + try: + filter_re = re.compile(filter_name) + except re.error as e: + format_validation_error( + ValidationError( + f"Invalid regex pattern '{filter_name}': {e}", + field="filter_name", + suggestion="Use a valid Python regex pattern", + ) + ) + return EXIT_ERROR + # Build Hatch management lookup: {server_name: {host: (env_name, version, last_synced)}} hatch_managed = {} for env_info in env_manager.list_environments(): @@ -737,6 +870,11 @@ def handle_mcp_show_hosts(args: Namespace) -> int: strategy = MCPHostRegistry.get_strategy(host_type) host_config = strategy.read_configuration() host_name = host_type.value + + # Apply host filter if specified + if filter_re and not filter_re.search(host_name): + continue + config_path = strategy.get_config_path() # Filter servers by pattern if specified @@ -825,8 +963,14 @@ def handle_mcp_show_hosts(args: Namespace) -> int: # Human-readable output if not hosts_data: + filters = [] + if filter_name: + filters.append(f"host '{filter_name}'") if server_pattern: - print(f"No hosts with servers matching '{server_pattern}'") + filters.append(f"server '{server_pattern}'") + + if filters: + print(f"No MCP hosts found matching {' and '.join(filters)}") else: print("No MCP hosts found") return EXIT_SUCCESS @@ -903,6 +1047,7 @@ def handle_mcp_show_servers(args: Namespace) -> int: args: Parsed command-line arguments containing: - env_manager: HatchEnvironmentManager instance - host: Optional regex pattern to filter by host name + - filter_name: Optional positional argument to filter by server name - json: Optional flag for JSON output Returns: @@ -919,6 +1064,7 @@ def handle_mcp_show_servers(args: Namespace) -> int: env_manager: HatchEnvironmentManager = args.env_manager host_pattern: Optional[str] = getattr(args, "host", None) + filter_name: Optional[str] = getattr(args, "filter_name", None) json_output: bool = getattr(args, "json", False) # Compile regex pattern if provided @@ -936,6 +1082,21 @@ def handle_mcp_show_servers(args: Namespace) -> int: ) return EXIT_ERROR + # Compile server filter pattern if provided + filter_re = None + if filter_name: + try: + filter_re = re.compile(filter_name) + except re.error as e: + format_validation_error( + ValidationError( + f"Invalid regex pattern '{filter_name}': {e}", + field="filter_name", + suggestion="Use a valid Python regex pattern", + ) + ) + return EXIT_ERROR + # Build Hatch management lookup: {server_name: {host: (env_name, version, last_synced)}} hatch_managed = {} for env_info in env_manager.list_environments(): @@ -1005,6 +1166,10 @@ def handle_mcp_show_servers(args: Namespace) -> int: host_config = strategy.read_configuration() for server_name, server_config in host_config.servers.items(): + # Apply server filter if specified + if filter_re and not filter_re.search(server_name): + continue + if server_name not in server_hosts_map: server_hosts_map[server_name] = [] @@ -1094,8 +1259,14 @@ def handle_mcp_show_servers(args: Namespace) -> int: # Human-readable output if not servers_data: + filters = [] + if filter_name: + filters.append(f"server '{filter_name}'") if host_pattern: - print(f"No servers on hosts matching '{host_pattern}'") + filters.append(f"host '{host_pattern}'") + + if filters: + print(f"No MCP servers found matching {' and '.join(filters)}") else: print("No MCP servers found") return EXIT_SUCCESS