hanzo-mcp 0.6.12__py3-none-any.whl → 0.6.13__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.

Potentially problematic release.


This version of hanzo-mcp might be problematic. Click here for more details.

Files changed (77) hide show
  1. hanzo_mcp/__init__.py +2 -2
  2. hanzo_mcp/cli.py +2 -2
  3. hanzo_mcp/cli_enhanced.py +4 -4
  4. hanzo_mcp/cli_plugin.py +91 -0
  5. hanzo_mcp/config/__init__.py +1 -1
  6. hanzo_mcp/config/settings.py +69 -6
  7. hanzo_mcp/config/tool_config.py +2 -2
  8. hanzo_mcp/dev_server.py +3 -3
  9. hanzo_mcp/prompts/project_system.py +1 -1
  10. hanzo_mcp/server.py +6 -2
  11. hanzo_mcp/server_enhanced.py +69 -0
  12. hanzo_mcp/tools/__init__.py +75 -29
  13. hanzo_mcp/tools/agent/__init__.py +1 -1
  14. hanzo_mcp/tools/agent/agent_tool.py +2 -2
  15. hanzo_mcp/tools/common/__init__.py +15 -1
  16. hanzo_mcp/tools/common/base.py +4 -4
  17. hanzo_mcp/tools/common/batch_tool.py +1 -1
  18. hanzo_mcp/tools/common/config_tool.py +2 -2
  19. hanzo_mcp/tools/common/context.py +2 -2
  20. hanzo_mcp/tools/common/context_fix.py +26 -0
  21. hanzo_mcp/tools/common/critic_tool.py +196 -0
  22. hanzo_mcp/tools/common/decorators.py +208 -0
  23. hanzo_mcp/tools/common/enhanced_base.py +106 -0
  24. hanzo_mcp/tools/common/mode.py +116 -0
  25. hanzo_mcp/tools/common/mode_loader.py +105 -0
  26. hanzo_mcp/tools/common/permissions.py +1 -1
  27. hanzo_mcp/tools/common/personality.py +936 -0
  28. hanzo_mcp/tools/common/plugin_loader.py +287 -0
  29. hanzo_mcp/tools/common/stats.py +4 -4
  30. hanzo_mcp/tools/common/tool_list.py +1 -1
  31. hanzo_mcp/tools/common/validation.py +1 -1
  32. hanzo_mcp/tools/config/__init__.py +3 -1
  33. hanzo_mcp/tools/config/config_tool.py +1 -1
  34. hanzo_mcp/tools/config/mode_tool.py +209 -0
  35. hanzo_mcp/tools/database/__init__.py +1 -1
  36. hanzo_mcp/tools/editor/__init__.py +1 -1
  37. hanzo_mcp/tools/filesystem/__init__.py +19 -14
  38. hanzo_mcp/tools/filesystem/batch_search.py +3 -3
  39. hanzo_mcp/tools/filesystem/diff.py +2 -2
  40. hanzo_mcp/tools/filesystem/rules_tool.py +235 -0
  41. hanzo_mcp/tools/filesystem/{unified_search.py → search_tool.py} +12 -12
  42. hanzo_mcp/tools/filesystem/{symbols_unified.py → symbols_tool.py} +104 -5
  43. hanzo_mcp/tools/filesystem/watch.py +3 -2
  44. hanzo_mcp/tools/jupyter/__init__.py +2 -2
  45. hanzo_mcp/tools/jupyter/jupyter.py +1 -1
  46. hanzo_mcp/tools/llm/__init__.py +3 -3
  47. hanzo_mcp/tools/llm/llm_tool.py +648 -143
  48. hanzo_mcp/tools/mcp/__init__.py +2 -2
  49. hanzo_mcp/tools/mcp/{mcp_unified.py → mcp_tool.py} +3 -3
  50. hanzo_mcp/tools/shell/__init__.py +6 -6
  51. hanzo_mcp/tools/shell/base_process.py +4 -2
  52. hanzo_mcp/tools/shell/bash_session_executor.py +1 -1
  53. hanzo_mcp/tools/shell/{bash_unified.py → bash_tool.py} +1 -1
  54. hanzo_mcp/tools/shell/command_executor.py +2 -2
  55. hanzo_mcp/tools/shell/{npx_unified.py → npx_tool.py} +1 -1
  56. hanzo_mcp/tools/shell/open.py +2 -2
  57. hanzo_mcp/tools/shell/{process_unified.py → process_tool.py} +1 -1
  58. hanzo_mcp/tools/shell/run_command_windows.py +1 -1
  59. hanzo_mcp/tools/shell/uvx.py +47 -2
  60. hanzo_mcp/tools/shell/uvx_background.py +47 -2
  61. hanzo_mcp/tools/shell/{uvx_unified.py → uvx_tool.py} +1 -1
  62. hanzo_mcp/tools/todo/__init__.py +14 -19
  63. hanzo_mcp/tools/todo/todo.py +22 -1
  64. hanzo_mcp/tools/vector/__init__.py +1 -1
  65. hanzo_mcp/tools/vector/infinity_store.py +2 -2
  66. hanzo_mcp/tools/vector/project_manager.py +1 -1
  67. hanzo_mcp-0.6.13.dist-info/METADATA +359 -0
  68. {hanzo_mcp-0.6.12.dist-info → hanzo_mcp-0.6.13.dist-info}/RECORD +72 -64
  69. {hanzo_mcp-0.6.12.dist-info → hanzo_mcp-0.6.13.dist-info}/entry_points.txt +1 -0
  70. hanzo_mcp/tools/common/palette.py +0 -344
  71. hanzo_mcp/tools/common/palette_loader.py +0 -108
  72. hanzo_mcp/tools/config/palette_tool.py +0 -179
  73. hanzo_mcp/tools/llm/llm_unified.py +0 -851
  74. hanzo_mcp-0.6.12.dist-info/METADATA +0 -339
  75. {hanzo_mcp-0.6.12.dist-info → hanzo_mcp-0.6.13.dist-info}/WHEEL +0 -0
  76. {hanzo_mcp-0.6.12.dist-info → hanzo_mcp-0.6.13.dist-info}/licenses/LICENSE +0 -0
  77. {hanzo_mcp-0.6.12.dist-info → hanzo_mcp-0.6.13.dist-info}/top_level.txt +0 -0
hanzo_mcp/__init__.py CHANGED
@@ -1,4 +1,4 @@
1
- """Hanzo MCP - Implementation of Hanzo capabilities using MCP."""
1
+ """Hanzo AI - Implementation of Hanzo capabilities using MCP."""
2
2
 
3
3
  # Configure FastMCP logging globally for stdio transport
4
4
  import os
@@ -9,4 +9,4 @@ if os.environ.get("HANZO_MCP_TRANSPORT") == "stdio":
9
9
  except ImportError:
10
10
  pass
11
11
 
12
- __version__ = "0.6.12"
12
+ __version__ = "0.6.13"
hanzo_mcp/cli.py CHANGED
@@ -1,4 +1,4 @@
1
- """Command-line interface for the Hanzo MCP server."""
1
+ """Command-line interface for the Hanzo AI server."""
2
2
 
3
3
  import argparse
4
4
  import json
@@ -13,7 +13,7 @@ from hanzo_mcp.server import HanzoMCPServer
13
13
 
14
14
 
15
15
  def main() -> None:
16
- """Run the CLI for the Hanzo MCP server."""
16
+ """Run the CLI for the Hanzo AI server."""
17
17
 
18
18
  # Pre-parse arguments to check transport type early
19
19
  import sys
hanzo_mcp/cli_enhanced.py CHANGED
@@ -1,4 +1,4 @@
1
- """Enhanced command-line interface for the Hanzo MCP server with full tool configuration."""
1
+ """Enhanced command-line interface for the Hanzo AI server with full tool configuration."""
2
2
 
3
3
  import argparse
4
4
  import json
@@ -15,7 +15,7 @@ from hanzo_mcp.server import HanzoMCPServer
15
15
  def create_parser() -> argparse.ArgumentParser:
16
16
  """Create the argument parser with all tool configuration options."""
17
17
  parser = argparse.ArgumentParser(
18
- description="Hanzo MCP server with comprehensive tool configuration",
18
+ description="Hanzo AI server with comprehensive tool configuration",
19
19
  formatter_class=argparse.RawDescriptionHelpFormatter,
20
20
  epilog="""
21
21
  Tool Configuration:
@@ -346,7 +346,7 @@ def apply_cli_overrides(args: argparse.Namespace) -> Dict[str, Any]:
346
346
  def list_tools(settings: HanzoMCPSettings) -> None:
347
347
  """List all tools and their current status."""
348
348
  logger = logging.getLogger(__name__)
349
- logger.info("Hanzo MCP Tools Status:")
349
+ logger.info("Hanzo AI Tools Status:")
350
350
  logger.info("=" * 50)
351
351
 
352
352
  categories = {}
@@ -371,7 +371,7 @@ def list_tools(settings: HanzoMCPSettings) -> None:
371
371
 
372
372
 
373
373
  def main() -> None:
374
- """Run the enhanced CLI for the Hanzo MCP server."""
374
+ """Run the enhanced CLI for the Hanzo AI server."""
375
375
  parser = create_parser()
376
376
  args = parser.parse_args()
377
377
 
@@ -0,0 +1,91 @@
1
+ #!/usr/bin/env python3
2
+ """CLI for managing Hanzo MCP plugins."""
3
+
4
+ import argparse
5
+ import sys
6
+ from pathlib import Path
7
+
8
+ from hanzo_mcp.tools.common.plugin_loader import create_plugin_template, list_plugin_tools
9
+
10
+
11
+ def main():
12
+ """Main CLI entry point."""
13
+ parser = argparse.ArgumentParser(
14
+ description="Hanzo MCP Plugin Manager",
15
+ formatter_class=argparse.RawDescriptionHelpFormatter,
16
+ epilog="""
17
+ Examples:
18
+ # Create a new plugin template
19
+ hanzo-plugin create mytool
20
+
21
+ # List installed plugins
22
+ hanzo-plugin list
23
+
24
+ # Create plugin in specific directory
25
+ hanzo-plugin create mytool --output /path/to/plugins
26
+ """
27
+ )
28
+
29
+ subparsers = parser.add_subparsers(dest="command", help="Command to run")
30
+
31
+ # Create command
32
+ create_parser = subparsers.add_parser("create", help="Create a new plugin template")
33
+ create_parser.add_argument("name", help="Name of the tool (e.g., 'mytool')")
34
+ create_parser.add_argument(
35
+ "--output", "-o",
36
+ type=Path,
37
+ default=Path.home() / ".hanzo" / "plugins",
38
+ help="Output directory for the plugin (default: ~/.hanzo/plugins)"
39
+ )
40
+
41
+ # List command
42
+ list_parser = subparsers.add_parser("list", help="List installed plugins")
43
+
44
+ args = parser.parse_args()
45
+
46
+ if args.command == "create":
47
+ # Create plugin template
48
+ output_dir = args.output / args.name
49
+ try:
50
+ create_plugin_template(output_dir, args.name)
51
+ print(f"\n✅ Plugin template created successfully!")
52
+ print(f"\nTo use your plugin:")
53
+ print(f"1. Edit the tool implementation in {output_dir / f'{args.name}_tool.py'}")
54
+ print(f"2. Restart Hanzo MCP to load the plugin")
55
+ print(f"3. Add '{args.name}' to your mode's tool list")
56
+ except Exception as e:
57
+ print(f"❌ Error creating plugin: {e}", file=sys.stderr)
58
+ sys.exit(1)
59
+
60
+ elif args.command == "list":
61
+ # List installed plugins
62
+ try:
63
+ from hanzo_mcp.tools.common.plugin_loader import load_user_plugins
64
+ plugins = load_user_plugins()
65
+
66
+ if not plugins:
67
+ print("No plugins installed.")
68
+ print("\nPlugin directories:")
69
+ print(" ~/.hanzo/plugins/")
70
+ print(" ./.hanzo/plugins/")
71
+ print(" $HANZO_PLUGIN_PATH")
72
+ else:
73
+ print(f"Installed plugins ({len(plugins)}):")
74
+ for name, plugin in plugins.items():
75
+ print(f"\n {name}:")
76
+ print(f" Source: {plugin.source_path}")
77
+ if plugin.metadata:
78
+ print(f" Version: {plugin.metadata.get('version', 'unknown')}")
79
+ print(f" Author: {plugin.metadata.get('author', 'unknown')}")
80
+ print(f" Description: {plugin.metadata.get('description', '')}")
81
+ except Exception as e:
82
+ print(f"❌ Error listing plugins: {e}", file=sys.stderr)
83
+ sys.exit(1)
84
+
85
+ else:
86
+ parser.print_help()
87
+ sys.exit(1)
88
+
89
+
90
+ if __name__ == "__main__":
91
+ main()
@@ -1,4 +1,4 @@
1
- """Configuration management for Hanzo MCP.
1
+ """Configuration management for Hanzo AI.
2
2
 
3
3
  This module provides a comprehensive configuration system that supports:
4
4
  - CLI arguments for individual tool control
@@ -1,4 +1,4 @@
1
- """Settings management for Hanzo MCP.
1
+ """Settings management for Hanzo AI.
2
2
 
3
3
  Handles loading and saving configuration from multiple sources:
4
4
  1. Default settings
@@ -59,6 +59,7 @@ class AgentConfig:
59
59
  enabled: bool = False
60
60
  model: Optional[str] = None
61
61
  api_key: Optional[str] = None
62
+ hanzo_api_key: Optional[str] = None # HANZO_API_KEY support
62
63
  base_url: Optional[str] = None
63
64
  max_tokens: Optional[int] = None
64
65
  max_iterations: int = 10
@@ -78,7 +79,7 @@ class ServerConfig:
78
79
 
79
80
  @dataclass
80
81
  class HanzoMCPSettings:
81
- """Complete configuration for Hanzo MCP."""
82
+ """Complete configuration for Hanzo AI."""
82
83
  # Server settings
83
84
  server: ServerConfig = field(default_factory=ServerConfig)
84
85
 
@@ -106,6 +107,9 @@ class HanzoMCPSettings:
106
107
  projects: Dict[str, ProjectConfig] = field(default_factory=dict)
107
108
  current_project: Optional[str] = None
108
109
 
110
+ # Mode configuration
111
+ active_mode: Optional[str] = None
112
+
109
113
  def __post_init__(self):
110
114
  """Initialize default tool states if not specified."""
111
115
  if not self.enabled_tools:
@@ -250,7 +254,7 @@ class HanzoMCPSettings:
250
254
 
251
255
 
252
256
  def get_config_dir() -> Path:
253
- """Get the configuration directory for Hanzo MCP."""
257
+ """Get the configuration directory for Hanzo AI."""
254
258
  if os.name == "nt": # Windows
255
259
  config_dir = Path(os.environ.get("APPDATA", "")) / "hanzo"
256
260
  else: # Unix/macOS
@@ -341,6 +345,59 @@ def detect_project_from_path(file_path: str) -> Optional[Dict[str, str]]:
341
345
  return None
342
346
 
343
347
 
348
+ def _load_from_env() -> Dict[str, Any]:
349
+ """Load configuration from environment variables."""
350
+ config = {}
351
+
352
+ # Check for agent API keys
353
+ has_api_keys = False
354
+
355
+ # HANZO_API_KEY
356
+ if hanzo_key := os.environ.get("HANZO_API_KEY"):
357
+ config.setdefault("agent", {})["hanzo_api_key"] = hanzo_key
358
+ config["agent"]["enabled"] = True
359
+ has_api_keys = True
360
+
361
+ # Check for other API keys
362
+ api_key_env_vars = [
363
+ ("OPENAI_API_KEY", "openai"),
364
+ ("ANTHROPIC_API_KEY", "anthropic"),
365
+ ("GOOGLE_API_KEY", "google"),
366
+ ("GROQ_API_KEY", "groq"),
367
+ ("TOGETHER_API_KEY", "together"),
368
+ ("MISTRAL_API_KEY", "mistral"),
369
+ ("PERPLEXITY_API_KEY", "perplexity"),
370
+ ]
371
+
372
+ for env_var, provider in api_key_env_vars:
373
+ if os.environ.get(env_var):
374
+ has_api_keys = True
375
+ break
376
+
377
+ # Auto-enable agent and consensus tools if API keys present
378
+ if has_api_keys:
379
+ config.setdefault("enabled_tools", {})
380
+ config["enabled_tools"]["agent"] = True
381
+ config["enabled_tools"]["consensus"] = True
382
+ config.setdefault("agent", {})["enabled"] = True
383
+
384
+ # Check for MODE/PERSONALITY/HANZO_MODE
385
+ if mode := os.environ.get("HANZO_MODE") or os.environ.get("PERSONALITY") or os.environ.get("MODE"):
386
+ config["active_mode"] = mode
387
+
388
+ # Check for other environment overrides
389
+ if project_dir := os.environ.get("HANZO_PROJECT_DIR"):
390
+ config["project_dir"] = project_dir
391
+
392
+ if log_level := os.environ.get("HANZO_LOG_LEVEL"):
393
+ config.setdefault("server", {})["log_level"] = log_level
394
+
395
+ if allowed_paths := os.environ.get("HANZO_ALLOWED_PATHS"):
396
+ config["allowed_paths"] = allowed_paths.split(":")
397
+
398
+ return config
399
+
400
+
344
401
  def load_settings(
345
402
  project_dir: Optional[str] = None,
346
403
  config_overrides: Optional[Dict[str, Any]] = None
@@ -349,9 +406,10 @@ def load_settings(
349
406
 
350
407
  Priority (highest to lowest):
351
408
  1. config_overrides (usually from CLI)
352
- 2. Project-specific config file
353
- 3. Global config file
354
- 4. Defaults
409
+ 2. Environment variables
410
+ 3. Project-specific config file
411
+ 4. Global config file
412
+ 5. Defaults
355
413
  """
356
414
  # Start with defaults
357
415
  settings = HanzoMCPSettings()
@@ -380,6 +438,11 @@ def load_settings(
380
438
  logger = logging.getLogger(__name__)
381
439
  logger.warning(f"Failed to load project config: {e}")
382
440
 
441
+ # Apply environment variables
442
+ env_config = _load_from_env()
443
+ if env_config:
444
+ settings = _merge_config(settings, env_config)
445
+
383
446
  # Apply CLI overrides
384
447
  if config_overrides:
385
448
  settings = _merge_config(settings, config_overrides)
@@ -1,4 +1,4 @@
1
- """Tool configuration definitions for Hanzo MCP."""
1
+ """Tool configuration definitions for Hanzo AI."""
2
2
 
3
3
  from enum import Enum
4
4
  from typing import Dict, List, Optional
@@ -6,7 +6,7 @@ from dataclasses import dataclass
6
6
 
7
7
 
8
8
  class ToolCategory(str, Enum):
9
- """Categories of tools available in Hanzo MCP."""
9
+ """Categories of tools available in Hanzo AI."""
10
10
  FILESYSTEM = "filesystem"
11
11
  SHELL = "shell"
12
12
  JUPYTER = "jupyter"
hanzo_mcp/dev_server.py CHANGED
@@ -1,4 +1,4 @@
1
- """Development server with hot reload for Hanzo MCP."""
1
+ """Development server with hot reload for Hanzo AI."""
2
2
 
3
3
  import asyncio
4
4
  import logging
@@ -159,7 +159,7 @@ class DevServer:
159
159
  self.running = True
160
160
 
161
161
  logger = logging.getLogger(__name__)
162
- logger.info(f"\n🚀 Starting Hanzo MCP in development mode...")
162
+ logger.info(f"\n🚀 Starting Hanzo AI in development mode...")
163
163
  logger.info(f"🔧 Hot reload enabled - watching for file changes")
164
164
  logger.info(f"📁 Project: {self.project_dir or 'current directory'}")
165
165
  logger.info(f"🌐 Transport: {transport}\n")
@@ -194,7 +194,7 @@ def run_dev_server():
194
194
  """Entry point for development server."""
195
195
  import argparse
196
196
 
197
- parser = argparse.ArgumentParser(description="Run Hanzo MCP in development mode with hot reload")
197
+ parser = argparse.ArgumentParser(description="Run Hanzo AI in development mode with hot reload")
198
198
  parser.add_argument(
199
199
  "--name",
200
200
  type=str,
@@ -30,7 +30,7 @@ Recent commits:
30
30
  </project_info>
31
31
 
32
32
  <available_tools>
33
- Hanzo MCP provides 65+ tools organized by category. Key tools include:
33
+ Hanzo AI provides 65+ tools organized by category. Key tools include:
34
34
 
35
35
  # File Operations
36
36
  - read, write, edit, multi_edit: File manipulation
hanzo_mcp/server.py CHANGED
@@ -16,6 +16,9 @@ except ImportError:
16
16
  # Fallback for older MCP versions
17
17
  from mcp.server import FastMCP
18
18
 
19
+ # Import our enhanced server
20
+ from hanzo_mcp.server_enhanced import EnhancedFastMCP
21
+
19
22
  from hanzo_mcp.prompts import register_all_prompts
20
23
  from hanzo_mcp.tools import register_all_tools
21
24
 
@@ -49,7 +52,7 @@ class HanzoMCPServer:
49
52
  enabled_tools: dict[str, bool] | None = None,
50
53
  disabled_tools: list[str] | None = None,
51
54
  ):
52
- """Initialize the Hanzo MCP server.
55
+ """Initialize the Hanzo AI server.
53
56
 
54
57
  Args:
55
58
  name: The name of the server
@@ -72,7 +75,8 @@ class HanzoMCPServer:
72
75
  enabled_tools: Dictionary of individual tool enable states (default: None)
73
76
  disabled_tools: List of tool names to disable (default: None)
74
77
  """
75
- self.mcp = mcp_instance if mcp_instance is not None else FastMCP(name)
78
+ # Use enhanced server for automatic context normalization
79
+ self.mcp = mcp_instance if mcp_instance is not None else EnhancedFastMCP(name)
76
80
 
77
81
  # Initialize permissions and command executor
78
82
  self.permission_manager = PermissionManager()
@@ -0,0 +1,69 @@
1
+ """Enhanced MCP server with automatic context normalization.
2
+
3
+ This module provides an enhanced FastMCP server that automatically
4
+ applies context normalization to all registered tools.
5
+ """
6
+
7
+ from typing import Any, Callable
8
+ from functools import wraps
9
+
10
+ from mcp.server import FastMCP
11
+
12
+ from hanzo_mcp.tools.common.decorators import with_context_normalization
13
+
14
+
15
+ class EnhancedFastMCP(FastMCP):
16
+ """Enhanced FastMCP server with automatic context normalization.
17
+
18
+ This server automatically wraps all tool registrations with context
19
+ normalization, ensuring that tools work properly when called externally
20
+ with serialized context parameters.
21
+ """
22
+
23
+ def tool(
24
+ self,
25
+ name: str | None = None,
26
+ description: str | None = None
27
+ ) -> Callable:
28
+ """Enhanced tool decorator that includes automatic context normalization.
29
+
30
+ Args:
31
+ name: Tool name (defaults to function name)
32
+ description: Tool description
33
+
34
+ Returns:
35
+ Decorator function that registers the tool with context normalization
36
+ """
37
+ # Get the original decorator from parent class
38
+ original_decorator = super().tool(
39
+ name=name,
40
+ description=description
41
+ )
42
+
43
+ # Create our enhanced decorator
44
+ def enhanced_decorator(func: Callable) -> Callable:
45
+ # Apply context normalization first
46
+ # Check if function has ctx parameter
47
+ import inspect
48
+ sig = inspect.signature(func)
49
+ if 'ctx' in sig.parameters:
50
+ normalized_func = with_context_normalization(func)
51
+ else:
52
+ normalized_func = func
53
+
54
+ # Then apply the original decorator
55
+ return original_decorator(normalized_func)
56
+
57
+ return enhanced_decorator
58
+
59
+
60
+ def create_enhanced_server(name: str = "hanzo") -> EnhancedFastMCP:
61
+ """Create an enhanced MCP server with automatic context normalization.
62
+
63
+ Args:
64
+ name: Server name
65
+
66
+ Returns:
67
+ Enhanced FastMCP server instance
68
+ """
69
+ return EnhancedFastMCP(name)
@@ -1,7 +1,7 @@
1
- """Tools package for Hanzo MCP.
1
+ """Tools package for Hanzo AI.
2
2
 
3
- This package contains all the tools for the Hanzo MCP server.
4
- It provides a unified interface for registering all tools with an MCP server.
3
+ This package contains all the tools for the Hanzo AI server.
4
+ It provides a interface for registering all tools with an MCP server.
5
5
 
6
6
  This includes a "think" tool implementation based on Anthropic's research showing
7
7
  improved performance for complex tool-based interactions when Claude has a dedicated
@@ -12,7 +12,7 @@ to delegate tasks to sub-agents for concurrent execution and specialized process
12
12
  from mcp.server import FastMCP
13
13
 
14
14
  from hanzo_mcp.tools.agent import register_agent_tools
15
- from hanzo_mcp.tools.common import register_batch_tool, register_thinking_tool
15
+ from hanzo_mcp.tools.common import register_batch_tool, register_thinking_tool, register_critic_tool
16
16
  from hanzo_mcp.tools.common.base import BaseTool
17
17
  from hanzo_mcp.tools.common.permissions import PermissionManager
18
18
  from hanzo_mcp.tools.common.tool_enable import ToolEnableTool
@@ -25,11 +25,13 @@ from hanzo_mcp.tools.shell import register_shell_tools
25
25
  from hanzo_mcp.tools.todo import register_todo_tools
26
26
  from hanzo_mcp.tools.vector import register_vector_tools
27
27
  from hanzo_mcp.tools.database import register_database_tools, DatabaseManager
28
- from hanzo_mcp.tools.mcp import UnifiedMCPTool, McpAddTool, McpRemoveTool, McpStatsTool
28
+ from hanzo_mcp.tools.mcp import MCPTool, McpAddTool, McpRemoveTool, McpStatsTool
29
29
  from hanzo_mcp.tools.editor import NeovimEditTool, NeovimCommandTool, NeovimSessionTool
30
- from hanzo_mcp.tools.llm import UnifiedLLMTool, LLMTool, ConsensusTool, LLMManageTool, create_provider_tools
31
- from hanzo_mcp.tools.config.palette_tool import palette_tool
32
- from hanzo_mcp.tools.common.palette_loader import PaletteLoader
30
+ from hanzo_mcp.tools.llm import LLMTool, LLMTool, ConsensusTool, LLMManageTool, create_provider_tools
31
+ from hanzo_mcp.tools.config.mode_tool import mode_tool
32
+ from hanzo_mcp.tools.common.mode_loader import ModeLoader
33
+ from hanzo_mcp.tools.common.mode import activate_mode_from_env
34
+ from hanzo_mcp.tools.common.plugin_loader import load_user_plugins
33
35
 
34
36
 
35
37
  def register_all_tools(
@@ -46,8 +48,8 @@ def register_all_tools(
46
48
  disable_search_tools: bool = False,
47
49
  enabled_tools: dict[str, bool] | None = None,
48
50
  vector_config: dict | None = None,
49
- use_palette: bool = True,
50
- force_palette: str | None = None,
51
+ use_mode: bool = True,
52
+ force_mode: str | None = None,
51
53
  ) -> None:
52
54
  """Register all Hanzo tools with the MCP server.
53
55
 
@@ -65,20 +67,36 @@ def register_all_tools(
65
67
  disable_search_tools: Whether to disable search tools (default: False)
66
68
  enabled_tools: Dictionary of individual tool enable/disable states (default: None)
67
69
  vector_config: Vector store configuration (default: None)
68
- use_palette: Whether to use palette system for tool configuration (default: True)
69
- force_palette: Force a specific palette to be active (default: None)
70
+ use_mode: Whether to use mode system for tool configuration (default: True)
71
+ force_mode: Force a specific mode to be active (default: None)
70
72
  """
71
73
  # Dictionary to store all registered tools
72
74
  all_tools: dict[str, BaseTool] = {}
73
75
 
74
- # Apply palette configuration if enabled
75
- if use_palette:
76
- tool_config = PaletteLoader.get_enabled_tools_from_palette(
76
+ # Load user plugins early
77
+ try:
78
+ plugins = load_user_plugins()
79
+ import logging
80
+ logger = logging.getLogger(__name__)
81
+ if plugins:
82
+ logger.info(f"Loaded {len(plugins)} user plugin tools: {', '.join(plugins.keys())}")
83
+ except Exception as e:
84
+ import logging
85
+ logger = logging.getLogger(__name__)
86
+ logger.warning(f"Failed to load user plugins: {e}")
87
+ plugins = {}
88
+
89
+ # Apply mode configuration if enabled
90
+ if use_mode:
91
+ # First check for mode activation from environment
92
+ activate_mode_from_env()
93
+
94
+ tool_config = ModeLoader.get_enabled_tools_from_mode(
77
95
  base_enabled_tools=enabled_tools,
78
- force_palette=force_palette
96
+ force_mode=force_mode
79
97
  )
80
- # Apply palette environment variables
81
- PaletteLoader.apply_palette_environment()
98
+ # Apply mode environment variables
99
+ ModeLoader.apply_environment_from_mode()
82
100
  else:
83
101
  # Use individual tool configuration if provided, otherwise fall back to category-level flags
84
102
  tool_config = enabled_tools or {}
@@ -97,15 +115,16 @@ def register_all_tools(
97
115
  "multi_edit": is_tool_enabled("multi_edit", not disable_write_tools),
98
116
  "directory_tree": is_tool_enabled("directory_tree", True),
99
117
  "grep": is_tool_enabled("grep", not disable_search_tools),
100
- "grep_ast": is_tool_enabled("grep_ast", not disable_search_tools),
118
+ "symbols": is_tool_enabled("symbols", not disable_search_tools),
101
119
  "git_search": is_tool_enabled("git_search", not disable_search_tools),
102
120
  "content_replace": is_tool_enabled("content_replace", not disable_write_tools),
103
121
  "batch_search": is_tool_enabled("batch_search", not disable_search_tools),
104
122
  "find_files": is_tool_enabled("find_files", True),
105
- "unified_search": is_tool_enabled("unified_search", not disable_search_tools),
123
+ "rules": is_tool_enabled("rules", True),
124
+ "search": is_tool_enabled("search", not disable_search_tools),
106
125
  }
107
126
 
108
- # Vector tools setup (needed for unified search)
127
+ # Vector tools setup (needed for search)
109
128
  project_manager = None
110
129
  vector_enabled = {
111
130
  "vector_index": is_tool_enabled("vector_index", False),
@@ -113,7 +132,7 @@ def register_all_tools(
113
132
  }
114
133
 
115
134
  # Create project manager if vector tools, batch_search, or unified_search are enabled
116
- if any(vector_enabled.values()) or filesystem_enabled.get("batch_search", False) or filesystem_enabled.get("unified_search", False):
135
+ if any(vector_enabled.values()) or filesystem_enabled.get("batch_search", False) or filesystem_enabled.get("search", False):
117
136
  if vector_config:
118
137
  from hanzo_mcp.tools.vector.project_manager import ProjectVectorManager
119
138
  search_paths = [str(path) for path in permission_manager.allowed_paths]
@@ -155,7 +174,7 @@ def register_all_tools(
155
174
  all_tools[tool.name] = tool
156
175
 
157
176
  # Register agent tools if enabled
158
- agent_enabled = enable_agent_tool or is_tool_enabled("dispatch_agent", False)
177
+ agent_enabled = enable_agent_tool or is_tool_enabled("agent", False) or is_tool_enabled("dispatch_agent", False)
159
178
  if agent_enabled:
160
179
  agent_tools = register_agent_tools(
161
180
  mcp_server,
@@ -172,12 +191,15 @@ def register_all_tools(
172
191
 
173
192
  # Register todo tools if enabled
174
193
  todo_enabled = {
194
+ "todo": is_tool_enabled("todo", True),
195
+ # Backward compatibility - if old names are used, enable the unified tool
175
196
  "todo_read": is_tool_enabled("todo_read", True),
176
197
  "todo_write": is_tool_enabled("todo_write", True),
177
198
  }
178
199
 
200
+ # Enable unified todo if any of the todo tools are enabled
179
201
  if any(todo_enabled.values()):
180
- todo_tools = register_todo_tools(mcp_server, enabled_tools=todo_enabled)
202
+ todo_tools = register_todo_tools(mcp_server, enabled_tools={"todo": True})
181
203
  for tool in todo_tools:
182
204
  all_tools[tool.name] = tool
183
205
 
@@ -186,6 +208,12 @@ def register_all_tools(
186
208
  thinking_tool = register_thinking_tool(mcp_server)
187
209
  for tool in thinking_tool:
188
210
  all_tools[tool.name] = tool
211
+
212
+ # Register critic tool if enabled
213
+ if is_tool_enabled("critic", True):
214
+ critic_tools = register_critic_tool(mcp_server)
215
+ for tool in critic_tools:
216
+ all_tools[tool.name] = tool
189
217
 
190
218
  # Register vector tools if enabled (reuse project_manager if available)
191
219
  if any(vector_enabled.values()) and project_manager:
@@ -230,7 +258,7 @@ def register_all_tools(
230
258
 
231
259
  # Register unified MCP tool if enabled
232
260
  if is_tool_enabled("mcp", True):
233
- tool = UnifiedMCPTool()
261
+ tool = MCPTool()
234
262
  tool.register(mcp_server)
235
263
  all_tools[tool.name] = tool
236
264
 
@@ -275,9 +303,9 @@ def register_all_tools(
275
303
  stats_tool.register(mcp_server)
276
304
  all_tools[stats_tool.name] = stats_tool
277
305
 
278
- # Palette tool (always enabled for managing tool sets)
279
- palette_tool.register(mcp_server)
280
- all_tools[palette_tool.name] = palette_tool
306
+ # Mode tool (always enabled for managing tool sets)
307
+ mode_tool.register(mcp_server)
308
+ all_tools[mode_tool.name] = mode_tool
281
309
 
282
310
  # Register editor tools if enabled
283
311
  editor_enabled = {
@@ -303,11 +331,18 @@ def register_all_tools(
303
331
 
304
332
  # Register unified LLM tool if enabled
305
333
  if is_tool_enabled("llm", True):
306
- tool = UnifiedLLMTool()
334
+ tool = LLMTool()
307
335
  if tool.available_providers: # Only register if API keys found
308
336
  tool.register(mcp_server)
309
337
  all_tools[tool.name] = tool
310
338
 
339
+ # Register consensus tool if enabled (enabled by default)
340
+ if is_tool_enabled("consensus", True):
341
+ tool = ConsensusTool()
342
+ if tool.llm_tool.available_providers:
343
+ tool.register(mcp_server)
344
+ all_tools[tool.name] = tool
345
+
311
346
  # Register legacy LLM tools if explicitly enabled (disabled by default)
312
347
  legacy_llm_enabled = {
313
348
  "llm_legacy": is_tool_enabled("llm_legacy", False),
@@ -339,3 +374,14 @@ def register_all_tools(
339
374
  if is_tool_enabled(tool.name, False):
340
375
  tool.register(mcp_server)
341
376
  all_tools[tool.name] = tool
377
+
378
+ # Register user plugins last (so they can override built-in tools)
379
+ for plugin_name, plugin in plugins.items():
380
+ if is_tool_enabled(plugin_name, True):
381
+ try:
382
+ tool = plugin.tool_class()
383
+ tool.register(mcp_server)
384
+ all_tools[tool.name] = tool
385
+ logger.info(f"Registered plugin tool: {plugin_name}")
386
+ except Exception as e:
387
+ logger.error(f"Failed to register plugin tool {plugin_name}: {e}")
@@ -1,4 +1,4 @@
1
- """Agent tools for Hanzo MCP.
1
+ """Agent tools for Hanzo AI.
2
2
 
3
3
  This module provides tools that allow Claude to delegate tasks to sub-agents,
4
4
  enabling concurrent execution of multiple operations and specialized processing.
@@ -1,4 +1,4 @@
1
- """Agent tool implementation for Hanzo MCP.
1
+ """Agent tool implementation for Hanzo AI.
2
2
 
3
3
  This module implements the AgentTool that allows Claude to delegate tasks to sub-agents,
4
4
  enabling concurrent execution of multiple operations and specialized processing.
@@ -75,7 +75,7 @@ class AgentTool(BaseTool):
75
75
  Returns:
76
76
  Tool name
77
77
  """
78
- return "dispatch_agent"
78
+ return "agent"
79
79
 
80
80
  @property
81
81
  @override