hanzo-mcp 0.7.7__tar.gz → 0.8.0__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.7.7 → hanzo_mcp-0.8.0}/PKG-INFO +1 -1
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/__init__.py +6 -0
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/__main__.py +1 -1
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/analytics/__init__.py +2 -2
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/analytics/posthog_analytics.py +76 -82
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/cli.py +31 -36
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/cli_enhanced.py +94 -72
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/cli_plugin.py +27 -17
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/config/__init__.py +2 -2
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/config/settings.py +112 -88
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/config/tool_config.py +32 -34
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/dev_server.py +66 -67
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/prompts/__init__.py +94 -12
- hanzo_mcp-0.8.0/hanzo_mcp/prompts/enhanced_prompts.py +809 -0
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/prompts/example_custom_prompt.py +6 -5
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/prompts/project_todo_reminder.py +0 -1
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/prompts/tool_explorer.py +10 -7
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/server.py +17 -21
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/server_enhanced.py +15 -22
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/__init__.py +56 -28
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/agent/__init__.py +16 -19
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/agent/agent.py +82 -65
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/agent/agent_tool.py +152 -122
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/agent/agent_tool_v1_deprecated.py +66 -62
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/agent/clarification_protocol.py +55 -50
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/agent/clarification_tool.py +11 -10
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/agent/claude_cli_tool.py +21 -20
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/agent/claude_desktop_auth.py +130 -144
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/agent/cli_agent_base.py +59 -53
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/agent/code_auth.py +102 -107
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/agent/code_auth_tool.py +28 -27
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/agent/codex_cli_tool.py +20 -19
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/agent/critic_tool.py +86 -73
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/agent/gemini_cli_tool.py +21 -20
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/agent/grok_cli_tool.py +21 -20
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/agent/iching_tool.py +404 -139
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/agent/network_tool.py +89 -73
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/agent/prompt.py +2 -1
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/agent/review_tool.py +101 -98
- hanzo_mcp-0.8.0/hanzo_mcp/tools/agent/swarm_alias.py +87 -0
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/agent/swarm_tool.py +246 -161
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/agent/swarm_tool_v1_deprecated.py +134 -92
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/agent/tool_adapter.py +21 -11
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/common/base.py +3 -5
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/common/batch_tool.py +46 -39
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/common/config_tool.py +120 -84
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/common/context.py +1 -5
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/common/context_fix.py +5 -3
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/common/critic_tool.py +4 -8
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/common/decorators.py +58 -56
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/common/enhanced_base.py +29 -32
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/common/fastmcp_pagination.py +91 -94
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/common/forgiving_edit.py +91 -87
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/common/mode.py +15 -17
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/common/mode_loader.py +27 -24
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/common/paginated_base.py +61 -53
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/common/paginated_response.py +72 -79
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/common/pagination.py +50 -53
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/common/permissions.py +4 -4
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/common/personality.py +186 -138
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/common/plugin_loader.py +54 -54
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/common/stats.py +65 -47
- hanzo_mcp-0.8.0/hanzo_mcp/tools/common/test_helpers.py +31 -0
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/common/thinking_tool.py +4 -8
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/common/tool_disable.py +17 -12
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/common/tool_enable.py +13 -14
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/common/tool_list.py +36 -28
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/common/truncate.py +23 -23
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/config/__init__.py +4 -4
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/config/config_tool.py +42 -29
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/config/index_config.py +37 -34
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/config/mode_tool.py +175 -55
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/database/__init__.py +15 -12
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/database/database_manager.py +77 -75
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/database/graph.py +137 -91
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/database/graph_add.py +30 -18
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/database/graph_query.py +178 -102
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/database/graph_remove.py +33 -28
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/database/graph_search.py +97 -75
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/database/graph_stats.py +91 -59
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/database/sql.py +107 -79
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/database/sql_query.py +30 -24
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/database/sql_search.py +29 -25
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/database/sql_stats.py +47 -35
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/editor/neovim_command.py +25 -28
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/editor/neovim_edit.py +21 -23
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/editor/neovim_session.py +60 -54
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/filesystem/__init__.py +31 -30
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/filesystem/ast_multi_edit.py +329 -249
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/filesystem/ast_tool.py +4 -4
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/filesystem/batch_search.py +316 -224
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/filesystem/content_replace.py +4 -4
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/filesystem/diff.py +71 -59
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/filesystem/directory_tree.py +7 -7
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/filesystem/directory_tree_paginated.py +49 -37
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/filesystem/edit.py +4 -4
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/filesystem/find.py +173 -80
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/filesystem/find_files.py +73 -52
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/filesystem/git_search.py +157 -104
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/filesystem/grep.py +8 -8
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/filesystem/multi_edit.py +4 -8
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/filesystem/read.py +12 -10
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/filesystem/rules_tool.py +59 -43
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/filesystem/search_tool.py +263 -207
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/filesystem/symbols_tool.py +94 -54
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/filesystem/tree.py +35 -33
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/filesystem/unix_aliases.py +13 -18
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/filesystem/watch.py +37 -36
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/filesystem/write.py +4 -8
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/jupyter/__init__.py +4 -4
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/jupyter/base.py +4 -5
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/jupyter/jupyter.py +67 -47
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/jupyter/notebook_edit.py +4 -4
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/jupyter/notebook_read.py +4 -7
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/llm/__init__.py +5 -7
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/llm/consensus_tool.py +72 -52
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/llm/llm_manage.py +101 -60
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/llm/llm_tool.py +226 -166
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/llm/provider_tools.py +25 -26
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/lsp/__init__.py +1 -1
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/lsp/lsp_tool.py +228 -143
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/mcp/__init__.py +2 -3
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/mcp/mcp_add.py +27 -25
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/mcp/mcp_remove.py +7 -8
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/mcp/mcp_stats.py +23 -22
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/mcp/mcp_tool.py +129 -98
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/memory/__init__.py +39 -21
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/memory/knowledge_tools.py +124 -99
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/memory/memory_tools.py +90 -108
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/search/__init__.py +7 -2
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/search/find_tool.py +297 -212
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/search/unified_search.py +366 -314
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/shell/__init__.py +8 -7
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/shell/auto_background.py +56 -49
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/shell/base.py +1 -1
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/shell/base_process.py +75 -75
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/shell/bash_session.py +2 -2
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/shell/bash_session_executor.py +4 -4
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/shell/bash_tool.py +24 -31
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/shell/command_executor.py +12 -12
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/shell/logs.py +43 -33
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/shell/npx.py +13 -13
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/shell/npx_background.py +24 -21
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/shell/npx_tool.py +18 -22
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/shell/open.py +19 -21
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/shell/pkill.py +31 -26
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/shell/process_tool.py +32 -32
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/shell/processes.py +57 -58
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/shell/run_background.py +24 -25
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/shell/run_command.py +5 -5
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/shell/run_command_windows.py +5 -5
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/shell/session_storage.py +3 -3
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/shell/streaming_command.py +141 -126
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/shell/uvx.py +24 -25
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/shell/uvx_background.py +35 -33
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/shell/uvx_tool.py +18 -22
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/todo/__init__.py +6 -2
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/todo/todo.py +50 -37
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/todo/todo_read.py +5 -8
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/todo/todo_write.py +5 -7
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/vector/__init__.py +40 -28
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/vector/ast_analyzer.py +176 -143
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/vector/git_ingester.py +170 -179
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/vector/index_tool.py +96 -44
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/vector/infinity_store.py +283 -228
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/vector/mock_infinity.py +39 -40
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/vector/project_manager.py +88 -78
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/vector/vector.py +59 -42
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/vector/vector_index.py +30 -27
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/vector/vector_search.py +64 -45
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/types.py +6 -4
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp.egg-info/PKG-INFO +1 -1
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp.egg-info/SOURCES.txt +6 -0
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/pyproject.toml +1 -1
- hanzo_mcp-0.8.0/tests/test_agent_tools_ci.py +171 -0
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/tests/test_async_support.py +1 -0
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/tests/test_batch_tool_edge_cases.py +79 -90
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/tests/test_cli.py +103 -107
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/tests/test_cli_agents.py +93 -83
- hanzo_mcp-0.8.0/tests/test_e2e_demo.py +207 -0
- hanzo_mcp-0.8.0/tests/test_e2e_simple.py +86 -0
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/tests/test_failure_cases.py +50 -49
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/tests/test_find_tool_ffind.py +103 -106
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/tests/test_find_tool_integration.py +83 -146
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/tests/test_find_tool_registration.py +33 -42
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/tests/test_git_ingestion.py +168 -129
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/tests/test_hanzo_agents_integration.py +24 -21
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/tests/test_hanzo_mcp_integration.py +79 -89
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/tests/test_hanzo_mcp_local.py +56 -80
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/tests/test_hanzo_mcp_simple.py +51 -55
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/tests/test_hanzo_network_integration.py +164 -182
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/tests/test_litellm_warnings.py +18 -15
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/tests/test_lsp_tool.py +36 -47
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/tests/test_manual.py +36 -31
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/tests/test_memory_basic.py +28 -18
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/tests/test_memory_edge_cases.py +189 -183
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/tests/test_memory_simple.py +7 -11
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/tests/test_memory_tools.py +85 -60
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/tests/test_memory_tools_comprehensive.py +305 -273
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/tests/test_memory_utils.py +8 -4
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/tests/test_new_tools.py +153 -183
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/tests/test_performance.py +154 -145
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/tests/test_search.py +153 -135
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/tests/test_search_quality.py +201 -138
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/tests/test_shell_features.py +62 -70
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/tests/test_simple.py +64 -58
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/tests/test_stdio_protocol.py +37 -43
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/tests/test_stdio_simple.py +15 -13
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/tests/test_streaming_command.py +64 -70
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/tests/test_swarm_simple.py +73 -61
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/tests/test_tools_suite.py +220 -241
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/tests/test_unified_search.py +48 -75
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/tests/test_utils.py +72 -58
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/tests/test_vector_store.py +97 -99
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/tests/test_web3_integration.py +113 -126
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/README.md +0 -0
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/prompts/compact_conversation.py +0 -0
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/prompts/create_release.py +0 -0
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/prompts/project_system.py +0 -0
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/prompts/utils.py +0 -0
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/common/__init__.py +1 -1
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/common/validation.py +0 -0
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/editor/__init__.py +0 -0
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/filesystem/base.py +1 -1
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/shell/session_manager.py +0 -0
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp/tools/todo/base.py +0 -0
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp.egg-info/dependency_links.txt +0 -0
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp.egg-info/entry_points.txt +0 -0
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp.egg-info/requires.txt +0 -0
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/hanzo_mcp.egg-info/top_level.txt +0 -0
- {hanzo_mcp-0.7.7 → hanzo_mcp-0.8.0}/setup.cfg +0 -0
|
@@ -2,9 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
# Configure FastMCP logging globally for stdio transport
|
|
4
4
|
import os
|
|
5
|
+
import warnings
|
|
6
|
+
|
|
7
|
+
# Suppress litellm deprecation warnings about event loop
|
|
8
|
+
warnings.filterwarnings("ignore", message="There is no current event loop", category=DeprecationWarning)
|
|
9
|
+
|
|
5
10
|
if os.environ.get("HANZO_MCP_TRANSPORT") == "stdio":
|
|
6
11
|
try:
|
|
7
12
|
from fastmcp.utilities.logging import configure_logging
|
|
13
|
+
|
|
8
14
|
configure_logging(level="ERROR")
|
|
9
15
|
except ImportError:
|
|
10
16
|
pass
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"""Analytics module for Hanzo MCP using PostHog."""
|
|
2
2
|
|
|
3
|
-
from .posthog_analytics import Analytics, track_event, track_tool_usage
|
|
3
|
+
from .posthog_analytics import Analytics, track_error, track_event, track_tool_usage
|
|
4
4
|
|
|
5
|
-
__all__ = ["Analytics", "track_event", "track_tool_usage", "track_error"]
|
|
5
|
+
__all__ = ["Analytics", "track_event", "track_tool_usage", "track_error"]
|
|
@@ -9,29 +9,31 @@ This module provides analytics tracking for:
|
|
|
9
9
|
|
|
10
10
|
import os
|
|
11
11
|
import time
|
|
12
|
+
import asyncio
|
|
13
|
+
import platform
|
|
12
14
|
import functools
|
|
13
15
|
import traceback
|
|
14
|
-
from typing import
|
|
16
|
+
from typing import Any, Dict, TypeVar, Callable, Optional
|
|
15
17
|
from datetime import datetime
|
|
16
|
-
import platform
|
|
17
|
-
import asyncio
|
|
18
18
|
from dataclasses import dataclass
|
|
19
19
|
|
|
20
20
|
# Try to import PostHog, but make it optional
|
|
21
21
|
try:
|
|
22
22
|
from posthog import Posthog
|
|
23
|
+
|
|
23
24
|
POSTHOG_AVAILABLE = True
|
|
24
25
|
except ImportError:
|
|
25
26
|
POSTHOG_AVAILABLE = False
|
|
26
27
|
Posthog = None
|
|
27
28
|
|
|
28
29
|
|
|
29
|
-
F = TypeVar(
|
|
30
|
+
F = TypeVar("F", bound=Callable[..., Any])
|
|
30
31
|
|
|
31
32
|
|
|
32
33
|
@dataclass
|
|
33
34
|
class AnalyticsConfig:
|
|
34
35
|
"""Configuration for analytics."""
|
|
36
|
+
|
|
35
37
|
api_key: Optional[str] = None
|
|
36
38
|
host: str = "https://us.i.posthog.com"
|
|
37
39
|
enabled: bool = True
|
|
@@ -39,56 +41,57 @@ class AnalyticsConfig:
|
|
|
39
41
|
capture_errors: bool = True
|
|
40
42
|
capture_performance: bool = True
|
|
41
43
|
distinct_id: Optional[str] = None
|
|
42
|
-
|
|
44
|
+
|
|
43
45
|
|
|
44
46
|
class Analytics:
|
|
45
47
|
"""Main analytics class for Hanzo MCP."""
|
|
46
|
-
|
|
48
|
+
|
|
47
49
|
def __init__(self, config: Optional[AnalyticsConfig] = None):
|
|
48
50
|
"""Initialize analytics with configuration."""
|
|
49
51
|
self.config = config or AnalyticsConfig()
|
|
50
52
|
self._client = None
|
|
51
|
-
|
|
53
|
+
|
|
52
54
|
# Load from environment if not provided
|
|
53
55
|
if not self.config.api_key:
|
|
54
56
|
self.config.api_key = os.environ.get("POSTHOG_API_KEY")
|
|
55
|
-
|
|
57
|
+
|
|
56
58
|
if not self.config.distinct_id:
|
|
57
59
|
# Use machine ID or generate one
|
|
58
60
|
self.config.distinct_id = self._get_distinct_id()
|
|
59
|
-
|
|
61
|
+
|
|
60
62
|
# Initialize PostHog if available and configured
|
|
61
63
|
if POSTHOG_AVAILABLE and self.config.api_key and self.config.enabled:
|
|
62
64
|
self._client = Posthog(
|
|
63
65
|
self.config.api_key,
|
|
64
66
|
host=self.config.host,
|
|
65
67
|
debug=self.config.debug,
|
|
66
|
-
enable_exception_autocapture=self.config.capture_errors
|
|
68
|
+
enable_exception_autocapture=self.config.capture_errors,
|
|
67
69
|
)
|
|
68
|
-
|
|
70
|
+
|
|
69
71
|
def _get_distinct_id(self) -> str:
|
|
70
72
|
"""Get a distinct ID for this installation."""
|
|
71
73
|
# Try to get from environment
|
|
72
74
|
distinct_id = os.environ.get("HANZO_DISTINCT_ID")
|
|
73
75
|
if distinct_id:
|
|
74
76
|
return distinct_id
|
|
75
|
-
|
|
77
|
+
|
|
76
78
|
# Use hostname + username as fallback
|
|
77
79
|
import socket
|
|
78
80
|
import getpass
|
|
81
|
+
|
|
79
82
|
hostname = socket.gethostname()
|
|
80
83
|
username = getpass.getuser()
|
|
81
84
|
return f"{hostname}:{username}"
|
|
82
|
-
|
|
85
|
+
|
|
83
86
|
def is_enabled(self) -> bool:
|
|
84
87
|
"""Check if analytics is enabled."""
|
|
85
88
|
return bool(self._client and self.config.enabled)
|
|
86
|
-
|
|
89
|
+
|
|
87
90
|
def capture(self, event: str, properties: Optional[Dict[str, Any]] = None) -> None:
|
|
88
91
|
"""Capture an analytics event."""
|
|
89
92
|
if not self.is_enabled():
|
|
90
93
|
return
|
|
91
|
-
|
|
94
|
+
|
|
92
95
|
try:
|
|
93
96
|
# Add common properties
|
|
94
97
|
props = {
|
|
@@ -96,97 +99,84 @@ class Analytics:
|
|
|
96
99
|
"platform": platform.system(),
|
|
97
100
|
"python_version": platform.python_version(),
|
|
98
101
|
"mcp_version": "0.6.13", # TODO: Get from package
|
|
99
|
-
**(properties or {})
|
|
102
|
+
**(properties or {}),
|
|
100
103
|
}
|
|
101
|
-
|
|
102
|
-
self._client.capture(
|
|
103
|
-
self.config.distinct_id,
|
|
104
|
-
event,
|
|
105
|
-
properties=props
|
|
106
|
-
)
|
|
104
|
+
|
|
105
|
+
self._client.capture(self.config.distinct_id, event, properties=props)
|
|
107
106
|
except Exception as e:
|
|
108
107
|
if self.config.debug:
|
|
109
108
|
print(f"Analytics error: {e}")
|
|
110
|
-
|
|
109
|
+
|
|
111
110
|
def identify(self, properties: Optional[Dict[str, Any]] = None) -> None:
|
|
112
111
|
"""Identify the current user/installation."""
|
|
113
112
|
if not self.is_enabled():
|
|
114
113
|
return
|
|
115
|
-
|
|
114
|
+
|
|
116
115
|
try:
|
|
117
|
-
self._client.identify(
|
|
118
|
-
self.config.distinct_id,
|
|
119
|
-
properties=properties or {}
|
|
120
|
-
)
|
|
116
|
+
self._client.identify(self.config.distinct_id, properties=properties or {})
|
|
121
117
|
except Exception as e:
|
|
122
118
|
if self.config.debug:
|
|
123
119
|
print(f"Analytics identify error: {e}")
|
|
124
|
-
|
|
125
|
-
def track_tool_usage(
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
120
|
+
|
|
121
|
+
def track_tool_usage(
|
|
122
|
+
self,
|
|
123
|
+
tool_name: str,
|
|
124
|
+
duration_ms: Optional[float] = None,
|
|
125
|
+
success: bool = True,
|
|
126
|
+
error: Optional[str] = None,
|
|
127
|
+
metadata: Optional[Dict[str, Any]] = None,
|
|
128
|
+
) -> None:
|
|
131
129
|
"""Track tool usage event."""
|
|
132
|
-
properties = {
|
|
133
|
-
|
|
134
|
-
"success": success,
|
|
135
|
-
**(metadata or {})
|
|
136
|
-
}
|
|
137
|
-
|
|
130
|
+
properties = {"tool_name": tool_name, "success": success, **(metadata or {})}
|
|
131
|
+
|
|
138
132
|
if duration_ms is not None:
|
|
139
133
|
properties["duration_ms"] = duration_ms
|
|
140
|
-
|
|
134
|
+
|
|
141
135
|
if error:
|
|
142
136
|
properties["error"] = str(error)
|
|
143
|
-
|
|
137
|
+
|
|
144
138
|
self.capture("tool_used", properties)
|
|
145
|
-
|
|
146
|
-
def track_error(
|
|
147
|
-
|
|
148
|
-
|
|
139
|
+
|
|
140
|
+
def track_error(
|
|
141
|
+
self, error: Exception, context: Optional[Dict[str, Any]] = None
|
|
142
|
+
) -> None:
|
|
149
143
|
"""Track an error event."""
|
|
150
144
|
if not self.config.capture_errors:
|
|
151
145
|
return
|
|
152
|
-
|
|
146
|
+
|
|
153
147
|
properties = {
|
|
154
148
|
"error_type": type(error).__name__,
|
|
155
149
|
"error_message": str(error),
|
|
156
150
|
"error_traceback": traceback.format_exc(),
|
|
157
|
-
**(context or {})
|
|
151
|
+
**(context or {}),
|
|
158
152
|
}
|
|
159
|
-
|
|
153
|
+
|
|
160
154
|
self.capture("error_occurred", properties)
|
|
161
|
-
|
|
155
|
+
|
|
162
156
|
def feature_enabled(self, flag_key: str, default: bool = False) -> bool:
|
|
163
157
|
"""Check if a feature flag is enabled."""
|
|
164
158
|
if not self.is_enabled():
|
|
165
159
|
return default
|
|
166
|
-
|
|
160
|
+
|
|
167
161
|
try:
|
|
168
162
|
return self._client.feature_enabled(
|
|
169
|
-
flag_key,
|
|
170
|
-
self.config.distinct_id,
|
|
171
|
-
default=default
|
|
163
|
+
flag_key, self.config.distinct_id, default=default
|
|
172
164
|
)
|
|
173
165
|
except Exception:
|
|
174
166
|
return default
|
|
175
|
-
|
|
167
|
+
|
|
176
168
|
def get_feature_flag(self, flag_key: str, default: Any = None) -> Any:
|
|
177
169
|
"""Get feature flag value."""
|
|
178
170
|
if not self.is_enabled():
|
|
179
171
|
return default
|
|
180
|
-
|
|
172
|
+
|
|
181
173
|
try:
|
|
182
174
|
return self._client.get_feature_flag(
|
|
183
|
-
flag_key,
|
|
184
|
-
self.config.distinct_id,
|
|
185
|
-
default=default
|
|
175
|
+
flag_key, self.config.distinct_id, default=default
|
|
186
176
|
)
|
|
187
177
|
except Exception:
|
|
188
178
|
return default
|
|
189
|
-
|
|
179
|
+
|
|
190
180
|
def flush(self) -> None:
|
|
191
181
|
"""Flush any pending events."""
|
|
192
182
|
if self.is_enabled():
|
|
@@ -194,7 +184,7 @@ class Analytics:
|
|
|
194
184
|
self._client.flush()
|
|
195
185
|
except Exception:
|
|
196
186
|
pass
|
|
197
|
-
|
|
187
|
+
|
|
198
188
|
def shutdown(self) -> None:
|
|
199
189
|
"""Shutdown analytics client."""
|
|
200
190
|
if self.is_enabled():
|
|
@@ -233,6 +223,7 @@ def track_error(error: Exception, context: Optional[Dict[str, Any]] = None) -> N
|
|
|
233
223
|
|
|
234
224
|
def with_analytics(tool_name: str):
|
|
235
225
|
"""Decorator to track tool usage with analytics."""
|
|
226
|
+
|
|
236
227
|
def decorator(func: F) -> F:
|
|
237
228
|
@functools.wraps(func)
|
|
238
229
|
async def async_wrapper(*args, **kwargs):
|
|
@@ -251,9 +242,9 @@ def with_analytics(tool_name: str):
|
|
|
251
242
|
tool_name,
|
|
252
243
|
duration_ms=duration_ms,
|
|
253
244
|
success=error is None,
|
|
254
|
-
error=str(error) if error else None
|
|
245
|
+
error=str(error) if error else None,
|
|
255
246
|
)
|
|
256
|
-
|
|
247
|
+
|
|
257
248
|
@functools.wraps(func)
|
|
258
249
|
def sync_wrapper(*args, **kwargs):
|
|
259
250
|
start_time = time.time()
|
|
@@ -271,20 +262,21 @@ def with_analytics(tool_name: str):
|
|
|
271
262
|
tool_name,
|
|
272
263
|
duration_ms=duration_ms,
|
|
273
264
|
success=error is None,
|
|
274
|
-
error=str(error) if error else None
|
|
265
|
+
error=str(error) if error else None,
|
|
275
266
|
)
|
|
276
|
-
|
|
267
|
+
|
|
277
268
|
# Return appropriate wrapper based on function type
|
|
278
269
|
if asyncio.iscoroutinefunction(func):
|
|
279
270
|
return async_wrapper
|
|
280
271
|
else:
|
|
281
272
|
return sync_wrapper
|
|
282
|
-
|
|
273
|
+
|
|
283
274
|
return decorator
|
|
284
275
|
|
|
285
276
|
|
|
286
277
|
def feature_flag(flag_key: str, default: bool = False):
|
|
287
278
|
"""Decorator to conditionally enable features based on flags."""
|
|
279
|
+
|
|
288
280
|
def decorator(func: F) -> F:
|
|
289
281
|
@functools.wraps(func)
|
|
290
282
|
def wrapper(*args, **kwargs):
|
|
@@ -292,40 +284,42 @@ def feature_flag(flag_key: str, default: bool = False):
|
|
|
292
284
|
return func(*args, **kwargs)
|
|
293
285
|
else:
|
|
294
286
|
raise NotImplementedError(f"Feature '{flag_key}' is not enabled")
|
|
287
|
+
|
|
295
288
|
return wrapper
|
|
289
|
+
|
|
296
290
|
return decorator
|
|
297
291
|
|
|
298
292
|
|
|
299
293
|
# Tool usage context manager
|
|
300
294
|
class ToolUsageTracker:
|
|
301
295
|
"""Context manager for tracking tool usage."""
|
|
302
|
-
|
|
296
|
+
|
|
303
297
|
def __init__(self, tool_name: str, metadata: Optional[Dict[str, Any]] = None):
|
|
304
298
|
self.tool_name = tool_name
|
|
305
299
|
self.metadata = metadata or {}
|
|
306
300
|
self.start_time = None
|
|
307
301
|
self.error = None
|
|
308
|
-
|
|
302
|
+
|
|
309
303
|
def __enter__(self):
|
|
310
304
|
self.start_time = time.time()
|
|
311
305
|
return self
|
|
312
|
-
|
|
306
|
+
|
|
313
307
|
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
314
308
|
duration_ms = (time.time() - self.start_time) * 1000
|
|
315
309
|
success = exc_type is None
|
|
316
|
-
|
|
310
|
+
|
|
317
311
|
if exc_type:
|
|
318
312
|
self.error = str(exc_val)
|
|
319
313
|
track_error(exc_val, {"tool": self.tool_name, **self.metadata})
|
|
320
|
-
|
|
314
|
+
|
|
321
315
|
track_tool_usage(
|
|
322
316
|
self.tool_name,
|
|
323
317
|
duration_ms=duration_ms,
|
|
324
318
|
success=success,
|
|
325
319
|
error=self.error,
|
|
326
|
-
metadata=self.metadata
|
|
320
|
+
metadata=self.metadata,
|
|
327
321
|
)
|
|
328
|
-
|
|
322
|
+
|
|
329
323
|
# Don't suppress exceptions
|
|
330
324
|
return False
|
|
331
325
|
|
|
@@ -333,32 +327,32 @@ class ToolUsageTracker:
|
|
|
333
327
|
# Async context manager version
|
|
334
328
|
class AsyncToolUsageTracker:
|
|
335
329
|
"""Async context manager for tracking tool usage."""
|
|
336
|
-
|
|
330
|
+
|
|
337
331
|
def __init__(self, tool_name: str, metadata: Optional[Dict[str, Any]] = None):
|
|
338
332
|
self.tool_name = tool_name
|
|
339
333
|
self.metadata = metadata or {}
|
|
340
334
|
self.start_time = None
|
|
341
335
|
self.error = None
|
|
342
|
-
|
|
336
|
+
|
|
343
337
|
async def __aenter__(self):
|
|
344
338
|
self.start_time = time.time()
|
|
345
339
|
return self
|
|
346
|
-
|
|
340
|
+
|
|
347
341
|
async def __aexit__(self, exc_type, exc_val, exc_tb):
|
|
348
342
|
duration_ms = (time.time() - self.start_time) * 1000
|
|
349
343
|
success = exc_type is None
|
|
350
|
-
|
|
344
|
+
|
|
351
345
|
if exc_type:
|
|
352
346
|
self.error = str(exc_val)
|
|
353
347
|
track_error(exc_val, {"tool": self.tool_name, **self.metadata})
|
|
354
|
-
|
|
348
|
+
|
|
355
349
|
track_tool_usage(
|
|
356
350
|
self.tool_name,
|
|
357
351
|
duration_ms=duration_ms,
|
|
358
352
|
success=success,
|
|
359
353
|
error=self.error,
|
|
360
|
-
metadata=self.metadata
|
|
354
|
+
metadata=self.metadata,
|
|
361
355
|
)
|
|
362
|
-
|
|
356
|
+
|
|
363
357
|
# Don't suppress exceptions
|
|
364
|
-
return False
|
|
358
|
+
return False
|
|
@@ -1,57 +1,59 @@
|
|
|
1
1
|
"""Command-line interface for the Hanzo AI server."""
|
|
2
2
|
|
|
3
|
-
import argparse
|
|
4
|
-
import json
|
|
5
|
-
import logging
|
|
6
3
|
import os
|
|
7
|
-
import signal
|
|
8
4
|
import sys
|
|
9
|
-
|
|
5
|
+
import json
|
|
6
|
+
import signal
|
|
7
|
+
import logging
|
|
8
|
+
import argparse
|
|
10
9
|
from typing import Any, cast
|
|
10
|
+
from pathlib import Path
|
|
11
11
|
|
|
12
12
|
from hanzo_mcp.server import HanzoMCPServer
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
def main() -> None:
|
|
16
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
|
|
20
|
+
|
|
20
21
|
early_parser = argparse.ArgumentParser(add_help=False)
|
|
21
22
|
early_parser.add_argument("--transport", choices=["stdio", "sse"], default="stdio")
|
|
22
23
|
early_args, _ = early_parser.parse_known_args()
|
|
23
|
-
|
|
24
|
+
|
|
24
25
|
# Configure logging VERY early based on transport
|
|
25
26
|
if early_args.transport == "stdio":
|
|
26
27
|
# Set environment variable for server to detect stdio mode
|
|
27
28
|
import os
|
|
29
|
+
|
|
28
30
|
os.environ["HANZO_MCP_TRANSPORT"] = "stdio"
|
|
29
|
-
|
|
31
|
+
|
|
30
32
|
# For stdio transport, disable ALL logging immediately
|
|
31
33
|
from fastmcp.utilities.logging import configure_logging
|
|
34
|
+
|
|
32
35
|
# Set to ERROR to suppress INFO/WARNING messages from FastMCP
|
|
33
36
|
configure_logging(level="ERROR")
|
|
34
|
-
|
|
37
|
+
|
|
35
38
|
# Also configure standard logging to ERROR level
|
|
36
39
|
logging.basicConfig(
|
|
37
40
|
level=logging.ERROR, # Only show errors
|
|
38
|
-
handlers=[] # No handlers for stdio to prevent protocol corruption
|
|
41
|
+
handlers=[], # No handlers for stdio to prevent protocol corruption
|
|
39
42
|
)
|
|
40
|
-
|
|
43
|
+
|
|
41
44
|
# Redirect stderr to devnull for stdio transport to prevent any output
|
|
42
45
|
import sys
|
|
43
|
-
|
|
44
|
-
|
|
46
|
+
|
|
47
|
+
sys.stderr = open(os.devnull, "w")
|
|
48
|
+
|
|
45
49
|
from hanzo_mcp import __version__
|
|
46
|
-
|
|
50
|
+
|
|
47
51
|
parser = argparse.ArgumentParser(
|
|
48
52
|
description="MCP server implementing Hanzo AI capabilities"
|
|
49
53
|
)
|
|
50
|
-
|
|
54
|
+
|
|
51
55
|
parser.add_argument(
|
|
52
|
-
"--version",
|
|
53
|
-
action="version",
|
|
54
|
-
version=f"hanzo-mcp {__version__}"
|
|
56
|
+
"--version", action="version", version=f"hanzo-mcp {__version__}"
|
|
55
57
|
)
|
|
56
58
|
|
|
57
59
|
_ = parser.add_argument(
|
|
@@ -188,7 +190,7 @@ def main() -> None:
|
|
|
188
190
|
action="store_true",
|
|
189
191
|
help="Run in development mode with hot reload",
|
|
190
192
|
)
|
|
191
|
-
|
|
193
|
+
|
|
192
194
|
_ = parser.add_argument(
|
|
193
195
|
"--install",
|
|
194
196
|
action="store_true",
|
|
@@ -232,27 +234,22 @@ def main() -> None:
|
|
|
232
234
|
|
|
233
235
|
if install:
|
|
234
236
|
install_claude_desktop_config(
|
|
235
|
-
name,
|
|
236
|
-
allowed_paths,
|
|
237
|
-
disable_write_tools,
|
|
238
|
-
disable_search_tools,
|
|
239
|
-
host,
|
|
240
|
-
port
|
|
237
|
+
name, allowed_paths, disable_write_tools, disable_search_tools, host, port
|
|
241
238
|
)
|
|
242
239
|
return
|
|
243
240
|
|
|
244
241
|
# Get logger
|
|
245
242
|
logger = logging.getLogger(__name__)
|
|
246
|
-
|
|
243
|
+
|
|
247
244
|
# Set up signal handler to ensure clean exit
|
|
248
245
|
def signal_handler(signum, frame):
|
|
249
246
|
if transport != "stdio":
|
|
250
247
|
logger.info("\nReceived interrupt signal, shutting down...")
|
|
251
248
|
sys.exit(0)
|
|
252
|
-
|
|
249
|
+
|
|
253
250
|
signal.signal(signal.SIGINT, signal_handler)
|
|
254
251
|
signal.signal(signal.SIGTERM, signal_handler)
|
|
255
|
-
|
|
252
|
+
|
|
256
253
|
# Configure logging based on transport (stdio already configured early)
|
|
257
254
|
if transport != "stdio":
|
|
258
255
|
# For SSE transport, logging is fine
|
|
@@ -260,11 +257,11 @@ def main() -> None:
|
|
|
260
257
|
"DEBUG": logging.DEBUG,
|
|
261
258
|
"INFO": logging.INFO,
|
|
262
259
|
"WARNING": logging.WARNING,
|
|
263
|
-
"ERROR": logging.ERROR
|
|
260
|
+
"ERROR": logging.ERROR,
|
|
264
261
|
}
|
|
265
262
|
logging.basicConfig(
|
|
266
263
|
level=log_level_map.get(log_level, logging.INFO),
|
|
267
|
-
format=
|
|
264
|
+
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
|
|
268
265
|
)
|
|
269
266
|
|
|
270
267
|
# If no allowed paths are specified, use the current directory
|
|
@@ -274,7 +271,7 @@ def main() -> None:
|
|
|
274
271
|
# Run in dev mode if requested
|
|
275
272
|
if dev:
|
|
276
273
|
from hanzo_mcp.dev_server import DevServer
|
|
277
|
-
|
|
274
|
+
|
|
278
275
|
dev_server = DevServer(
|
|
279
276
|
name=name,
|
|
280
277
|
allowed_paths=allowed_paths,
|
|
@@ -315,7 +312,7 @@ def main() -> None:
|
|
|
315
312
|
host=host,
|
|
316
313
|
port=port,
|
|
317
314
|
)
|
|
318
|
-
|
|
315
|
+
|
|
319
316
|
try:
|
|
320
317
|
# Transport will be automatically cast to Literal['stdio', 'sse'] by the server
|
|
321
318
|
server.run(transport=transport)
|
|
@@ -378,7 +375,7 @@ def install_claude_desktop_config(
|
|
|
378
375
|
# Add tool disable flags if specified
|
|
379
376
|
if disable_write_tools:
|
|
380
377
|
args.append("--disable-write-tools")
|
|
381
|
-
|
|
378
|
+
|
|
382
379
|
if disable_search_tools:
|
|
383
380
|
args.append("--disable-search-tools")
|
|
384
381
|
|
|
@@ -419,9 +416,7 @@ def install_claude_desktop_config(
|
|
|
419
416
|
else:
|
|
420
417
|
logger.info(f"\nDefault allowed path: {home}")
|
|
421
418
|
|
|
422
|
-
logger.info(
|
|
423
|
-
"\nYou can modify allowed paths in the config file directly."
|
|
424
|
-
)
|
|
419
|
+
logger.info("\nYou can modify allowed paths in the config file directly.")
|
|
425
420
|
logger.info("Restart Claude Desktop for changes to take effect.")
|
|
426
421
|
|
|
427
422
|
|