claude-mpm 4.3.6__py3-none-any.whl → 4.3.12__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- claude_mpm/VERSION +1 -1
- claude_mpm/agents/BASE_PM.md +41 -8
- claude_mpm/agents/PM_INSTRUCTIONS.md +85 -43
- claude_mpm/agents/templates/clerk-ops.json +223 -0
- claude_mpm/agents/templates/data_engineer.json +41 -5
- claude_mpm/agents/templates/php-engineer.json +185 -0
- claude_mpm/agents/templates/research.json +20 -8
- claude_mpm/agents/templates/web_qa.json +25 -10
- claude_mpm/cli/__init__.py +41 -2
- claude_mpm/cli/commands/agents.py +2 -2
- claude_mpm/cli/commands/analyze.py +4 -4
- claude_mpm/cli/commands/cleanup.py +7 -7
- claude_mpm/cli/commands/configure_tui.py +2 -2
- claude_mpm/cli/commands/debug.py +2 -2
- claude_mpm/cli/commands/info.py +3 -4
- claude_mpm/cli/commands/mcp.py +8 -6
- claude_mpm/cli/commands/mcp_command_router.py +11 -0
- claude_mpm/cli/commands/mcp_config.py +157 -0
- claude_mpm/cli/commands/mcp_external_commands.py +241 -0
- claude_mpm/cli/commands/mcp_install_commands.py +73 -32
- claude_mpm/cli/commands/mcp_setup_external.py +829 -0
- claude_mpm/cli/commands/run.py +73 -3
- claude_mpm/cli/commands/search.py +285 -0
- claude_mpm/cli/parsers/base_parser.py +13 -0
- claude_mpm/cli/parsers/mcp_parser.py +17 -0
- claude_mpm/cli/parsers/run_parser.py +5 -0
- claude_mpm/cli/parsers/search_parser.py +239 -0
- claude_mpm/cli/startup_logging.py +20 -7
- claude_mpm/constants.py +1 -0
- claude_mpm/core/unified_agent_registry.py +7 -0
- claude_mpm/hooks/instruction_reinforcement.py +295 -0
- claude_mpm/services/agents/deployment/agent_deployment.py +28 -13
- claude_mpm/services/agents/deployment/agent_discovery_service.py +16 -6
- claude_mpm/services/agents/deployment/deployment_wrapper.py +59 -0
- claude_mpm/services/agents/deployment/multi_source_deployment_service.py +6 -4
- claude_mpm/services/cli/agent_cleanup_service.py +5 -0
- claude_mpm/services/mcp_config_manager.py +294 -0
- claude_mpm/services/mcp_gateway/config/configuration.py +17 -0
- claude_mpm/services/mcp_gateway/main.py +38 -0
- claude_mpm/services/mcp_gateway/tools/external_mcp_services.py +390 -0
- claude_mpm/utils/log_cleanup.py +17 -17
- claude_mpm/utils/subprocess_utils.py +6 -6
- {claude_mpm-4.3.6.dist-info → claude_mpm-4.3.12.dist-info}/METADATA +24 -1
- {claude_mpm-4.3.6.dist-info → claude_mpm-4.3.12.dist-info}/RECORD +48 -39
- claude_mpm/agents/templates/agent-manager.md +0 -619
- {claude_mpm-4.3.6.dist-info → claude_mpm-4.3.12.dist-info}/WHEEL +0 -0
- {claude_mpm-4.3.6.dist-info → claude_mpm-4.3.12.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.3.6.dist-info → claude_mpm-4.3.12.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.3.6.dist-info → claude_mpm-4.3.12.dist-info}/top_level.txt +0 -0
claude_mpm/cli/commands/info.py
CHANGED
|
@@ -11,6 +11,7 @@ DESIGN DECISIONS:
|
|
|
11
11
|
- Provide comprehensive system information for troubleshooting
|
|
12
12
|
"""
|
|
13
13
|
|
|
14
|
+
import importlib.util
|
|
14
15
|
import shutil
|
|
15
16
|
from pathlib import Path
|
|
16
17
|
from typing import Any, Dict
|
|
@@ -119,14 +120,12 @@ class InfoCommand(BaseCommand):
|
|
|
119
120
|
}
|
|
120
121
|
|
|
121
122
|
# Check ai-trackdown-pytools
|
|
122
|
-
|
|
123
|
-
import ai_trackdown_pytools
|
|
124
|
-
|
|
123
|
+
if importlib.util.find_spec("ai_trackdown_pytools") is not None:
|
|
125
124
|
dependencies["ai_trackdown_pytools"] = {
|
|
126
125
|
"installed": True,
|
|
127
126
|
"status": "✓ Installed",
|
|
128
127
|
}
|
|
129
|
-
|
|
128
|
+
else:
|
|
130
129
|
dependencies["ai_trackdown_pytools"] = {
|
|
131
130
|
"installed": False,
|
|
132
131
|
"status": "✗ Not installed",
|
claude_mpm/cli/commands/mcp.py
CHANGED
|
@@ -34,9 +34,10 @@ def manage_mcp(args):
|
|
|
34
34
|
logger = get_logger("cli.mcp")
|
|
35
35
|
|
|
36
36
|
# First check if MCP package is installed for any command
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
37
|
+
import importlib.util
|
|
38
|
+
|
|
39
|
+
mcp_spec = importlib.util.find_spec("mcp")
|
|
40
|
+
if not mcp_spec:
|
|
40
41
|
if args.mcp_command != MCPCommands.INSTALL.value:
|
|
41
42
|
print("\nMCP package is not installed.", file=sys.stderr)
|
|
42
43
|
print("Please install it first:", file=sys.stderr)
|
|
@@ -129,11 +130,12 @@ def _show_status(
|
|
|
129
130
|
print("=" * 50)
|
|
130
131
|
|
|
131
132
|
# Check if MCP package is installed
|
|
132
|
-
|
|
133
|
-
import mcp
|
|
133
|
+
import importlib.util
|
|
134
134
|
|
|
135
|
+
mcp_spec = importlib.util.find_spec("mcp")
|
|
136
|
+
if mcp_spec:
|
|
135
137
|
print("✅ MCP package installed")
|
|
136
|
-
|
|
138
|
+
else:
|
|
137
139
|
print("❌ MCP package not installed")
|
|
138
140
|
print(" Run: claude-mpm mcp install")
|
|
139
141
|
return 1
|
|
@@ -45,6 +45,9 @@ class MCPCommandRouter:
|
|
|
45
45
|
if args.mcp_command == MCPCommands.SERVER.value:
|
|
46
46
|
return self._run_server(args)
|
|
47
47
|
|
|
48
|
+
if args.mcp_command == MCPCommands.EXTERNAL.value:
|
|
49
|
+
return self._manage_external(args)
|
|
50
|
+
|
|
48
51
|
if args.mcp_command == "cleanup":
|
|
49
52
|
return self._cleanup_locks(args)
|
|
50
53
|
|
|
@@ -124,6 +127,13 @@ class MCPCommandRouter:
|
|
|
124
127
|
handler = MCPServerCommands(self.logger)
|
|
125
128
|
return asyncio.run(handler.start_server(args))
|
|
126
129
|
|
|
130
|
+
def _manage_external(self, args) -> int:
|
|
131
|
+
"""Manage external MCP services command handler."""
|
|
132
|
+
from .mcp_external_commands import MCPExternalCommands
|
|
133
|
+
|
|
134
|
+
handler = MCPExternalCommands(self.logger)
|
|
135
|
+
return handler.manage_external(args)
|
|
136
|
+
|
|
127
137
|
def _show_help(self):
|
|
128
138
|
"""Show available MCP commands."""
|
|
129
139
|
print("\nAvailable MCP commands:")
|
|
@@ -136,6 +146,7 @@ class MCPCommandRouter:
|
|
|
136
146
|
print(" register - Register a new tool")
|
|
137
147
|
print(" test - Test tool invocation")
|
|
138
148
|
print(" config - View and manage configuration")
|
|
149
|
+
print(" external - Manage external MCP services")
|
|
139
150
|
print(" cleanup - Clean up legacy files")
|
|
140
151
|
print("\nFor help with a specific command:")
|
|
141
152
|
print(" claude-mpm mcp <command> --help")
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
"""
|
|
2
|
+
MCP Configuration Command
|
|
3
|
+
=========================
|
|
4
|
+
|
|
5
|
+
Command for managing MCP service configurations with pipx preference.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import json
|
|
9
|
+
import sys
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
|
|
12
|
+
from ...services.mcp_config_manager import MCPConfigManager
|
|
13
|
+
from ..shared import BaseCommand, CommandResult
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class MCPConfigCommand(BaseCommand):
|
|
17
|
+
"""Manage MCP service configurations."""
|
|
18
|
+
|
|
19
|
+
def __init__(self):
|
|
20
|
+
super().__init__("mcp-config")
|
|
21
|
+
|
|
22
|
+
def run(self, args) -> CommandResult:
|
|
23
|
+
"""Execute the MCP configuration command."""
|
|
24
|
+
manager = MCPConfigManager()
|
|
25
|
+
|
|
26
|
+
# Handle different sub-commands
|
|
27
|
+
if hasattr(args, "mcp_config_command"):
|
|
28
|
+
command = args.mcp_config_command
|
|
29
|
+
|
|
30
|
+
if command == "detect":
|
|
31
|
+
return self._detect_services(manager)
|
|
32
|
+
elif command == "update":
|
|
33
|
+
return self._update_config(manager, args)
|
|
34
|
+
elif command == "validate":
|
|
35
|
+
return self._validate_config(manager)
|
|
36
|
+
elif command == "install":
|
|
37
|
+
return self._install_services(manager)
|
|
38
|
+
else:
|
|
39
|
+
return self._show_status(manager)
|
|
40
|
+
else:
|
|
41
|
+
return self._show_status(manager)
|
|
42
|
+
|
|
43
|
+
def _detect_services(self, manager: MCPConfigManager) -> CommandResult:
|
|
44
|
+
"""Detect available MCP services."""
|
|
45
|
+
results = {}
|
|
46
|
+
for service in manager.PIPX_SERVICES:
|
|
47
|
+
path = manager.detect_service_path(service)
|
|
48
|
+
results[service] = {
|
|
49
|
+
"found": path is not None,
|
|
50
|
+
"path": path or "Not found",
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return CommandResult(
|
|
54
|
+
success=True,
|
|
55
|
+
message="MCP service detection complete",
|
|
56
|
+
data=results,
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
def _update_config(self, manager: MCPConfigManager, args) -> CommandResult:
|
|
60
|
+
"""Update MCP configuration."""
|
|
61
|
+
force_pipx = getattr(args, "force_pipx", True)
|
|
62
|
+
success, message = manager.update_mcp_config(force_pipx=force_pipx)
|
|
63
|
+
|
|
64
|
+
if success:
|
|
65
|
+
# Show the updated configuration
|
|
66
|
+
config_path = Path.cwd() / ".mcp.json"
|
|
67
|
+
if config_path.exists():
|
|
68
|
+
with open(config_path, "r") as f:
|
|
69
|
+
config = json.load(f)
|
|
70
|
+
return CommandResult(
|
|
71
|
+
success=True,
|
|
72
|
+
message=message,
|
|
73
|
+
data=config,
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
return CommandResult(
|
|
77
|
+
success=success,
|
|
78
|
+
message=message,
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
def _validate_config(self, manager: MCPConfigManager) -> CommandResult:
|
|
82
|
+
"""Validate current MCP configuration."""
|
|
83
|
+
results = manager.validate_configuration()
|
|
84
|
+
|
|
85
|
+
all_valid = all(results.values()) if results else False
|
|
86
|
+
message = (
|
|
87
|
+
"All MCP services are properly configured"
|
|
88
|
+
if all_valid
|
|
89
|
+
else "Some MCP services are not accessible"
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
return CommandResult(
|
|
93
|
+
success=all_valid,
|
|
94
|
+
message=message,
|
|
95
|
+
data=results,
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
def _install_services(self, manager: MCPConfigManager) -> CommandResult:
|
|
99
|
+
"""Install missing MCP services."""
|
|
100
|
+
success, message = manager.install_missing_services()
|
|
101
|
+
return CommandResult(
|
|
102
|
+
success=success,
|
|
103
|
+
message=message,
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
def _show_status(self, manager: MCPConfigManager) -> CommandResult:
|
|
107
|
+
"""Show current MCP configuration status."""
|
|
108
|
+
# Detect services
|
|
109
|
+
detected = {}
|
|
110
|
+
for service in manager.PIPX_SERVICES:
|
|
111
|
+
path = manager.detect_service_path(service)
|
|
112
|
+
detected[service] = {
|
|
113
|
+
"installed": path is not None,
|
|
114
|
+
"path": path or "Not installed",
|
|
115
|
+
"via_pipx": path and "pipx" in path if path else False,
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
# Validate configuration
|
|
119
|
+
config_valid = manager.validate_configuration()
|
|
120
|
+
|
|
121
|
+
# Read current config
|
|
122
|
+
config_path = Path.cwd() / ".mcp.json"
|
|
123
|
+
current_config = {}
|
|
124
|
+
if config_path.exists():
|
|
125
|
+
try:
|
|
126
|
+
with open(config_path, "r") as f:
|
|
127
|
+
current_config = json.load(f)
|
|
128
|
+
except Exception:
|
|
129
|
+
pass
|
|
130
|
+
|
|
131
|
+
status_data = {
|
|
132
|
+
"services": detected,
|
|
133
|
+
"configuration_valid": config_valid,
|
|
134
|
+
"config_file_exists": config_path.exists(),
|
|
135
|
+
"configured_services": list(current_config.get("mcpServers", {}).keys()),
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return CommandResult(
|
|
139
|
+
success=True,
|
|
140
|
+
message="MCP configuration status",
|
|
141
|
+
data=status_data,
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def manage_mcp_config(args):
|
|
146
|
+
"""
|
|
147
|
+
Entry point for MCP configuration command.
|
|
148
|
+
|
|
149
|
+
Args:
|
|
150
|
+
args: Parsed command line arguments
|
|
151
|
+
|
|
152
|
+
Returns:
|
|
153
|
+
Exit code
|
|
154
|
+
"""
|
|
155
|
+
command = MCPConfigCommand()
|
|
156
|
+
result = command.execute(args)
|
|
157
|
+
return result.exit_code
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
"""MCP external services command implementations.
|
|
2
|
+
|
|
3
|
+
This module provides commands for managing external MCP services
|
|
4
|
+
like mcp-vector-search and mcp-browser.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import sys
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class MCPExternalCommands:
|
|
11
|
+
"""Handles MCP external service commands."""
|
|
12
|
+
|
|
13
|
+
def __init__(self, logger):
|
|
14
|
+
"""Initialize the MCP external commands handler."""
|
|
15
|
+
self.logger = logger
|
|
16
|
+
|
|
17
|
+
def manage_external(self, args):
|
|
18
|
+
"""Manage external MCP services.
|
|
19
|
+
|
|
20
|
+
Args:
|
|
21
|
+
args: Parsed command line arguments
|
|
22
|
+
|
|
23
|
+
Returns:
|
|
24
|
+
int: Exit code (0 for success, non-zero for failure)
|
|
25
|
+
"""
|
|
26
|
+
# Get the external subcommand if it exists
|
|
27
|
+
external_action = getattr(args, 'external_action', None)
|
|
28
|
+
|
|
29
|
+
if not external_action:
|
|
30
|
+
# No subcommand provided, show help
|
|
31
|
+
self._show_help()
|
|
32
|
+
return 0
|
|
33
|
+
|
|
34
|
+
# Route to appropriate handler
|
|
35
|
+
if external_action == "setup":
|
|
36
|
+
return self._setup_external(args)
|
|
37
|
+
elif external_action == "list":
|
|
38
|
+
return self._list_external(args)
|
|
39
|
+
elif external_action == "check":
|
|
40
|
+
return self._check_external(args)
|
|
41
|
+
elif external_action == "fix-browser":
|
|
42
|
+
return self._fix_browser(args)
|
|
43
|
+
elif external_action == "detect":
|
|
44
|
+
return self._detect_and_update(args)
|
|
45
|
+
else:
|
|
46
|
+
print(f"Unknown external subcommand: {external_action}")
|
|
47
|
+
self._show_help()
|
|
48
|
+
return 1
|
|
49
|
+
|
|
50
|
+
def _setup_external(self, args):
|
|
51
|
+
"""Setup external MCP services in Claude Desktop.
|
|
52
|
+
|
|
53
|
+
Args:
|
|
54
|
+
args: Command line arguments
|
|
55
|
+
|
|
56
|
+
Returns:
|
|
57
|
+
int: Exit code
|
|
58
|
+
"""
|
|
59
|
+
print("📦 Setting up External MCP Services")
|
|
60
|
+
print("=" * 50)
|
|
61
|
+
|
|
62
|
+
from .mcp_setup_external import MCPExternalServicesSetup
|
|
63
|
+
|
|
64
|
+
setup = MCPExternalServicesSetup(self.logger)
|
|
65
|
+
|
|
66
|
+
# First install Python packages
|
|
67
|
+
print("\n1️⃣ Installing Python packages...")
|
|
68
|
+
if not setup.check_and_install_pip_packages():
|
|
69
|
+
print("⚠️ Some Python packages could not be installed")
|
|
70
|
+
print(" You may need to install them manually:")
|
|
71
|
+
print(" pip install mcp-vector-search mcp-browser")
|
|
72
|
+
|
|
73
|
+
# Then configure in Claude Desktop
|
|
74
|
+
print("\n2️⃣ Configuring Claude Desktop...")
|
|
75
|
+
force = getattr(args, 'force', False)
|
|
76
|
+
if setup.setup_external_services(force=force):
|
|
77
|
+
print("\n✅ External services setup completed successfully!")
|
|
78
|
+
print("\nNext steps:")
|
|
79
|
+
print("1. Restart Claude Desktop to load the new services")
|
|
80
|
+
print("2. Check status with: claude-mpm mcp external list")
|
|
81
|
+
print("3. The services will be available in Claude as separate MCP servers")
|
|
82
|
+
return 0
|
|
83
|
+
else:
|
|
84
|
+
print("\n❌ Failed to setup external services")
|
|
85
|
+
print("Please check the error messages above and try again")
|
|
86
|
+
return 1
|
|
87
|
+
|
|
88
|
+
def _list_external(self, args):
|
|
89
|
+
"""List external MCP services and their status.
|
|
90
|
+
|
|
91
|
+
Args:
|
|
92
|
+
args: Command line arguments
|
|
93
|
+
|
|
94
|
+
Returns:
|
|
95
|
+
int: Exit code
|
|
96
|
+
"""
|
|
97
|
+
from .mcp_setup_external import MCPExternalServicesSetup
|
|
98
|
+
|
|
99
|
+
setup = MCPExternalServicesSetup(self.logger)
|
|
100
|
+
setup.list_external_services()
|
|
101
|
+
return 0
|
|
102
|
+
|
|
103
|
+
def _check_external(self, args):
|
|
104
|
+
"""Check if external services are properly configured.
|
|
105
|
+
|
|
106
|
+
Args:
|
|
107
|
+
args: Command line arguments
|
|
108
|
+
|
|
109
|
+
Returns:
|
|
110
|
+
int: Exit code
|
|
111
|
+
"""
|
|
112
|
+
print("🔍 Checking External MCP Services Configuration")
|
|
113
|
+
print("=" * 50)
|
|
114
|
+
|
|
115
|
+
from pathlib import Path
|
|
116
|
+
import json
|
|
117
|
+
|
|
118
|
+
# Check Claude Desktop configuration
|
|
119
|
+
config_paths = [
|
|
120
|
+
Path.home() / "Library" / "Application Support" / "Claude" / "claude_desktop_config.json", # macOS
|
|
121
|
+
Path.home() / ".config" / "Claude" / "claude_desktop_config.json", # Linux
|
|
122
|
+
Path.home() / "AppData" / "Roaming" / "Claude" / "claude_desktop_config.json", # Windows
|
|
123
|
+
Path.home() / ".claude" / "claude_desktop_config.json", # Alternative
|
|
124
|
+
Path.home() / ".claude.json" # Legacy
|
|
125
|
+
]
|
|
126
|
+
|
|
127
|
+
config_found = False
|
|
128
|
+
for config_path in config_paths:
|
|
129
|
+
if config_path.exists():
|
|
130
|
+
config_found = True
|
|
131
|
+
print(f"\n📄 Found config: {config_path}")
|
|
132
|
+
|
|
133
|
+
try:
|
|
134
|
+
with open(config_path) as f:
|
|
135
|
+
config = json.load(f)
|
|
136
|
+
|
|
137
|
+
mcp_servers = config.get("mcpServers", {})
|
|
138
|
+
|
|
139
|
+
# Check for external services
|
|
140
|
+
external_services = ["mcp-vector-search", "mcp-browser"]
|
|
141
|
+
for service in external_services:
|
|
142
|
+
if service in mcp_servers:
|
|
143
|
+
print(f" ✅ {service} is configured")
|
|
144
|
+
server_config = mcp_servers[service]
|
|
145
|
+
print(f" Command: {server_config.get('command')}")
|
|
146
|
+
print(f" Args: {server_config.get('args')}")
|
|
147
|
+
else:
|
|
148
|
+
print(f" ❌ {service} is NOT configured")
|
|
149
|
+
|
|
150
|
+
except Exception as e:
|
|
151
|
+
print(f" ❌ Error reading config: {e}")
|
|
152
|
+
|
|
153
|
+
break
|
|
154
|
+
|
|
155
|
+
if not config_found:
|
|
156
|
+
print("❌ No Claude Desktop configuration found")
|
|
157
|
+
print(" Please run: claude-mpm mcp install")
|
|
158
|
+
|
|
159
|
+
# Check Python packages
|
|
160
|
+
print("\n🐍 Python Package Status:")
|
|
161
|
+
from .mcp_setup_external import MCPExternalServicesSetup
|
|
162
|
+
|
|
163
|
+
setup = MCPExternalServicesSetup(self.logger)
|
|
164
|
+
|
|
165
|
+
packages = [
|
|
166
|
+
("mcp-vector-search", "mcp_vector_search"),
|
|
167
|
+
("mcp-browser", "mcp_browser")
|
|
168
|
+
]
|
|
169
|
+
|
|
170
|
+
for package_name, module_name in packages:
|
|
171
|
+
if setup._check_python_package(module_name):
|
|
172
|
+
print(f" ✅ {package_name} is installed")
|
|
173
|
+
else:
|
|
174
|
+
print(f" ❌ {package_name} is NOT installed")
|
|
175
|
+
|
|
176
|
+
return 0
|
|
177
|
+
|
|
178
|
+
def _fix_browser(self, args):
|
|
179
|
+
"""Fix mcp-browser configuration to use pipx installation.
|
|
180
|
+
|
|
181
|
+
Args:
|
|
182
|
+
args: Command line arguments
|
|
183
|
+
|
|
184
|
+
Returns:
|
|
185
|
+
int: Exit code
|
|
186
|
+
"""
|
|
187
|
+
from .mcp_setup_external import MCPExternalServicesSetup
|
|
188
|
+
|
|
189
|
+
setup = MCPExternalServicesSetup(self.logger)
|
|
190
|
+
if setup.fix_browser_configuration():
|
|
191
|
+
return 0
|
|
192
|
+
else:
|
|
193
|
+
return 1
|
|
194
|
+
|
|
195
|
+
def _detect_and_update(self, args):
|
|
196
|
+
"""Auto-detect MCP service installations and update configuration.
|
|
197
|
+
|
|
198
|
+
Prioritizes local development installations over pipx/system.
|
|
199
|
+
|
|
200
|
+
Args:
|
|
201
|
+
args: Command line arguments
|
|
202
|
+
|
|
203
|
+
Returns:
|
|
204
|
+
int: Exit code
|
|
205
|
+
"""
|
|
206
|
+
from .mcp_setup_external import MCPExternalServicesSetup
|
|
207
|
+
|
|
208
|
+
setup = MCPExternalServicesSetup(self.logger)
|
|
209
|
+
force = getattr(args, 'force', False)
|
|
210
|
+
|
|
211
|
+
if setup.update_mcp_json_with_detected(force=force):
|
|
212
|
+
print("\n✅ Configuration updated successfully!")
|
|
213
|
+
print("\nNext steps:")
|
|
214
|
+
print("1. Review the .mcp.json file to verify the configuration")
|
|
215
|
+
print("2. Restart Claude Desktop to load the updated services")
|
|
216
|
+
return 0
|
|
217
|
+
else:
|
|
218
|
+
print("\n❌ Failed to update configuration")
|
|
219
|
+
return 1
|
|
220
|
+
|
|
221
|
+
def _show_help(self):
|
|
222
|
+
"""Show help for external commands."""
|
|
223
|
+
print("\nMCP External Services Management")
|
|
224
|
+
print("=" * 40)
|
|
225
|
+
print("\nAvailable commands:")
|
|
226
|
+
print(" setup - Setup external MCP services (mcp-vector-search, mcp-browser)")
|
|
227
|
+
print(" list - List available external services and their status")
|
|
228
|
+
print(" check - Check configuration and installation status")
|
|
229
|
+
print(" detect - Auto-detect installations and update .mcp.json (prioritizes local dev)")
|
|
230
|
+
print(" fix-browser - Fix mcp-browser configuration to use pipx installation")
|
|
231
|
+
print("\nUsage:")
|
|
232
|
+
print(" claude-mpm mcp external setup # Interactive setup")
|
|
233
|
+
print(" claude-mpm mcp external setup --force # Force reconfiguration")
|
|
234
|
+
print(" claude-mpm mcp external detect # Auto-detect and update config")
|
|
235
|
+
print(" claude-mpm mcp external detect --force # Force update even if configured")
|
|
236
|
+
print(" claude-mpm mcp external list # Show service status")
|
|
237
|
+
print(" claude-mpm mcp external check # Detailed configuration check")
|
|
238
|
+
print(" claude-mpm mcp external fix-browser # Fix mcp-browser to use pipx")
|
|
239
|
+
print("\nExternal services provide additional capabilities:")
|
|
240
|
+
print(" - mcp-vector-search: Semantic code search with embeddings")
|
|
241
|
+
print(" - mcp-browser: Web browsing and content extraction")
|
|
@@ -31,11 +31,12 @@ class MCPInstallCommands:
|
|
|
31
31
|
|
|
32
32
|
# Step 1: Install MCP package if needed
|
|
33
33
|
print("\n1️⃣ Checking MCP package installation...")
|
|
34
|
-
|
|
35
|
-
import mcp
|
|
34
|
+
import importlib.util
|
|
36
35
|
|
|
36
|
+
mcp_spec = importlib.util.find_spec("mcp")
|
|
37
|
+
if mcp_spec:
|
|
37
38
|
print("✅ MCP package already installed")
|
|
38
|
-
|
|
39
|
+
else:
|
|
39
40
|
print("📦 Installing MCP package...")
|
|
40
41
|
try:
|
|
41
42
|
subprocess.check_call([sys.executable, "-m", "pip", "install", "mcp"])
|
|
@@ -45,31 +46,54 @@ class MCPInstallCommands:
|
|
|
45
46
|
print("\nPlease install manually with: pip install mcp")
|
|
46
47
|
return 1
|
|
47
48
|
|
|
48
|
-
# Step 2: Configure Claude
|
|
49
|
-
print("\n2️⃣ Configuring Claude
|
|
49
|
+
# Step 2: Configure Claude Desktop with the new CLI command
|
|
50
|
+
print("\n2️⃣ Configuring Claude Desktop...")
|
|
50
51
|
try:
|
|
51
52
|
success = self._configure_claude_desktop(args.force)
|
|
52
|
-
if success:
|
|
53
|
-
print("
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
53
|
+
if not success:
|
|
54
|
+
print("❌ Main gateway configuration failed")
|
|
55
|
+
return 1
|
|
56
|
+
|
|
57
|
+
# Step 3: Setup external MCP services
|
|
58
|
+
print("\n3️⃣ Setting up External MCP Services...")
|
|
59
|
+
from .mcp_setup_external import MCPExternalServicesSetup
|
|
60
|
+
|
|
61
|
+
external_setup = MCPExternalServicesSetup(self.logger)
|
|
62
|
+
|
|
63
|
+
# Check if user wants to set up external services
|
|
64
|
+
response = input("\nDo you want to set up external MCP services (mcp-vector-search, mcp-browser)? (Y/n): ").strip().lower()
|
|
65
|
+
if response in ["", "y", "yes"]:
|
|
66
|
+
# Install Python packages for external services
|
|
67
|
+
external_setup.check_and_install_pip_packages()
|
|
68
|
+
|
|
69
|
+
# Setup external services in Claude Desktop config
|
|
70
|
+
if external_setup.setup_external_services(force=args.force):
|
|
71
|
+
print("✅ External services configured successfully")
|
|
72
|
+
else:
|
|
73
|
+
print("⚠️ Some external services may not have been configured")
|
|
74
|
+
else:
|
|
75
|
+
print("⏭️ Skipping external services setup")
|
|
76
|
+
print(" You can set them up later with: claude-mpm mcp external setup")
|
|
77
|
+
|
|
78
|
+
print("\n✅ Configuration completed successfully")
|
|
79
|
+
print("\n🎉 MCP Gateway is ready to use!")
|
|
80
|
+
print("\nNext steps:")
|
|
81
|
+
print("1. Restart Claude Desktop (if running)")
|
|
82
|
+
print("2. Test the server: claude-mpm mcp server --test")
|
|
83
|
+
print("3. Check status: claude-mpm mcp status")
|
|
84
|
+
print("4. List external services: claude-mpm mcp external list")
|
|
85
|
+
return 0
|
|
62
86
|
|
|
63
87
|
except Exception as e:
|
|
64
88
|
print(f"❌ Error during configuration: {e}")
|
|
65
89
|
return 1
|
|
66
90
|
|
|
67
91
|
def _configure_claude_desktop(self, force=False):
|
|
68
|
-
"""Configure Claude
|
|
92
|
+
"""Configure Claude Desktop to use the MCP gateway via CLI command.
|
|
69
93
|
|
|
70
|
-
WHY: Claude
|
|
71
|
-
|
|
72
|
-
|
|
94
|
+
WHY: Claude Desktop reads MCP server configurations from a platform-specific
|
|
95
|
+
configuration file. This method updates that file to include the claude-mpm-gateway
|
|
96
|
+
server configuration.
|
|
73
97
|
|
|
74
98
|
Args:
|
|
75
99
|
force: Whether to overwrite existing configuration
|
|
@@ -134,16 +158,34 @@ class MCPInstallCommands:
|
|
|
134
158
|
return self._save_config(config, config_path)
|
|
135
159
|
|
|
136
160
|
def _get_claude_config_path(self):
|
|
137
|
-
"""Get the Claude
|
|
161
|
+
"""Get the Claude Desktop configuration file path.
|
|
138
162
|
|
|
139
163
|
Returns:
|
|
140
|
-
Path or None: Path to Claude
|
|
164
|
+
Path or None: Path to Claude Desktop config file
|
|
141
165
|
"""
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
#
|
|
145
|
-
|
|
146
|
-
|
|
166
|
+
import platform
|
|
167
|
+
|
|
168
|
+
# Try multiple possible locations for Claude Desktop config
|
|
169
|
+
possible_paths = [
|
|
170
|
+
Path.home() / "Library" / "Application Support" / "Claude" / "claude_desktop_config.json", # macOS
|
|
171
|
+
Path.home() / ".config" / "Claude" / "claude_desktop_config.json", # Linux
|
|
172
|
+
Path.home() / "AppData" / "Roaming" / "Claude" / "claude_desktop_config.json", # Windows
|
|
173
|
+
Path.home() / ".claude" / "claude_desktop_config.json", # Alternative
|
|
174
|
+
Path.home() / ".claude.json", # Legacy
|
|
175
|
+
]
|
|
176
|
+
|
|
177
|
+
for path in possible_paths:
|
|
178
|
+
if path.exists():
|
|
179
|
+
return path
|
|
180
|
+
|
|
181
|
+
# If none exist, return the platform-appropriate default
|
|
182
|
+
system = platform.system()
|
|
183
|
+
if system == "Darwin": # macOS
|
|
184
|
+
return Path.home() / "Library" / "Application Support" / "Claude" / "claude_desktop_config.json"
|
|
185
|
+
elif system == "Windows":
|
|
186
|
+
return Path.home() / "AppData" / "Roaming" / "Claude" / "claude_desktop_config.json"
|
|
187
|
+
else: # Linux and others
|
|
188
|
+
return Path.home() / ".config" / "Claude" / "claude_desktop_config.json"
|
|
147
189
|
|
|
148
190
|
def _find_claude_mpm_executable(self):
|
|
149
191
|
"""Find the claude-mpm executable path.
|
|
@@ -172,13 +214,12 @@ class MCPInstallCommands:
|
|
|
172
214
|
return str(executable_path)
|
|
173
215
|
|
|
174
216
|
# Fallback: Use Python module invocation if no executable found
|
|
175
|
-
|
|
176
|
-
import claude_mpm
|
|
217
|
+
import importlib.util
|
|
177
218
|
|
|
219
|
+
claude_mpm_spec = importlib.util.find_spec("claude_mpm")
|
|
220
|
+
if claude_mpm_spec:
|
|
178
221
|
print(f" Using Python module: {sys.executable} -m claude_mpm")
|
|
179
222
|
return sys.executable
|
|
180
|
-
except ImportError:
|
|
181
|
-
pass
|
|
182
223
|
|
|
183
224
|
return None
|
|
184
225
|
|
|
@@ -193,7 +234,7 @@ class MCPInstallCommands:
|
|
|
193
234
|
dict or None: Configuration dictionary
|
|
194
235
|
"""
|
|
195
236
|
import json
|
|
196
|
-
from datetime import datetime
|
|
237
|
+
from datetime import datetime, timezone
|
|
197
238
|
|
|
198
239
|
config = {}
|
|
199
240
|
|
|
@@ -226,7 +267,7 @@ class MCPInstallCommands:
|
|
|
226
267
|
|
|
227
268
|
# Create backup
|
|
228
269
|
backup_path = config_path.with_suffix(
|
|
229
|
-
f'.backup.{datetime.now().strftime("%Y%m%d_%H%M%S")}.json'
|
|
270
|
+
f'.backup.{datetime.now(timezone.utc).strftime("%Y%m%d_%H%M%S")}.json'
|
|
230
271
|
)
|
|
231
272
|
try:
|
|
232
273
|
config_path.rename(backup_path)
|