hanzo-mcp 0.8.0__tar.gz → 0.8.2__tar.gz
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.
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/PKG-INFO +3 -3
- hanzo_mcp-0.8.2/hanzo_mcp/bridge.py +478 -0
- hanzo_mcp-0.8.2/hanzo_mcp/compute_nodes.py +179 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/dev_server.py +11 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/server.py +14 -1
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp.egg-info/PKG-INFO +3 -3
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp.egg-info/SOURCES.txt +5 -4
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp.egg-info/requires.txt +2 -2
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/pyproject.toml +3 -3
- hanzo_mcp-0.8.2/tests/test_cli_agents_consolidated.py +118 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/tests/test_hanzo_mcp_local.py +1 -1
- hanzo_mcp-0.8.2/tests/test_lsp_tool.py +206 -0
- hanzo_mcp-0.8.2/tests/test_memory_base.py +119 -0
- hanzo_mcp-0.8.2/tests/test_memory_consolidated.py +203 -0
- hanzo_mcp-0.8.2/tests/test_tools_suite.py +844 -0
- hanzo_mcp-0.8.0/tests/test_cli_agents.py +0 -248
- hanzo_mcp-0.8.0/tests/test_lsp_tool.py +0 -165
- hanzo_mcp-0.8.0/tests/test_memory_edge_cases.py +0 -478
- hanzo_mcp-0.8.0/tests/test_memory_tools.py +0 -246
- hanzo_mcp-0.8.0/tests/test_memory_tools_comprehensive.py +0 -651
- hanzo_mcp-0.8.0/tests/test_tools_suite.py +0 -458
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/README.md +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/__init__.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/__main__.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/analytics/__init__.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/analytics/posthog_analytics.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/cli.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/cli_enhanced.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/cli_plugin.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/config/__init__.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/config/settings.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/config/tool_config.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/prompts/__init__.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/prompts/compact_conversation.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/prompts/create_release.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/prompts/enhanced_prompts.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/prompts/example_custom_prompt.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/prompts/project_system.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/prompts/project_todo_reminder.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/prompts/tool_explorer.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/prompts/utils.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/server_enhanced.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/__init__.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/agent/__init__.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/agent/agent.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/agent/agent_tool.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/agent/agent_tool_v1_deprecated.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/agent/clarification_protocol.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/agent/clarification_tool.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/agent/claude_cli_tool.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/agent/claude_desktop_auth.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/agent/cli_agent_base.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/agent/code_auth.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/agent/code_auth_tool.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/agent/codex_cli_tool.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/agent/critic_tool.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/agent/gemini_cli_tool.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/agent/grok_cli_tool.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/agent/iching_tool.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/agent/network_tool.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/agent/prompt.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/agent/review_tool.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/agent/swarm_alias.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/agent/swarm_tool.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/agent/swarm_tool_v1_deprecated.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/agent/tool_adapter.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/common/__init__.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/common/base.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/common/batch_tool.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/common/config_tool.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/common/context.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/common/context_fix.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/common/critic_tool.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/common/decorators.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/common/enhanced_base.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/common/fastmcp_pagination.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/common/forgiving_edit.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/common/mode.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/common/mode_loader.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/common/paginated_base.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/common/paginated_response.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/common/pagination.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/common/permissions.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/common/personality.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/common/plugin_loader.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/common/stats.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/common/test_helpers.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/common/thinking_tool.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/common/tool_disable.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/common/tool_enable.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/common/tool_list.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/common/truncate.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/common/validation.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/config/__init__.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/config/config_tool.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/config/index_config.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/config/mode_tool.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/database/__init__.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/database/database_manager.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/database/graph.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/database/graph_add.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/database/graph_query.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/database/graph_remove.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/database/graph_search.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/database/graph_stats.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/database/sql.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/database/sql_query.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/database/sql_search.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/database/sql_stats.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/editor/__init__.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/editor/neovim_command.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/editor/neovim_edit.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/editor/neovim_session.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/filesystem/__init__.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/filesystem/ast_multi_edit.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/filesystem/ast_tool.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/filesystem/base.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/filesystem/batch_search.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/filesystem/content_replace.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/filesystem/diff.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/filesystem/directory_tree.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/filesystem/directory_tree_paginated.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/filesystem/edit.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/filesystem/find.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/filesystem/find_files.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/filesystem/git_search.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/filesystem/grep.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/filesystem/multi_edit.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/filesystem/read.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/filesystem/rules_tool.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/filesystem/search_tool.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/filesystem/symbols_tool.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/filesystem/tree.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/filesystem/unix_aliases.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/filesystem/watch.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/filesystem/write.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/jupyter/__init__.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/jupyter/base.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/jupyter/jupyter.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/jupyter/notebook_edit.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/jupyter/notebook_read.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/llm/__init__.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/llm/consensus_tool.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/llm/llm_manage.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/llm/llm_tool.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/llm/provider_tools.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/lsp/__init__.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/lsp/lsp_tool.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/mcp/__init__.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/mcp/mcp_add.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/mcp/mcp_remove.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/mcp/mcp_stats.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/mcp/mcp_tool.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/memory/__init__.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/memory/knowledge_tools.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/memory/memory_tools.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/search/__init__.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/search/find_tool.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/search/unified_search.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/shell/__init__.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/shell/auto_background.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/shell/base.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/shell/base_process.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/shell/bash_session.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/shell/bash_session_executor.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/shell/bash_tool.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/shell/command_executor.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/shell/logs.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/shell/npx.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/shell/npx_background.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/shell/npx_tool.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/shell/open.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/shell/pkill.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/shell/process_tool.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/shell/processes.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/shell/run_background.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/shell/run_command.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/shell/run_command_windows.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/shell/session_manager.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/shell/session_storage.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/shell/streaming_command.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/shell/uvx.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/shell/uvx_background.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/shell/uvx_tool.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/todo/__init__.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/todo/base.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/todo/todo.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/todo/todo_read.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/todo/todo_write.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/vector/__init__.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/vector/ast_analyzer.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/vector/git_ingester.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/vector/index_tool.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/vector/infinity_store.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/vector/mock_infinity.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/vector/project_manager.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/vector/vector.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/vector/vector_index.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/tools/vector/vector_search.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp/types.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp.egg-info/dependency_links.txt +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp.egg-info/entry_points.txt +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/hanzo_mcp.egg-info/top_level.txt +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/setup.cfg +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/tests/test_agent_tools_ci.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/tests/test_async_support.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/tests/test_batch_tool_edge_cases.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/tests/test_cli.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/tests/test_e2e_demo.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/tests/test_e2e_simple.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/tests/test_failure_cases.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/tests/test_find_tool_ffind.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/tests/test_find_tool_integration.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/tests/test_find_tool_registration.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/tests/test_git_ingestion.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/tests/test_hanzo_agents_integration.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/tests/test_hanzo_mcp_integration.py +1 -1
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/tests/test_hanzo_mcp_simple.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/tests/test_hanzo_network_integration.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/tests/test_litellm_warnings.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/tests/test_manual.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/tests/test_memory_basic.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/tests/test_memory_simple.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/tests/test_memory_utils.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/tests/test_new_tools.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/tests/test_performance.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/tests/test_search.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/tests/test_search_quality.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/tests/test_shell_features.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/tests/test_simple.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/tests/test_stdio_protocol.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/tests/test_stdio_simple.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/tests/test_streaming_command.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/tests/test_swarm_simple.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/tests/test_unified_search.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/tests/test_utils.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/tests/test_vector_store.py +0 -0
- {hanzo_mcp-0.8.0 → hanzo_mcp-0.8.2}/tests/test_web3_integration.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: hanzo-mcp
|
|
3
|
-
Version: 0.8.
|
|
3
|
+
Version: 0.8.2
|
|
4
4
|
Summary: The Zen of Hanzo MCP: One server to rule them all. The ultimate MCP that orchestrates all others.
|
|
5
5
|
Author-email: Hanzo Industries Inc <dev@hanzo.ai>
|
|
6
6
|
License: MIT
|
|
@@ -24,8 +24,8 @@ Requires-Dist: grep-ast>=0.8.1
|
|
|
24
24
|
Requires-Dist: bashlex>=0.18
|
|
25
25
|
Requires-Dist: libtmux>=0.39.0
|
|
26
26
|
Requires-Dist: nbformat>=5.10.4
|
|
27
|
-
Requires-Dist: psutil>=6.
|
|
28
|
-
Requires-Dist: pydantic>=2.
|
|
27
|
+
Requires-Dist: psutil>=6.0.0
|
|
28
|
+
Requires-Dist: pydantic>=2.9.2
|
|
29
29
|
Requires-Dist: pydantic-settings>=2.7.0
|
|
30
30
|
Requires-Dist: typing-extensions>=4.13.0
|
|
31
31
|
Requires-Dist: watchdog>=6.0.0
|
|
@@ -0,0 +1,478 @@
|
|
|
1
|
+
"""MCP Bridge for inter-Claude communication.
|
|
2
|
+
|
|
3
|
+
This module provides MCP server functionality that allows Claude instances
|
|
4
|
+
to communicate with each other, enabling peer-to-peer agent networks.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import argparse
|
|
8
|
+
import asyncio
|
|
9
|
+
import json
|
|
10
|
+
import logging
|
|
11
|
+
import os
|
|
12
|
+
import sys
|
|
13
|
+
from typing import Any, Dict, List, Optional
|
|
14
|
+
from dataclasses import dataclass, asdict
|
|
15
|
+
|
|
16
|
+
import mcp.server.fastmcp as mcp
|
|
17
|
+
from mcp import tool
|
|
18
|
+
from mcp.server.fastmcp import FastMCP
|
|
19
|
+
from mcp.server.models import InitializationOptions
|
|
20
|
+
from mcp.server.stdio import stdio_server
|
|
21
|
+
from mcp.types import TextContent, Tool, INTERNAL_ERROR
|
|
22
|
+
|
|
23
|
+
logger = logging.getLogger(__name__)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@dataclass
|
|
27
|
+
class BridgeConfig:
|
|
28
|
+
"""Configuration for MCP bridge."""
|
|
29
|
+
target_port: int
|
|
30
|
+
instance_id: int
|
|
31
|
+
role: str
|
|
32
|
+
source_instance: Optional[int] = None
|
|
33
|
+
target_instance: Optional[int] = None
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class ClaudeBridge(FastMCP):
|
|
37
|
+
"""MCP Bridge server for Claude-to-Claude communication."""
|
|
38
|
+
|
|
39
|
+
def __init__(self, config: BridgeConfig):
|
|
40
|
+
"""Initialize the bridge.
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
config: Bridge configuration
|
|
44
|
+
"""
|
|
45
|
+
# Set server name based on target instance
|
|
46
|
+
super().__init__(f"claude_instance_{config.instance_id}")
|
|
47
|
+
|
|
48
|
+
self.config = config
|
|
49
|
+
self.conversation_history: List[Dict[str, Any]] = []
|
|
50
|
+
self.shared_context: Dict[str, Any] = {}
|
|
51
|
+
|
|
52
|
+
# Register tools
|
|
53
|
+
self._register_tools()
|
|
54
|
+
|
|
55
|
+
def _register_tools(self):
|
|
56
|
+
"""Register MCP tools for inter-Claude communication."""
|
|
57
|
+
|
|
58
|
+
@self.tool()
|
|
59
|
+
async def chat_with_claude(message: str, context: Optional[str] = None) -> str:
|
|
60
|
+
"""Chat with another Claude instance.
|
|
61
|
+
|
|
62
|
+
Args:
|
|
63
|
+
message: Message to send to the other Claude
|
|
64
|
+
context: Optional context to provide
|
|
65
|
+
|
|
66
|
+
Returns:
|
|
67
|
+
Response from the other Claude instance
|
|
68
|
+
"""
|
|
69
|
+
logger.info(f"Bridge {self.config.instance_id}: Received chat request")
|
|
70
|
+
|
|
71
|
+
# Record in conversation history
|
|
72
|
+
self.conversation_history.append({
|
|
73
|
+
"from": self.config.source_instance,
|
|
74
|
+
"to": self.config.target_instance,
|
|
75
|
+
"message": message,
|
|
76
|
+
"context": context
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
# Simulate response (in production, this would make actual API call)
|
|
80
|
+
response = await self._forward_to_claude(message, context)
|
|
81
|
+
|
|
82
|
+
self.conversation_history.append({
|
|
83
|
+
"from": self.config.target_instance,
|
|
84
|
+
"to": self.config.source_instance,
|
|
85
|
+
"response": response
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
return response
|
|
89
|
+
|
|
90
|
+
@self.tool()
|
|
91
|
+
async def ask_claude_to_review(
|
|
92
|
+
code: str,
|
|
93
|
+
description: str,
|
|
94
|
+
focus_areas: Optional[List[str]] = None
|
|
95
|
+
) -> Dict[str, Any]:
|
|
96
|
+
"""Ask another Claude to review code.
|
|
97
|
+
|
|
98
|
+
Args:
|
|
99
|
+
code: Code to review
|
|
100
|
+
description: Description of what the code does
|
|
101
|
+
focus_areas: Specific areas to focus on (e.g., ["security", "performance"])
|
|
102
|
+
|
|
103
|
+
Returns:
|
|
104
|
+
Review feedback from the other Claude
|
|
105
|
+
"""
|
|
106
|
+
logger.info(f"Bridge {self.config.instance_id}: Code review request")
|
|
107
|
+
|
|
108
|
+
review_prompt = self._build_review_prompt(code, description, focus_areas)
|
|
109
|
+
review = await self._forward_to_claude(review_prompt)
|
|
110
|
+
|
|
111
|
+
return {
|
|
112
|
+
"reviewer": f"claude_{self.config.instance_id}",
|
|
113
|
+
"role": self.config.role,
|
|
114
|
+
"feedback": review,
|
|
115
|
+
"focus_areas": focus_areas or ["general"]
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
@self.tool()
|
|
119
|
+
async def delegate_to_claude(
|
|
120
|
+
task: str,
|
|
121
|
+
requirements: List[str],
|
|
122
|
+
constraints: Optional[List[str]] = None
|
|
123
|
+
) -> Dict[str, Any]:
|
|
124
|
+
"""Delegate a task to another Claude instance.
|
|
125
|
+
|
|
126
|
+
Args:
|
|
127
|
+
task: Task description
|
|
128
|
+
requirements: List of requirements
|
|
129
|
+
constraints: Optional constraints
|
|
130
|
+
|
|
131
|
+
Returns:
|
|
132
|
+
Task completion result from the other Claude
|
|
133
|
+
"""
|
|
134
|
+
logger.info(f"Bridge {self.config.instance_id}: Task delegation")
|
|
135
|
+
|
|
136
|
+
delegation_prompt = self._build_delegation_prompt(task, requirements, constraints)
|
|
137
|
+
result = await self._forward_to_claude(delegation_prompt)
|
|
138
|
+
|
|
139
|
+
return {
|
|
140
|
+
"delegated_to": f"claude_{self.config.instance_id}",
|
|
141
|
+
"role": self.config.role,
|
|
142
|
+
"task": task,
|
|
143
|
+
"result": result,
|
|
144
|
+
"status": "completed"
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
@self.tool()
|
|
148
|
+
async def get_claude_opinion(
|
|
149
|
+
question: str,
|
|
150
|
+
options: Optional[List[str]] = None,
|
|
151
|
+
criteria: Optional[List[str]] = None
|
|
152
|
+
) -> Dict[str, Any]:
|
|
153
|
+
"""Get another Claude's opinion on a decision.
|
|
154
|
+
|
|
155
|
+
Args:
|
|
156
|
+
question: The question or decision to get opinion on
|
|
157
|
+
options: Optional list of options to choose from
|
|
158
|
+
criteria: Optional evaluation criteria
|
|
159
|
+
|
|
160
|
+
Returns:
|
|
161
|
+
Opinion and reasoning from the other Claude
|
|
162
|
+
"""
|
|
163
|
+
logger.info(f"Bridge {self.config.instance_id}: Opinion request")
|
|
164
|
+
|
|
165
|
+
opinion_prompt = self._build_opinion_prompt(question, options, criteria)
|
|
166
|
+
opinion = await self._forward_to_claude(opinion_prompt)
|
|
167
|
+
|
|
168
|
+
return {
|
|
169
|
+
"advisor": f"claude_{self.config.instance_id}",
|
|
170
|
+
"role": self.config.role,
|
|
171
|
+
"question": question,
|
|
172
|
+
"opinion": opinion,
|
|
173
|
+
"options_considered": options,
|
|
174
|
+
"criteria_used": criteria
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
@self.tool()
|
|
178
|
+
async def share_context_with_claude(
|
|
179
|
+
key: str,
|
|
180
|
+
value: Any,
|
|
181
|
+
description: Optional[str] = None
|
|
182
|
+
) -> bool:
|
|
183
|
+
"""Share context with another Claude instance.
|
|
184
|
+
|
|
185
|
+
Args:
|
|
186
|
+
key: Context key
|
|
187
|
+
value: Context value
|
|
188
|
+
description: Optional description of the context
|
|
189
|
+
|
|
190
|
+
Returns:
|
|
191
|
+
Success status
|
|
192
|
+
"""
|
|
193
|
+
logger.info(f"Bridge {self.config.instance_id}: Sharing context '{key}'")
|
|
194
|
+
|
|
195
|
+
self.shared_context[key] = {
|
|
196
|
+
"value": value,
|
|
197
|
+
"description": description,
|
|
198
|
+
"shared_by": self.config.source_instance,
|
|
199
|
+
"shared_with": self.config.target_instance
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
return True
|
|
203
|
+
|
|
204
|
+
@self.tool()
|
|
205
|
+
async def get_shared_context(key: Optional[str] = None) -> Dict[str, Any]:
|
|
206
|
+
"""Get shared context from Claude network.
|
|
207
|
+
|
|
208
|
+
Args:
|
|
209
|
+
key: Optional specific key to retrieve
|
|
210
|
+
|
|
211
|
+
Returns:
|
|
212
|
+
Shared context data
|
|
213
|
+
"""
|
|
214
|
+
if key:
|
|
215
|
+
return self.shared_context.get(key, {})
|
|
216
|
+
return self.shared_context
|
|
217
|
+
|
|
218
|
+
@self.tool()
|
|
219
|
+
async def brainstorm_with_claude(
|
|
220
|
+
topic: str,
|
|
221
|
+
num_ideas: int = 5,
|
|
222
|
+
constraints: Optional[List[str]] = None
|
|
223
|
+
) -> List[str]:
|
|
224
|
+
"""Brainstorm ideas with another Claude.
|
|
225
|
+
|
|
226
|
+
Args:
|
|
227
|
+
topic: Topic to brainstorm about
|
|
228
|
+
num_ideas: Number of ideas to generate
|
|
229
|
+
constraints: Optional constraints
|
|
230
|
+
|
|
231
|
+
Returns:
|
|
232
|
+
List of brainstormed ideas
|
|
233
|
+
"""
|
|
234
|
+
logger.info(f"Bridge {self.config.instance_id}: Brainstorming request")
|
|
235
|
+
|
|
236
|
+
brainstorm_prompt = f"""
|
|
237
|
+
Please brainstorm {num_ideas} ideas about: {topic}
|
|
238
|
+
|
|
239
|
+
{"Constraints: " + ", ".join(constraints) if constraints else ""}
|
|
240
|
+
|
|
241
|
+
Provide creative and practical ideas.
|
|
242
|
+
"""
|
|
243
|
+
|
|
244
|
+
response = await self._forward_to_claude(brainstorm_prompt)
|
|
245
|
+
|
|
246
|
+
# Parse response into list (simplified)
|
|
247
|
+
ideas = response.split("\n")
|
|
248
|
+
ideas = [idea.strip() for idea in ideas if idea.strip()]
|
|
249
|
+
|
|
250
|
+
return ideas[:num_ideas]
|
|
251
|
+
|
|
252
|
+
@self.tool()
|
|
253
|
+
async def get_claude_status() -> Dict[str, Any]:
|
|
254
|
+
"""Get status of the connected Claude instance.
|
|
255
|
+
|
|
256
|
+
Returns:
|
|
257
|
+
Status information
|
|
258
|
+
"""
|
|
259
|
+
return {
|
|
260
|
+
"instance_id": self.config.instance_id,
|
|
261
|
+
"role": self.config.role,
|
|
262
|
+
"status": "available",
|
|
263
|
+
"conversation_count": len(self.conversation_history),
|
|
264
|
+
"shared_context_keys": list(self.shared_context.keys())
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
def _build_review_prompt(self, code: str, description: str,
|
|
268
|
+
focus_areas: Optional[List[str]]) -> str:
|
|
269
|
+
"""Build a code review prompt."""
|
|
270
|
+
prompt = f"""
|
|
271
|
+
Please review the following code:
|
|
272
|
+
|
|
273
|
+
Description: {description}
|
|
274
|
+
|
|
275
|
+
Code:
|
|
276
|
+
```
|
|
277
|
+
{code}
|
|
278
|
+
```
|
|
279
|
+
"""
|
|
280
|
+
|
|
281
|
+
if focus_areas:
|
|
282
|
+
prompt += f"\n\nPlease focus particularly on: {', '.join(focus_areas)}"
|
|
283
|
+
|
|
284
|
+
prompt += """
|
|
285
|
+
|
|
286
|
+
Provide constructive feedback on:
|
|
287
|
+
1. Potential bugs or issues
|
|
288
|
+
2. Code quality and best practices
|
|
289
|
+
3. Performance considerations
|
|
290
|
+
4. Security concerns
|
|
291
|
+
5. Suggestions for improvement
|
|
292
|
+
"""
|
|
293
|
+
|
|
294
|
+
return prompt
|
|
295
|
+
|
|
296
|
+
def _build_delegation_prompt(self, task: str, requirements: List[str],
|
|
297
|
+
constraints: Optional[List[str]]) -> str:
|
|
298
|
+
"""Build a task delegation prompt."""
|
|
299
|
+
prompt = f"""
|
|
300
|
+
Please complete the following task:
|
|
301
|
+
|
|
302
|
+
Task: {task}
|
|
303
|
+
|
|
304
|
+
Requirements:
|
|
305
|
+
{chr(10).join(f"- {req}" for req in requirements)}
|
|
306
|
+
"""
|
|
307
|
+
|
|
308
|
+
if constraints:
|
|
309
|
+
prompt += f"""
|
|
310
|
+
|
|
311
|
+
Constraints:
|
|
312
|
+
{chr(10).join(f"- {con}" for con in constraints)}
|
|
313
|
+
"""
|
|
314
|
+
|
|
315
|
+
prompt += """
|
|
316
|
+
|
|
317
|
+
Provide a complete solution that meets all requirements.
|
|
318
|
+
"""
|
|
319
|
+
|
|
320
|
+
return prompt
|
|
321
|
+
|
|
322
|
+
def _build_opinion_prompt(self, question: str, options: Optional[List[str]],
|
|
323
|
+
criteria: Optional[List[str]]) -> str:
|
|
324
|
+
"""Build an opinion request prompt."""
|
|
325
|
+
prompt = f"""
|
|
326
|
+
I need your opinion on the following:
|
|
327
|
+
|
|
328
|
+
Question: {question}
|
|
329
|
+
"""
|
|
330
|
+
|
|
331
|
+
if options:
|
|
332
|
+
prompt += f"""
|
|
333
|
+
|
|
334
|
+
Options to consider:
|
|
335
|
+
{chr(10).join(f"{i+1}. {opt}" for i, opt in enumerate(options))}
|
|
336
|
+
"""
|
|
337
|
+
|
|
338
|
+
if criteria:
|
|
339
|
+
prompt += f"""
|
|
340
|
+
|
|
341
|
+
Please evaluate based on these criteria:
|
|
342
|
+
{chr(10).join(f"- {crit}" for crit in criteria)}
|
|
343
|
+
"""
|
|
344
|
+
|
|
345
|
+
prompt += """
|
|
346
|
+
|
|
347
|
+
Provide your recommendation with clear reasoning.
|
|
348
|
+
"""
|
|
349
|
+
|
|
350
|
+
return prompt
|
|
351
|
+
|
|
352
|
+
async def _forward_to_claude(self, prompt: str, context: Optional[str] = None) -> str:
|
|
353
|
+
"""Forward a request to the target Claude instance.
|
|
354
|
+
|
|
355
|
+
In production, this would make an actual API call to the Claude instance.
|
|
356
|
+
For now, it returns a simulated response.
|
|
357
|
+
"""
|
|
358
|
+
# Add context if provided
|
|
359
|
+
full_prompt = prompt
|
|
360
|
+
if context:
|
|
361
|
+
full_prompt = f"Context: {context}\n\n{prompt}"
|
|
362
|
+
|
|
363
|
+
# Log the forwarding
|
|
364
|
+
logger.info(f"Forwarding from instance {self.config.source_instance} to {self.config.target_instance}")
|
|
365
|
+
logger.debug(f"Prompt: {full_prompt[:200]}...")
|
|
366
|
+
|
|
367
|
+
# In production, this would:
|
|
368
|
+
# 1. Connect to the target Claude instance API
|
|
369
|
+
# 2. Send the prompt
|
|
370
|
+
# 3. Receive and return the response
|
|
371
|
+
|
|
372
|
+
# Simulated response based on role
|
|
373
|
+
if self.config.role.startswith("critic"):
|
|
374
|
+
return f"""
|
|
375
|
+
As {self.config.role}, I've analyzed your request:
|
|
376
|
+
|
|
377
|
+
Strengths:
|
|
378
|
+
- The approach is logical and well-structured
|
|
379
|
+
- Good attention to requirements
|
|
380
|
+
|
|
381
|
+
Areas for improvement:
|
|
382
|
+
- Consider edge cases more thoroughly
|
|
383
|
+
- Add more comprehensive error handling
|
|
384
|
+
- Optimize for performance in high-load scenarios
|
|
385
|
+
|
|
386
|
+
Recommendation: Proceed with suggested improvements.
|
|
387
|
+
"""
|
|
388
|
+
else:
|
|
389
|
+
return f"""
|
|
390
|
+
Response from {self.config.role} (instance {self.config.instance_id}):
|
|
391
|
+
|
|
392
|
+
I've processed your request: "{prompt[:100]}..."
|
|
393
|
+
|
|
394
|
+
The task has been completed successfully with the following approach:
|
|
395
|
+
1. Analyzed the requirements
|
|
396
|
+
2. Implemented the solution
|
|
397
|
+
3. Validated the results
|
|
398
|
+
|
|
399
|
+
The solution meets all specified criteria.
|
|
400
|
+
"""
|
|
401
|
+
|
|
402
|
+
|
|
403
|
+
async def run_bridge_server(config: BridgeConfig):
|
|
404
|
+
"""Run the MCP bridge server.
|
|
405
|
+
|
|
406
|
+
Args:
|
|
407
|
+
config: Bridge configuration
|
|
408
|
+
"""
|
|
409
|
+
# Configure logging
|
|
410
|
+
logging.basicConfig(
|
|
411
|
+
level=logging.INFO,
|
|
412
|
+
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
|
|
413
|
+
)
|
|
414
|
+
|
|
415
|
+
logger.info(f"Starting MCP Bridge for Claude instance {config.instance_id}")
|
|
416
|
+
logger.info(f"Role: {config.role}")
|
|
417
|
+
logger.info(f"Target port: {config.target_port}")
|
|
418
|
+
|
|
419
|
+
# Create and run the bridge
|
|
420
|
+
bridge = ClaudeBridge(config)
|
|
421
|
+
|
|
422
|
+
# Run the stdio server
|
|
423
|
+
async with stdio_server() as (read_stream, write_stream):
|
|
424
|
+
await bridge.run(
|
|
425
|
+
read_stream=read_stream,
|
|
426
|
+
write_stream=write_stream,
|
|
427
|
+
InitializationOptions(
|
|
428
|
+
server_name=bridge.name,
|
|
429
|
+
server_version="1.0.0",
|
|
430
|
+
capabilities=bridge.get_capabilities()
|
|
431
|
+
)
|
|
432
|
+
)
|
|
433
|
+
|
|
434
|
+
|
|
435
|
+
def main():
|
|
436
|
+
"""Main entry point for the bridge."""
|
|
437
|
+
parser = argparse.ArgumentParser(
|
|
438
|
+
description="MCP Bridge for Claude-to-Claude communication"
|
|
439
|
+
)
|
|
440
|
+
parser.add_argument(
|
|
441
|
+
"--target-port",
|
|
442
|
+
type=int,
|
|
443
|
+
required=True,
|
|
444
|
+
help="Port of the target Claude instance"
|
|
445
|
+
)
|
|
446
|
+
parser.add_argument(
|
|
447
|
+
"--instance-id",
|
|
448
|
+
type=int,
|
|
449
|
+
required=True,
|
|
450
|
+
help="ID of the target Claude instance"
|
|
451
|
+
)
|
|
452
|
+
parser.add_argument(
|
|
453
|
+
"--role",
|
|
454
|
+
type=str,
|
|
455
|
+
required=True,
|
|
456
|
+
help="Role of the target instance (primary, critic_1, etc.)"
|
|
457
|
+
)
|
|
458
|
+
|
|
459
|
+
args = parser.parse_args()
|
|
460
|
+
|
|
461
|
+
# Get source/target from environment
|
|
462
|
+
source_instance = int(os.environ.get("SOURCE_INSTANCE", "0"))
|
|
463
|
+
target_instance = int(os.environ.get("TARGET_INSTANCE", args.instance_id))
|
|
464
|
+
|
|
465
|
+
config = BridgeConfig(
|
|
466
|
+
target_port=args.target_port,
|
|
467
|
+
instance_id=args.instance_id,
|
|
468
|
+
role=args.role,
|
|
469
|
+
source_instance=source_instance,
|
|
470
|
+
target_instance=target_instance
|
|
471
|
+
)
|
|
472
|
+
|
|
473
|
+
# Run the bridge
|
|
474
|
+
asyncio.run(run_bridge_server(config))
|
|
475
|
+
|
|
476
|
+
|
|
477
|
+
if __name__ == "__main__":
|
|
478
|
+
main()
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
"""Compute node detection and management for distributed processing."""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import platform
|
|
5
|
+
import subprocess
|
|
6
|
+
from typing import Any, Dict, List
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class ComputeNodeDetector:
|
|
10
|
+
"""Detect available compute nodes (GPUs, WebGPU, CPUs) for distributed work."""
|
|
11
|
+
|
|
12
|
+
@staticmethod
|
|
13
|
+
def detect_local_gpus() -> List[Dict[str, Any]]:
|
|
14
|
+
"""Detect local GPU devices."""
|
|
15
|
+
gpus = []
|
|
16
|
+
|
|
17
|
+
# Try NVIDIA GPUs
|
|
18
|
+
try:
|
|
19
|
+
result = subprocess.run(
|
|
20
|
+
["nvidia-smi", "--query-gpu=name,memory.total", "--format=csv,noheader"],
|
|
21
|
+
capture_output=True,
|
|
22
|
+
text=True,
|
|
23
|
+
timeout=2
|
|
24
|
+
)
|
|
25
|
+
if result.returncode == 0:
|
|
26
|
+
for line in result.stdout.strip().split('\n'):
|
|
27
|
+
if line:
|
|
28
|
+
name, memory = line.split(', ')
|
|
29
|
+
gpus.append({
|
|
30
|
+
"type": "cuda",
|
|
31
|
+
"name": name,
|
|
32
|
+
"memory": memory,
|
|
33
|
+
"id": f"cuda:{len(gpus)}"
|
|
34
|
+
})
|
|
35
|
+
except (FileNotFoundError, subprocess.TimeoutExpired):
|
|
36
|
+
pass
|
|
37
|
+
|
|
38
|
+
# Try Metal GPUs (macOS)
|
|
39
|
+
if platform.system() == "Darwin":
|
|
40
|
+
try:
|
|
41
|
+
# Check for Metal support
|
|
42
|
+
result = subprocess.run(
|
|
43
|
+
["system_profiler", "SPDisplaysDataType"],
|
|
44
|
+
capture_output=True,
|
|
45
|
+
text=True,
|
|
46
|
+
timeout=2
|
|
47
|
+
)
|
|
48
|
+
if result.returncode == 0 and "Metal" in result.stdout:
|
|
49
|
+
# Parse GPU info from system_profiler
|
|
50
|
+
lines = result.stdout.split('\n')
|
|
51
|
+
for i, line in enumerate(lines):
|
|
52
|
+
if 'Chipset Model:' in line:
|
|
53
|
+
gpu_name = line.split(':')[1].strip()
|
|
54
|
+
gpus.append({
|
|
55
|
+
"type": "metal",
|
|
56
|
+
"name": gpu_name,
|
|
57
|
+
"memory": "Shared",
|
|
58
|
+
"id": f"metal:{len(gpus)}"
|
|
59
|
+
})
|
|
60
|
+
except (FileNotFoundError, subprocess.TimeoutExpired):
|
|
61
|
+
pass
|
|
62
|
+
|
|
63
|
+
return gpus
|
|
64
|
+
|
|
65
|
+
@staticmethod
|
|
66
|
+
def detect_webgpu_nodes() -> List[Dict[str, Any]]:
|
|
67
|
+
"""Detect connected WebGPU nodes (from browsers)."""
|
|
68
|
+
webgpu_nodes = []
|
|
69
|
+
|
|
70
|
+
# Check for WebGPU connections (would need actual WebSocket/server to track)
|
|
71
|
+
# For now, check if a WebGPU server is running
|
|
72
|
+
webgpu_port = os.environ.get("HANZO_WEBGPU_PORT", "8765")
|
|
73
|
+
try:
|
|
74
|
+
import socket
|
|
75
|
+
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
76
|
+
result = sock.connect_ex(('localhost', int(webgpu_port)))
|
|
77
|
+
sock.close()
|
|
78
|
+
if result == 0:
|
|
79
|
+
webgpu_nodes.append({
|
|
80
|
+
"type": "webgpu",
|
|
81
|
+
"name": "Chrome WebGPU",
|
|
82
|
+
"memory": "Browser",
|
|
83
|
+
"id": "webgpu:0"
|
|
84
|
+
})
|
|
85
|
+
except Exception:
|
|
86
|
+
pass
|
|
87
|
+
|
|
88
|
+
return webgpu_nodes
|
|
89
|
+
|
|
90
|
+
@staticmethod
|
|
91
|
+
def detect_cpu_nodes() -> List[Dict[str, Any]]:
|
|
92
|
+
"""Detect CPU compute nodes."""
|
|
93
|
+
import multiprocessing
|
|
94
|
+
|
|
95
|
+
return [{
|
|
96
|
+
"type": "cpu",
|
|
97
|
+
"name": f"{platform.processor() or 'CPU'}",
|
|
98
|
+
"cores": multiprocessing.cpu_count(),
|
|
99
|
+
"id": "cpu:0"
|
|
100
|
+
}]
|
|
101
|
+
|
|
102
|
+
@classmethod
|
|
103
|
+
def get_all_nodes(cls) -> List[Dict[str, Any]]:
|
|
104
|
+
"""Get all available compute nodes."""
|
|
105
|
+
nodes = []
|
|
106
|
+
|
|
107
|
+
# Detect GPUs
|
|
108
|
+
gpus = cls.detect_local_gpus()
|
|
109
|
+
nodes.extend(gpus)
|
|
110
|
+
|
|
111
|
+
# Detect WebGPU connections
|
|
112
|
+
webgpu = cls.detect_webgpu_nodes()
|
|
113
|
+
nodes.extend(webgpu)
|
|
114
|
+
|
|
115
|
+
# If no GPUs/WebGPU, add CPU as compute node
|
|
116
|
+
if not nodes:
|
|
117
|
+
nodes.extend(cls.detect_cpu_nodes())
|
|
118
|
+
|
|
119
|
+
return nodes
|
|
120
|
+
|
|
121
|
+
@classmethod
|
|
122
|
+
def get_node_count(cls) -> int:
|
|
123
|
+
"""Get total number of available compute nodes."""
|
|
124
|
+
return len(cls.get_all_nodes())
|
|
125
|
+
|
|
126
|
+
@classmethod
|
|
127
|
+
def get_node_summary(cls) -> str:
|
|
128
|
+
"""Get a summary string of available nodes."""
|
|
129
|
+
nodes = cls.get_all_nodes()
|
|
130
|
+
if not nodes:
|
|
131
|
+
return "No compute nodes available"
|
|
132
|
+
|
|
133
|
+
count = len(nodes)
|
|
134
|
+
node_word = "node" if count == 1 else "nodes"
|
|
135
|
+
|
|
136
|
+
# Group by type
|
|
137
|
+
types = {}
|
|
138
|
+
for node in nodes:
|
|
139
|
+
node_type = node["type"]
|
|
140
|
+
if node_type not in types:
|
|
141
|
+
types[node_type] = 0
|
|
142
|
+
types[node_type] += 1
|
|
143
|
+
|
|
144
|
+
# Build summary
|
|
145
|
+
parts = []
|
|
146
|
+
for node_type, type_count in types.items():
|
|
147
|
+
if node_type == "cuda":
|
|
148
|
+
parts.append(f"{type_count} CUDA GPU{'s' if type_count > 1 else ''}")
|
|
149
|
+
elif node_type == "metal":
|
|
150
|
+
parts.append(f"{type_count} Metal GPU{'s' if type_count > 1 else ''}")
|
|
151
|
+
elif node_type == "webgpu":
|
|
152
|
+
parts.append(f"{type_count} WebGPU")
|
|
153
|
+
elif node_type == "cpu":
|
|
154
|
+
parts.append(f"{type_count} CPU")
|
|
155
|
+
|
|
156
|
+
type_str = ", ".join(parts)
|
|
157
|
+
return f"{count} {node_word} available ({type_str})"
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def print_node_status():
|
|
161
|
+
"""Print current node status."""
|
|
162
|
+
detector = ComputeNodeDetector()
|
|
163
|
+
nodes = detector.get_all_nodes()
|
|
164
|
+
|
|
165
|
+
print(f"\n🖥️ Compute Nodes: {len(nodes)}")
|
|
166
|
+
for node in nodes:
|
|
167
|
+
if node["type"] in ["cuda", "metal"]:
|
|
168
|
+
print(f" • {node['id']}: {node['name']} ({node['memory']})")
|
|
169
|
+
elif node["type"] == "webgpu":
|
|
170
|
+
print(f" • {node['id']}: {node['name']}")
|
|
171
|
+
elif node["type"] == "cpu":
|
|
172
|
+
print(f" • {node['id']}: {node['name']} ({node['cores']} cores)")
|
|
173
|
+
print()
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
if __name__ == "__main__":
|
|
177
|
+
# Test the detector
|
|
178
|
+
print_node_status()
|
|
179
|
+
print(ComputeNodeDetector.get_node_summary())
|
|
@@ -172,6 +172,17 @@ class DevServer:
|
|
|
172
172
|
|
|
173
173
|
logger = logging.getLogger(__name__)
|
|
174
174
|
logger.info(f"\n🚀 Starting Hanzo AI in development mode...")
|
|
175
|
+
|
|
176
|
+
# Show compute nodes
|
|
177
|
+
try:
|
|
178
|
+
from hanzo_mcp.compute_nodes import ComputeNodeDetector
|
|
179
|
+
detector = ComputeNodeDetector()
|
|
180
|
+
summary = detector.get_node_summary()
|
|
181
|
+
logger.info(f"🖥️ {summary}")
|
|
182
|
+
except Exception:
|
|
183
|
+
# Silently ignore if compute node detection fails
|
|
184
|
+
pass
|
|
185
|
+
|
|
175
186
|
logger.info(f"🔧 Hot reload enabled - watching for file changes")
|
|
176
187
|
logger.info(f"📁 Project: {self.project_dir or 'current directory'}")
|
|
177
188
|
logger.info(f"🌐 Transport: {transport}\n")
|