claude-mpm 4.5.6__py3-none-any.whl → 4.5.11__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.
Files changed (62) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/__init__.py +20 -5
  3. claude_mpm/agents/BASE_OPS.md +10 -0
  4. claude_mpm/agents/PM_INSTRUCTIONS.md +28 -4
  5. claude_mpm/agents/agent_loader.py +19 -2
  6. claude_mpm/agents/base_agent_loader.py +5 -5
  7. claude_mpm/agents/templates/agent-manager.json +3 -3
  8. claude_mpm/agents/templates/agentic-coder-optimizer.json +3 -3
  9. claude_mpm/agents/templates/api_qa.json +1 -1
  10. claude_mpm/agents/templates/clerk-ops.json +3 -3
  11. claude_mpm/agents/templates/code_analyzer.json +3 -3
  12. claude_mpm/agents/templates/dart_engineer.json +294 -0
  13. claude_mpm/agents/templates/data_engineer.json +3 -3
  14. claude_mpm/agents/templates/documentation.json +2 -2
  15. claude_mpm/agents/templates/engineer.json +2 -2
  16. claude_mpm/agents/templates/gcp_ops_agent.json +2 -2
  17. claude_mpm/agents/templates/imagemagick.json +1 -1
  18. claude_mpm/agents/templates/local_ops_agent.json +363 -49
  19. claude_mpm/agents/templates/memory_manager.json +2 -2
  20. claude_mpm/agents/templates/nextjs_engineer.json +2 -2
  21. claude_mpm/agents/templates/ops.json +2 -2
  22. claude_mpm/agents/templates/php-engineer.json +1 -1
  23. claude_mpm/agents/templates/project_organizer.json +1 -1
  24. claude_mpm/agents/templates/prompt-engineer.json +6 -4
  25. claude_mpm/agents/templates/python_engineer.json +2 -2
  26. claude_mpm/agents/templates/qa.json +1 -1
  27. claude_mpm/agents/templates/react_engineer.json +3 -3
  28. claude_mpm/agents/templates/refactoring_engineer.json +3 -3
  29. claude_mpm/agents/templates/research.json +2 -2
  30. claude_mpm/agents/templates/security.json +2 -2
  31. claude_mpm/agents/templates/ticketing.json +2 -2
  32. claude_mpm/agents/templates/typescript_engineer.json +2 -2
  33. claude_mpm/agents/templates/vercel_ops_agent.json +2 -2
  34. claude_mpm/agents/templates/version_control.json +2 -2
  35. claude_mpm/agents/templates/web_qa.json +6 -6
  36. claude_mpm/agents/templates/web_ui.json +3 -3
  37. claude_mpm/cli/__init__.py +49 -19
  38. claude_mpm/cli/commands/configure.py +591 -7
  39. claude_mpm/cli/parsers/configure_parser.py +5 -0
  40. claude_mpm/core/__init__.py +53 -17
  41. claude_mpm/core/config.py +1 -1
  42. claude_mpm/core/log_manager.py +7 -0
  43. claude_mpm/hooks/claude_hooks/response_tracking.py +16 -11
  44. claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +9 -11
  45. claude_mpm/services/__init__.py +140 -156
  46. claude_mpm/services/agents/deployment/deployment_config_loader.py +21 -0
  47. claude_mpm/services/agents/loading/base_agent_manager.py +12 -2
  48. claude_mpm/services/async_session_logger.py +112 -96
  49. claude_mpm/services/claude_session_logger.py +63 -61
  50. claude_mpm/services/mcp_config_manager.py +328 -38
  51. claude_mpm/services/mcp_gateway/__init__.py +98 -94
  52. claude_mpm/services/monitor/event_emitter.py +1 -1
  53. claude_mpm/services/orphan_detection.py +791 -0
  54. claude_mpm/services/project_port_allocator.py +601 -0
  55. claude_mpm/services/response_tracker.py +17 -6
  56. claude_mpm/services/session_manager.py +176 -0
  57. {claude_mpm-4.5.6.dist-info → claude_mpm-4.5.11.dist-info}/METADATA +1 -1
  58. {claude_mpm-4.5.6.dist-info → claude_mpm-4.5.11.dist-info}/RECORD +62 -58
  59. {claude_mpm-4.5.6.dist-info → claude_mpm-4.5.11.dist-info}/WHEEL +0 -0
  60. {claude_mpm-4.5.6.dist-info → claude_mpm-4.5.11.dist-info}/entry_points.txt +0 -0
  61. {claude_mpm-4.5.6.dist-info → claude_mpm-4.5.11.dist-info}/licenses/LICENSE +0 -0
  62. {claude_mpm-4.5.6.dist-info → claude_mpm-4.5.11.dist-info}/top_level.txt +0 -0
@@ -41,6 +41,16 @@ class MCPConfigManager:
41
41
  "kuzu-memory",
42
42
  }
43
43
 
44
+ # Known missing dependencies for MCP services that pipx doesn't handle automatically
45
+ # Maps service names to list of missing dependencies that need injection
46
+ SERVICE_MISSING_DEPENDENCIES = {
47
+ "mcp-ticketer": [
48
+ "gql"
49
+ ], # mcp-ticketer v0.1.8+ needs gql but doesn't declare it
50
+ # Add more services here as needed, e.g.:
51
+ # "another-service": ["dep1", "dep2"],
52
+ }
53
+
44
54
  # Static known-good MCP service configurations
45
55
  # These are the correct, tested configurations that work reliably
46
56
  # Note: Commands will be resolved to full paths dynamically in get_static_service_config()
@@ -72,15 +82,75 @@ class MCPConfigManager:
72
82
  },
73
83
  }
74
84
 
75
- def __init__(self):
76
- """Initialize the MCP configuration manager."""
85
+ def __init__(self, config=None):
86
+ """Initialize the MCP configuration manager.
87
+
88
+ Args:
89
+ config: Optional Config object for filtering services
90
+ """
77
91
  self.logger = get_logger(__name__)
78
92
  self.pipx_base = Path.home() / ".local" / "pipx" / "venvs"
79
93
  self.project_root = Path.cwd()
80
94
 
95
+ # Validate config type if provided
96
+ if config is not None:
97
+ from ..core.config import Config
98
+
99
+ if not isinstance(config, Config):
100
+ self.logger.warning(
101
+ f"Invalid config type provided to MCPConfigManager: "
102
+ f"{type(config).__name__}. Expected Config. "
103
+ f"Proceeding with config=None (all services enabled)."
104
+ )
105
+ config = None
106
+
107
+ self.config = config
108
+
81
109
  # Use the proper Claude config file location
82
110
  self.claude_config_path = ConfigLocation.CLAUDE_JSON.value
83
111
 
112
+ def should_enable_service(self, service_name: str) -> bool:
113
+ """
114
+ Check if an MCP service should be enabled based on startup configuration.
115
+
116
+ Args:
117
+ service_name: Name of the MCP service
118
+
119
+ Returns:
120
+ True if the service should be enabled, False otherwise
121
+ """
122
+ # If no config provided, enable all services by default
123
+ if self.config is None:
124
+ return True
125
+
126
+ # Import Config here to avoid circular import at module level
127
+ from ..core.config import Config
128
+
129
+ # Validate config type
130
+ if not isinstance(self.config, Config):
131
+ self.logger.warning(
132
+ f"Invalid config type: {type(self.config).__name__}, "
133
+ f"expected Config. Enabling all services by default."
134
+ )
135
+ return True
136
+
137
+ # Get startup configuration
138
+ enabled_services = self.config.get("startup.enabled_mcp_services", None)
139
+
140
+ # If no startup preferences configured, enable all services
141
+ if enabled_services is None:
142
+ return True
143
+
144
+ # Check if this service is in the enabled list
145
+ is_enabled = service_name in enabled_services
146
+
147
+ if not is_enabled:
148
+ self.logger.debug(
149
+ f"MCP service '{service_name}' disabled by startup configuration"
150
+ )
151
+
152
+ return is_enabled
153
+
84
154
  def detect_service_path(self, service_name: str) -> Optional[str]:
85
155
  """
86
156
  Detect the best path for an MCP service.
@@ -660,10 +730,8 @@ class MCPConfigManager:
660
730
  claude_config["projects"] = {}
661
731
  updated = True
662
732
 
663
- # Fix any corrupted MCP service installations first
664
- fix_success, fix_message = self.fix_mcp_service_issues()
665
- if not fix_success:
666
- self.logger.warning(f"Some MCP services could not be fixed: {fix_message}")
733
+ # Note: fix_mcp_service_issues() is already called during CLI initialization
734
+ # Calling it here would duplicate the service health checks
667
735
 
668
736
  # Process ALL projects in the config, not just current one
669
737
  projects_to_update = list(claude_config.get("projects", {}).keys())
@@ -696,19 +764,10 @@ class MCPConfigManager:
696
764
  project_config["mcpServers"] = {}
697
765
  updated = True
698
766
 
699
- # Check and fix each service configuration
700
- for service_name in self.PIPX_SERVICES:
701
- # Get the correct static configuration with project-specific paths
702
- correct_config = self.get_static_service_config(
703
- service_name, project_key
704
- )
705
-
706
- if not correct_config:
707
- self.logger.warning(
708
- f"No static config available for {service_name}"
709
- )
710
- continue
767
+ # Check and fix each service configuration - now filtered by startup config
768
+ services_to_configure = self.get_filtered_services()
711
769
 
770
+ for service_name, correct_config in services_to_configure.items():
712
771
  # Check if service exists and has correct configuration
713
772
  existing_config = project_config["mcpServers"].get(service_name)
714
773
 
@@ -734,6 +793,29 @@ class MCPConfigManager:
734
793
  f"Updated MCP service config for {service_name} in project {Path(project_key).name}"
735
794
  )
736
795
 
796
+ # Remove disabled services from configuration
797
+ if self.config is not None:
798
+ # Import Config here to avoid circular import
799
+ from ..core.config import Config
800
+
801
+ if isinstance(self.config, Config):
802
+ enabled_services = self.config.get(
803
+ "startup.enabled_mcp_services", None
804
+ )
805
+ if enabled_services is not None:
806
+ # Remove services that are not in the enabled list
807
+ services_to_remove = []
808
+ for service_name in project_config["mcpServers"]:
809
+ if service_name not in enabled_services:
810
+ services_to_remove.append(service_name)
811
+
812
+ for service_name in services_to_remove:
813
+ del project_config["mcpServers"][service_name]
814
+ updated = True
815
+ self.logger.debug(
816
+ f"Removed disabled service {service_name} from project {Path(project_key).name}"
817
+ )
818
+
737
819
  # Write updated config if changes were made
738
820
  if updated:
739
821
  try:
@@ -943,6 +1025,13 @@ class MCPConfigManager:
943
1025
  )
944
1026
 
945
1027
  if result.returncode == 0:
1028
+ # Inject any missing dependencies if needed
1029
+ if service_name in self.SERVICE_MISSING_DEPENDENCIES:
1030
+ self.logger.debug(
1031
+ f"Injecting missing dependencies for newly installed {service_name}..."
1032
+ )
1033
+ self._inject_missing_dependencies(service_name)
1034
+
946
1035
  # Verify installation worked
947
1036
  if self._verify_service_installed(service_name, "pipx"):
948
1037
  return True, "pipx"
@@ -1050,18 +1139,19 @@ class MCPConfigManager:
1050
1139
  Returns:
1051
1140
  Tuple of (success, message)
1052
1141
  """
1053
- self.logger.info("🔍 Checking MCP services for issues...")
1054
-
1055
1142
  services_to_fix = []
1056
1143
  fixed_services = []
1057
1144
  failed_services = []
1058
1145
 
1059
1146
  # Check each service for issues
1060
1147
  for service_name in self.PIPX_SERVICES:
1148
+ self.logger.info(f"🔍 Checking {service_name} for issues...")
1061
1149
  issue_type = self._detect_service_issue(service_name)
1062
1150
  if issue_type:
1063
1151
  services_to_fix.append((service_name, issue_type))
1064
- self.logger.debug(f"Found issue with {service_name}: {issue_type}")
1152
+ self.logger.info(f" ⚠️ Found issue with {service_name}: {issue_type}")
1153
+ else:
1154
+ self.logger.debug(f" ✅ {service_name} is functioning correctly")
1065
1155
 
1066
1156
  if not services_to_fix:
1067
1157
  return True, "All MCP services are functioning correctly"
@@ -1092,18 +1182,45 @@ class MCPConfigManager:
1092
1182
  failed_services.append(f"{service_name} (reinstall failed)")
1093
1183
 
1094
1184
  elif issue_type == "missing_dependency":
1095
- # Fix missing dependencies by automatically reinstalling
1185
+ # Fix missing dependencies - try injection first, then reinstall if needed
1186
+ self.logger.info(
1187
+ f" {service_name} has missing dependencies - attempting fix..."
1188
+ )
1189
+
1190
+ # First try to inject dependencies without reinstalling
1191
+ injection_success = self._inject_missing_dependencies(service_name)
1192
+
1193
+ if injection_success:
1194
+ # Verify the fix worked
1195
+ issue_after_injection = self._detect_service_issue(service_name)
1196
+ if issue_after_injection is None:
1197
+ fixed_services.append(f"{service_name} (dependencies injected)")
1198
+ self.logger.info(
1199
+ f" ✅ Fixed {service_name} with dependency injection"
1200
+ )
1201
+ continue # Move to next service
1202
+
1203
+ # If injection alone didn't work, try full reinstall
1096
1204
  self.logger.info(
1097
- f" {service_name} has missing dependencies - auto-reinstalling..."
1205
+ " Dependency injection insufficient, trying full reinstall..."
1098
1206
  )
1099
1207
  success = self._auto_reinstall_mcp_service(service_name)
1100
1208
  if success:
1101
- fixed_services.append(f"{service_name} (auto-reinstalled)")
1102
- else:
1103
- self.logger.warning(
1104
- f" Auto-reinstall failed for {service_name}. Manual fix: "
1105
- f"pipx uninstall {service_name} && pipx install {service_name}"
1209
+ fixed_services.append(
1210
+ f"{service_name} (auto-reinstalled with dependencies)"
1106
1211
  )
1212
+ else:
1213
+ # Provide specific manual fix for known services
1214
+ if service_name == "mcp-ticketer":
1215
+ self.logger.warning(
1216
+ f" Auto-fix failed for {service_name}. Manual fix: "
1217
+ f"pipx uninstall {service_name} && pipx install {service_name} && pipx inject {service_name} gql"
1218
+ )
1219
+ else:
1220
+ self.logger.warning(
1221
+ f" Auto-reinstall failed for {service_name}. Manual fix: "
1222
+ f"pipx uninstall {service_name} && pipx install {service_name}"
1223
+ )
1107
1224
  failed_services.append(f"{service_name} (auto-reinstall failed)")
1108
1225
 
1109
1226
  elif issue_type == "path_issue":
@@ -1129,7 +1246,16 @@ class MCPConfigManager:
1129
1246
  message += "\n\n💡 Manual fix instructions:"
1130
1247
  for failed in failed_services:
1131
1248
  service = failed.split(" ")[0]
1132
- message += f"\n • {service}: pipx uninstall {service} && pipx install {service}"
1249
+ if service in self.SERVICE_MISSING_DEPENDENCIES:
1250
+ deps = " ".join(
1251
+ [
1252
+ f"&& pipx inject {service} {dep}"
1253
+ for dep in self.SERVICE_MISSING_DEPENDENCIES[service]
1254
+ ]
1255
+ )
1256
+ message += f"\n • {service}: pipx uninstall {service} && pipx install {service} {deps}"
1257
+ else:
1258
+ message += f"\n • {service}: pipx uninstall {service} && pipx install {service}"
1133
1259
 
1134
1260
  return success, message
1135
1261
 
@@ -1148,7 +1274,66 @@ class MCPConfigManager:
1148
1274
 
1149
1275
  # Try to run the service with --help to detect issues
1150
1276
  try:
1151
- # Test with pipx run
1277
+ # First check if service is installed in pipx venv
1278
+ pipx_venv_bin = self.pipx_base / service_name / "bin" / service_name
1279
+ if pipx_venv_bin.exists():
1280
+ # Test the installed version directly (has injected dependencies)
1281
+ # This avoids using pipx run which downloads a fresh cache copy without dependencies
1282
+ self.logger.debug(
1283
+ f" Testing {service_name} from installed pipx venv: {pipx_venv_bin}"
1284
+ )
1285
+ result = subprocess.run(
1286
+ [str(pipx_venv_bin), "--help"],
1287
+ capture_output=True,
1288
+ text=True,
1289
+ timeout=10,
1290
+ check=False,
1291
+ )
1292
+
1293
+ # Check for specific error patterns in installed version
1294
+ stderr_lower = result.stderr.lower()
1295
+ stdout_lower = result.stdout.lower()
1296
+ combined_output = stderr_lower + stdout_lower
1297
+
1298
+ # Import errors in installed version (should be rare if dependencies injected)
1299
+ if (
1300
+ "modulenotfounderror" in combined_output
1301
+ or "importerror" in combined_output
1302
+ ):
1303
+ # Check if it's specifically the gql dependency for mcp-ticketer
1304
+ if service_name == "mcp-ticketer" and "gql" in combined_output:
1305
+ return "missing_dependency"
1306
+ return "import_error"
1307
+
1308
+ # Path issues
1309
+ if "no such file or directory" in combined_output:
1310
+ return "path_issue"
1311
+
1312
+ # If help text appears, service is working
1313
+ if (
1314
+ "usage:" in combined_output
1315
+ or "help" in combined_output
1316
+ or result.returncode in [0, 1]
1317
+ ):
1318
+ self.logger.debug(
1319
+ f" {service_name} is working correctly (installed in venv)"
1320
+ )
1321
+ return None # Service is working
1322
+
1323
+ # Unknown issue
1324
+ if result.returncode not in [0, 1]:
1325
+ self.logger.debug(
1326
+ f"{service_name} returned unexpected exit code: {result.returncode}"
1327
+ )
1328
+ return "unknown_error"
1329
+
1330
+ return None # Default to working if no issues detected
1331
+
1332
+ # Service not installed in pipx venv - use pipx run for detection
1333
+ # Note: pipx run uses cache which may not have injected dependencies
1334
+ self.logger.debug(
1335
+ f" Testing {service_name} via pipx run (not installed in venv)"
1336
+ )
1152
1337
  result = subprocess.run(
1153
1338
  ["pipx", "run", service_name, "--help"],
1154
1339
  capture_output=True,
@@ -1169,15 +1354,17 @@ class MCPConfigManager:
1169
1354
  ):
1170
1355
  return "not_installed"
1171
1356
 
1172
- # Import errors (like mcp-ticketer's corrupted state)
1357
+ # Import errors when using pipx run (cache version)
1173
1358
  if (
1174
1359
  "modulenotfounderror" in combined_output
1175
1360
  or "importerror" in combined_output
1176
1361
  ):
1177
- # Check if it's specifically the gql dependency for mcp-ticketer
1178
- if service_name == "mcp-ticketer" and "gql" in combined_output:
1179
- return "missing_dependency"
1180
- return "import_error"
1362
+ # Don't report missing_dependency for cache version - it may be missing injected deps
1363
+ # Just report that service needs to be installed properly
1364
+ self.logger.debug(
1365
+ f"{service_name} has import errors in pipx run cache - needs proper installation"
1366
+ )
1367
+ return "not_installed"
1181
1368
 
1182
1369
  # Path issues
1183
1370
  if "no such file or directory" in combined_output:
@@ -1240,6 +1427,13 @@ class MCPConfigManager:
1240
1427
  )
1241
1428
 
1242
1429
  if install_result.returncode == 0:
1430
+ # Inject any missing dependencies if needed
1431
+ if service_name in self.SERVICE_MISSING_DEPENDENCIES:
1432
+ self.logger.debug(
1433
+ f"Injecting missing dependencies for {service_name}..."
1434
+ )
1435
+ self._inject_missing_dependencies(service_name)
1436
+
1243
1437
  # Verify the reinstall worked
1244
1438
  issue = self._detect_service_issue(service_name)
1245
1439
  if issue is None:
@@ -1258,6 +1452,66 @@ class MCPConfigManager:
1258
1452
  self.logger.error(f"Error reinstalling {service_name}: {e}")
1259
1453
  return False
1260
1454
 
1455
+ def _inject_missing_dependencies(self, service_name: str) -> bool:
1456
+ """
1457
+ Inject missing dependencies into a pipx-installed MCP service.
1458
+
1459
+ Some MCP services don't properly declare all their dependencies in their
1460
+ package metadata, which causes import errors when pipx creates isolated
1461
+ virtual environments. This method injects the missing dependencies using
1462
+ pipx inject.
1463
+
1464
+ Args:
1465
+ service_name: Name of the MCP service to fix
1466
+
1467
+ Returns:
1468
+ True if dependencies were injected successfully or no injection needed, False otherwise
1469
+ """
1470
+ # Check if this service has known missing dependencies
1471
+ if service_name not in self.SERVICE_MISSING_DEPENDENCIES:
1472
+ return True # No dependencies to inject
1473
+
1474
+ missing_deps = self.SERVICE_MISSING_DEPENDENCIES[service_name]
1475
+ if not missing_deps:
1476
+ return True # No dependencies to inject
1477
+
1478
+ self.logger.info(
1479
+ f" → Injecting missing dependencies for {service_name}: {', '.join(missing_deps)}"
1480
+ )
1481
+
1482
+ all_successful = True
1483
+ for dep in missing_deps:
1484
+ try:
1485
+ self.logger.debug(f" Injecting {dep} into {service_name}...")
1486
+ result = subprocess.run(
1487
+ ["pipx", "inject", service_name, dep],
1488
+ capture_output=True,
1489
+ text=True,
1490
+ timeout=60,
1491
+ check=False,
1492
+ )
1493
+
1494
+ if result.returncode == 0:
1495
+ self.logger.info(f" ✅ Successfully injected {dep}")
1496
+ # Check if already injected (pipx will complain if package already exists)
1497
+ elif (
1498
+ "already satisfied" in result.stderr.lower()
1499
+ or "already installed" in result.stderr.lower()
1500
+ ):
1501
+ self.logger.debug(f" {dep} already present in {service_name}")
1502
+ else:
1503
+ self.logger.error(f" Failed to inject {dep}: {result.stderr}")
1504
+ all_successful = False
1505
+
1506
+ except subprocess.TimeoutExpired:
1507
+ self.logger.error(f" Timeout while injecting {dep}")
1508
+ all_successful = False
1509
+ except Exception as e:
1510
+ self.logger.error(f" Error injecting {dep}: {e}")
1511
+ all_successful = False
1512
+
1513
+ return all_successful
1514
+
1261
1515
  def _auto_reinstall_mcp_service(self, service_name: str) -> bool:
1262
1516
  """
1263
1517
  Automatically reinstall an MCP service with missing dependencies.
@@ -1312,6 +1566,16 @@ class MCPConfigManager:
1312
1566
  )
1313
1567
  return False
1314
1568
 
1569
+ # Inject any missing dependencies that pipx doesn't handle automatically
1570
+ if service_name in self.SERVICE_MISSING_DEPENDENCIES:
1571
+ self.logger.info(
1572
+ f" → Fixing missing dependencies for {service_name}..."
1573
+ )
1574
+ if not self._inject_missing_dependencies(service_name):
1575
+ self.logger.warning(
1576
+ f"Failed to inject all dependencies for {service_name}, but continuing..."
1577
+ )
1578
+
1315
1579
  # Verify the reinstall worked
1316
1580
  self.logger.info(f" → Verifying {service_name} installation...")
1317
1581
  issue = self._detect_service_issue(service_name)
@@ -1319,9 +1583,17 @@ class MCPConfigManager:
1319
1583
  if issue is None:
1320
1584
  self.logger.info(f" ✅ Successfully reinstalled {service_name}")
1321
1585
  return True
1322
- self.logger.warning(
1323
- f"Reinstalled {service_name} but still has issue: {issue}"
1324
- )
1586
+
1587
+ # If still has missing dependency issue after injection, log specific instructions
1588
+ if issue == "missing_dependency" and service_name == "mcp-ticketer":
1589
+ self.logger.error(
1590
+ f" {service_name} still has missing dependencies after injection. "
1591
+ f"Manual fix: pipx inject {service_name} gql"
1592
+ )
1593
+ else:
1594
+ self.logger.warning(
1595
+ f"Reinstalled {service_name} but still has issue: {issue}"
1596
+ )
1325
1597
  return False
1326
1598
 
1327
1599
  except subprocess.TimeoutExpired:
@@ -1439,3 +1711,21 @@ class MCPConfigManager:
1439
1711
 
1440
1712
  # For other services, try pipx run
1441
1713
  return None
1714
+
1715
+ def get_filtered_services(self) -> Dict[str, Dict]:
1716
+ """Get all MCP service configurations filtered by startup configuration.
1717
+
1718
+ Returns:
1719
+ Dictionary of service configurations, filtered based on startup settings
1720
+ """
1721
+ filtered_services = {}
1722
+
1723
+ for service_name in self.STATIC_MCP_CONFIGS:
1724
+ if self.should_enable_service(service_name):
1725
+ # Get the actual service configuration with proper paths
1726
+ service_config = self.get_static_service_config(service_name)
1727
+ if service_config:
1728
+ filtered_services[service_name] = service_config
1729
+ # Removed noisy debug logging that was called multiple times per startup
1730
+
1731
+ return filtered_services