hanzo-mcp 0.8.11__py3-none-any.whl → 0.8.14__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.
- hanzo_mcp/__init__.py +2 -4
- hanzo_mcp/analytics/posthog_analytics.py +3 -9
- hanzo_mcp/bridge.py +9 -25
- hanzo_mcp/cli.py +6 -15
- hanzo_mcp/cli_enhanced.py +5 -14
- hanzo_mcp/cli_plugin.py +3 -9
- hanzo_mcp/config/settings.py +6 -20
- hanzo_mcp/config/tool_config.py +1 -3
- hanzo_mcp/core/base_agent.py +88 -88
- hanzo_mcp/core/model_registry.py +238 -210
- hanzo_mcp/dev_server.py +5 -15
- hanzo_mcp/prompts/__init__.py +2 -6
- hanzo_mcp/prompts/project_todo_reminder.py +3 -9
- hanzo_mcp/prompts/tool_explorer.py +1 -3
- hanzo_mcp/prompts/utils.py +7 -21
- hanzo_mcp/server.py +13 -6
- hanzo_mcp/tools/__init__.py +10 -24
- hanzo_mcp/tools/agent/__init__.py +2 -1
- hanzo_mcp/tools/agent/agent.py +10 -30
- hanzo_mcp/tools/agent/agent_tool.py +5 -15
- hanzo_mcp/tools/agent/agent_tool_v1_deprecated.py +14 -41
- hanzo_mcp/tools/agent/claude_desktop_auth.py +3 -9
- hanzo_mcp/tools/agent/cli_agent_base.py +7 -24
- hanzo_mcp/tools/agent/cli_tools.py +75 -74
- hanzo_mcp/tools/agent/code_auth.py +1 -3
- hanzo_mcp/tools/agent/code_auth_tool.py +2 -6
- hanzo_mcp/tools/agent/critic_tool.py +8 -24
- hanzo_mcp/tools/agent/iching_tool.py +12 -36
- hanzo_mcp/tools/agent/network_tool.py +7 -18
- hanzo_mcp/tools/agent/prompt.py +1 -5
- hanzo_mcp/tools/agent/review_tool.py +10 -25
- hanzo_mcp/tools/agent/swarm_alias.py +1 -3
- hanzo_mcp/tools/agent/swarm_tool.py +9 -29
- hanzo_mcp/tools/agent/swarm_tool_v1_deprecated.py +11 -39
- hanzo_mcp/tools/agent/unified_cli_tools.py +38 -38
- hanzo_mcp/tools/common/batch_tool.py +15 -45
- hanzo_mcp/tools/common/config_tool.py +9 -28
- hanzo_mcp/tools/common/context.py +1 -3
- hanzo_mcp/tools/common/critic_tool.py +1 -3
- hanzo_mcp/tools/common/decorators.py +2 -6
- hanzo_mcp/tools/common/enhanced_base.py +2 -6
- hanzo_mcp/tools/common/fastmcp_pagination.py +4 -12
- hanzo_mcp/tools/common/forgiving_edit.py +9 -28
- hanzo_mcp/tools/common/mode.py +1 -5
- hanzo_mcp/tools/common/paginated_base.py +3 -11
- hanzo_mcp/tools/common/paginated_response.py +10 -30
- hanzo_mcp/tools/common/pagination.py +3 -9
- hanzo_mcp/tools/common/permissions.py +38 -11
- hanzo_mcp/tools/common/personality.py +9 -34
- hanzo_mcp/tools/common/plugin_loader.py +3 -15
- hanzo_mcp/tools/common/stats.py +6 -18
- hanzo_mcp/tools/common/thinking_tool.py +1 -3
- hanzo_mcp/tools/common/tool_disable.py +2 -6
- hanzo_mcp/tools/common/tool_list.py +2 -6
- hanzo_mcp/tools/common/validation.py +1 -3
- hanzo_mcp/tools/config/config_tool.py +7 -13
- hanzo_mcp/tools/config/index_config.py +1 -3
- hanzo_mcp/tools/config/mode_tool.py +5 -15
- hanzo_mcp/tools/database/database_manager.py +3 -9
- hanzo_mcp/tools/database/graph.py +1 -3
- hanzo_mcp/tools/database/graph_add.py +3 -9
- hanzo_mcp/tools/database/graph_query.py +11 -34
- hanzo_mcp/tools/database/graph_remove.py +3 -9
- hanzo_mcp/tools/database/graph_search.py +6 -20
- hanzo_mcp/tools/database/graph_stats.py +11 -33
- hanzo_mcp/tools/database/sql.py +4 -12
- hanzo_mcp/tools/database/sql_query.py +6 -10
- hanzo_mcp/tools/database/sql_search.py +2 -6
- hanzo_mcp/tools/database/sql_stats.py +5 -15
- hanzo_mcp/tools/editor/neovim_command.py +1 -3
- hanzo_mcp/tools/editor/neovim_edit.py +2 -2
- hanzo_mcp/tools/editor/neovim_session.py +7 -13
- hanzo_mcp/tools/filesystem/__init__.py +2 -3
- hanzo_mcp/tools/filesystem/ast_multi_edit.py +14 -43
- hanzo_mcp/tools/filesystem/base.py +4 -12
- hanzo_mcp/tools/filesystem/batch_search.py +35 -115
- hanzo_mcp/tools/filesystem/content_replace.py +4 -12
- hanzo_mcp/tools/filesystem/diff.py +2 -10
- hanzo_mcp/tools/filesystem/directory_tree.py +9 -27
- hanzo_mcp/tools/filesystem/directory_tree_paginated.py +5 -15
- hanzo_mcp/tools/filesystem/edit.py +6 -18
- hanzo_mcp/tools/filesystem/find.py +3 -9
- hanzo_mcp/tools/filesystem/find_files.py +2 -6
- hanzo_mcp/tools/filesystem/git_search.py +9 -24
- hanzo_mcp/tools/filesystem/grep.py +9 -27
- hanzo_mcp/tools/filesystem/multi_edit.py +6 -18
- hanzo_mcp/tools/filesystem/read.py +8 -26
- hanzo_mcp/tools/filesystem/rules_tool.py +6 -17
- hanzo_mcp/tools/filesystem/search_tool.py +18 -62
- hanzo_mcp/tools/filesystem/symbols_tool.py +5 -15
- hanzo_mcp/tools/filesystem/tree.py +1 -3
- hanzo_mcp/tools/filesystem/watch.py +1 -3
- hanzo_mcp/tools/filesystem/write.py +1 -3
- hanzo_mcp/tools/jupyter/base.py +6 -20
- hanzo_mcp/tools/jupyter/jupyter.py +4 -12
- hanzo_mcp/tools/jupyter/notebook_edit.py +11 -35
- hanzo_mcp/tools/jupyter/notebook_read.py +2 -6
- hanzo_mcp/tools/llm/consensus_tool.py +8 -24
- hanzo_mcp/tools/llm/llm_manage.py +2 -6
- hanzo_mcp/tools/llm/llm_tool.py +17 -58
- hanzo_mcp/tools/llm/llm_unified.py +18 -59
- hanzo_mcp/tools/llm/provider_tools.py +1 -3
- hanzo_mcp/tools/lsp/lsp_tool.py +5 -17
- hanzo_mcp/tools/mcp/mcp_add.py +1 -3
- hanzo_mcp/tools/mcp/mcp_stats.py +1 -3
- hanzo_mcp/tools/mcp/mcp_tool.py +9 -23
- hanzo_mcp/tools/memory/__init__.py +10 -27
- hanzo_mcp/tools/memory/knowledge_tools.py +7 -25
- hanzo_mcp/tools/memory/memory_tools.py +6 -18
- hanzo_mcp/tools/search/find_tool.py +10 -32
- hanzo_mcp/tools/search/unified_search.py +24 -78
- hanzo_mcp/tools/shell/__init__.py +2 -2
- hanzo_mcp/tools/shell/auto_background.py +2 -6
- hanzo_mcp/tools/shell/base.py +1 -5
- hanzo_mcp/tools/shell/base_process.py +5 -7
- hanzo_mcp/tools/shell/bash_session.py +7 -24
- hanzo_mcp/tools/shell/bash_session_executor.py +5 -15
- hanzo_mcp/tools/shell/bash_tool.py +3 -7
- hanzo_mcp/tools/shell/command_executor.py +33 -86
- hanzo_mcp/tools/shell/logs.py +4 -16
- hanzo_mcp/tools/shell/npx.py +2 -8
- hanzo_mcp/tools/shell/npx_tool.py +1 -3
- hanzo_mcp/tools/shell/pkill.py +4 -12
- hanzo_mcp/tools/shell/process_tool.py +2 -8
- hanzo_mcp/tools/shell/processes.py +5 -17
- hanzo_mcp/tools/shell/run_background.py +1 -3
- hanzo_mcp/tools/shell/run_command.py +1 -3
- hanzo_mcp/tools/shell/run_command_windows.py +1 -3
- hanzo_mcp/tools/shell/session_manager.py +2 -6
- hanzo_mcp/tools/shell/session_storage.py +2 -6
- hanzo_mcp/tools/shell/streaming_command.py +7 -23
- hanzo_mcp/tools/shell/uvx.py +4 -14
- hanzo_mcp/tools/shell/uvx_background.py +2 -6
- hanzo_mcp/tools/shell/uvx_tool.py +1 -3
- hanzo_mcp/tools/shell/zsh_tool.py +12 -20
- hanzo_mcp/tools/todo/todo.py +1 -3
- hanzo_mcp/tools/todo/todo_read.py +3 -9
- hanzo_mcp/tools/todo/todo_write.py +6 -18
- hanzo_mcp/tools/vector/__init__.py +3 -9
- hanzo_mcp/tools/vector/ast_analyzer.py +6 -20
- hanzo_mcp/tools/vector/git_ingester.py +10 -30
- hanzo_mcp/tools/vector/index_tool.py +3 -9
- hanzo_mcp/tools/vector/infinity_store.py +7 -27
- hanzo_mcp/tools/vector/mock_infinity.py +1 -3
- hanzo_mcp/tools/vector/project_manager.py +4 -12
- hanzo_mcp/tools/vector/vector.py +2 -6
- hanzo_mcp/tools/vector/vector_index.py +8 -8
- hanzo_mcp/tools/vector/vector_search.py +7 -21
- {hanzo_mcp-0.8.11.dist-info → hanzo_mcp-0.8.14.dist-info}/METADATA +2 -2
- hanzo_mcp-0.8.14.dist-info/RECORD +193 -0
- hanzo_mcp-0.8.11.dist-info/RECORD +0 -193
- {hanzo_mcp-0.8.11.dist-info → hanzo_mcp-0.8.14.dist-info}/WHEEL +0 -0
- {hanzo_mcp-0.8.11.dist-info → hanzo_mcp-0.8.14.dist-info}/entry_points.txt +0 -0
- {hanzo_mcp-0.8.11.dist-info → hanzo_mcp-0.8.14.dist-info}/top_level.txt +0 -0
hanzo_mcp/core/model_registry.py
CHANGED
|
@@ -15,7 +15,7 @@ from dataclasses import field, dataclass
|
|
|
15
15
|
|
|
16
16
|
class ModelProvider(Enum):
|
|
17
17
|
"""Enumeration of AI model providers."""
|
|
18
|
-
|
|
18
|
+
|
|
19
19
|
ANTHROPIC = "anthropic"
|
|
20
20
|
OPENAI = "openai"
|
|
21
21
|
GOOGLE = "google"
|
|
@@ -30,7 +30,7 @@ class ModelProvider(Enum):
|
|
|
30
30
|
@dataclass(frozen=True)
|
|
31
31
|
class ModelConfig:
|
|
32
32
|
"""Configuration for a single AI model."""
|
|
33
|
-
|
|
33
|
+
|
|
34
34
|
full_name: str
|
|
35
35
|
provider: ModelProvider
|
|
36
36
|
aliases: Set[str] = field(default_factory=set)
|
|
@@ -46,16 +46,16 @@ class ModelConfig:
|
|
|
46
46
|
|
|
47
47
|
class ModelRegistry:
|
|
48
48
|
"""Centralized registry for all AI models.
|
|
49
|
-
|
|
49
|
+
|
|
50
50
|
Thread-safe singleton implementation ensuring single source of truth
|
|
51
51
|
for model configurations across the codebase.
|
|
52
52
|
"""
|
|
53
|
-
|
|
53
|
+
|
|
54
54
|
_instance: Optional[ModelRegistry] = None
|
|
55
55
|
_lock = threading.Lock()
|
|
56
56
|
_models: Dict[str, ModelConfig] = {}
|
|
57
57
|
_initialized = False
|
|
58
|
-
|
|
58
|
+
|
|
59
59
|
def __new__(cls) -> ModelRegistry:
|
|
60
60
|
"""Thread-safe singleton pattern."""
|
|
61
61
|
if cls._instance is None:
|
|
@@ -63,7 +63,7 @@ class ModelRegistry:
|
|
|
63
63
|
if cls._instance is None:
|
|
64
64
|
cls._instance = super().__new__(cls)
|
|
65
65
|
return cls._instance
|
|
66
|
-
|
|
66
|
+
|
|
67
67
|
def __init__(self) -> None:
|
|
68
68
|
"""Initialize model registry once."""
|
|
69
69
|
if not self._initialized:
|
|
@@ -71,225 +71,253 @@ class ModelRegistry:
|
|
|
71
71
|
if not self._initialized:
|
|
72
72
|
self._initialize_models()
|
|
73
73
|
self._initialized = True
|
|
74
|
-
|
|
74
|
+
|
|
75
75
|
def _initialize_models(self) -> None:
|
|
76
76
|
"""Initialize all model configurations."""
|
|
77
77
|
# Claude models
|
|
78
|
-
self._register(
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
78
|
+
self._register(
|
|
79
|
+
ModelConfig(
|
|
80
|
+
full_name="claude-3-5-sonnet-20241022",
|
|
81
|
+
provider=ModelProvider.ANTHROPIC,
|
|
82
|
+
aliases={"claude", "cc", "claude-code", "sonnet", "sonnet-4.1"},
|
|
83
|
+
supports_vision=True,
|
|
84
|
+
supports_tools=True,
|
|
85
|
+
context_window=200000,
|
|
86
|
+
max_output=8192,
|
|
87
|
+
api_key_env="ANTHROPIC_API_KEY",
|
|
88
|
+
cli_command="claude",
|
|
89
|
+
)
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
self._register(
|
|
93
|
+
ModelConfig(
|
|
94
|
+
full_name="claude-opus-4-1-20250805",
|
|
95
|
+
provider=ModelProvider.ANTHROPIC,
|
|
96
|
+
aliases={"opus", "opus-4.1", "claude-opus"},
|
|
97
|
+
supports_vision=True,
|
|
98
|
+
supports_tools=True,
|
|
99
|
+
context_window=200000,
|
|
100
|
+
max_output=8192,
|
|
101
|
+
api_key_env="ANTHROPIC_API_KEY",
|
|
102
|
+
cli_command="claude",
|
|
103
|
+
)
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
self._register(
|
|
107
|
+
ModelConfig(
|
|
108
|
+
full_name="claude-3-haiku-20240307",
|
|
109
|
+
provider=ModelProvider.ANTHROPIC,
|
|
110
|
+
aliases={"haiku", "claude-haiku"},
|
|
111
|
+
supports_vision=True,
|
|
112
|
+
supports_tools=True,
|
|
113
|
+
context_window=200000,
|
|
114
|
+
max_output=4096,
|
|
115
|
+
api_key_env="ANTHROPIC_API_KEY",
|
|
116
|
+
cli_command="claude",
|
|
117
|
+
)
|
|
118
|
+
)
|
|
119
|
+
|
|
114
120
|
# OpenAI models
|
|
115
|
-
self._register(
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
121
|
+
self._register(
|
|
122
|
+
ModelConfig(
|
|
123
|
+
full_name="gpt-4-turbo",
|
|
124
|
+
provider=ModelProvider.OPENAI,
|
|
125
|
+
aliases={"gpt4", "gpt-4", "codex"},
|
|
126
|
+
supports_vision=True,
|
|
127
|
+
supports_tools=True,
|
|
128
|
+
context_window=128000,
|
|
129
|
+
max_output=4096,
|
|
130
|
+
api_key_env="OPENAI_API_KEY",
|
|
131
|
+
cli_command="openai",
|
|
132
|
+
)
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
self._register(
|
|
136
|
+
ModelConfig(
|
|
137
|
+
full_name="gpt-5-turbo",
|
|
138
|
+
provider=ModelProvider.OPENAI,
|
|
139
|
+
aliases={"gpt5", "gpt-5"},
|
|
140
|
+
supports_vision=True,
|
|
141
|
+
supports_tools=True,
|
|
142
|
+
context_window=256000,
|
|
143
|
+
max_output=16384,
|
|
144
|
+
api_key_env="OPENAI_API_KEY",
|
|
145
|
+
cli_command="openai",
|
|
146
|
+
)
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
self._register(
|
|
150
|
+
ModelConfig(
|
|
151
|
+
full_name="o1-preview",
|
|
152
|
+
provider=ModelProvider.OPENAI,
|
|
153
|
+
aliases={"o1", "openai-o1"},
|
|
154
|
+
supports_vision=False,
|
|
155
|
+
supports_tools=False,
|
|
156
|
+
context_window=128000,
|
|
157
|
+
max_output=32768,
|
|
158
|
+
api_key_env="OPENAI_API_KEY",
|
|
159
|
+
cli_command="openai",
|
|
160
|
+
)
|
|
161
|
+
)
|
|
162
|
+
|
|
151
163
|
# Google models
|
|
152
|
-
self._register(
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
164
|
+
self._register(
|
|
165
|
+
ModelConfig(
|
|
166
|
+
full_name="gemini-2.0-flash-exp",
|
|
167
|
+
provider=ModelProvider.GOOGLE,
|
|
168
|
+
aliases={"gemini-2", "gemini-2.0", "gemini2"},
|
|
169
|
+
supports_vision=True,
|
|
170
|
+
supports_tools=True,
|
|
171
|
+
context_window=1000000,
|
|
172
|
+
max_output=8192,
|
|
173
|
+
api_key_env="GEMINI_API_KEY",
|
|
174
|
+
cli_command="gemini",
|
|
175
|
+
)
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
self._register(
|
|
179
|
+
ModelConfig(
|
|
180
|
+
full_name="gemini-exp-1206",
|
|
181
|
+
provider=ModelProvider.GOOGLE,
|
|
182
|
+
aliases={"gemini-2.5", "gemini-2.5-pro", "gemini-pro-2.5"},
|
|
183
|
+
supports_vision=True,
|
|
184
|
+
supports_tools=True,
|
|
185
|
+
context_window=2000000,
|
|
186
|
+
max_output=8192,
|
|
187
|
+
api_key_env="GEMINI_API_KEY",
|
|
188
|
+
cli_command="gemini",
|
|
189
|
+
)
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
self._register(
|
|
193
|
+
ModelConfig(
|
|
194
|
+
full_name="gemini-1.5-pro",
|
|
195
|
+
provider=ModelProvider.GOOGLE,
|
|
196
|
+
aliases={"gemini", "gemini-pro", "gemini-1.5"},
|
|
197
|
+
supports_vision=True,
|
|
198
|
+
supports_tools=True,
|
|
199
|
+
context_window=2000000,
|
|
200
|
+
max_output=8192,
|
|
201
|
+
api_key_env="GEMINI_API_KEY",
|
|
202
|
+
cli_command="gemini",
|
|
203
|
+
)
|
|
204
|
+
)
|
|
205
|
+
|
|
206
|
+
self._register(
|
|
207
|
+
ModelConfig(
|
|
208
|
+
full_name="gemini-1.5-flash",
|
|
209
|
+
provider=ModelProvider.GOOGLE,
|
|
210
|
+
aliases={"gemini-flash", "flash"},
|
|
211
|
+
supports_vision=True,
|
|
212
|
+
supports_tools=True,
|
|
213
|
+
context_window=1000000,
|
|
214
|
+
max_output=8192,
|
|
215
|
+
api_key_env="GEMINI_API_KEY",
|
|
216
|
+
cli_command="gemini",
|
|
217
|
+
)
|
|
218
|
+
)
|
|
219
|
+
|
|
200
220
|
# xAI models
|
|
201
|
-
self._register(
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
221
|
+
self._register(
|
|
222
|
+
ModelConfig(
|
|
223
|
+
full_name="grok-4",
|
|
224
|
+
provider=ModelProvider.XAI,
|
|
225
|
+
aliases={"grok", "xai-grok", "grok-2"}, # grok-2 for backward compat
|
|
226
|
+
supports_vision=True, # Grok-4 supports multimodal
|
|
227
|
+
supports_tools=True,
|
|
228
|
+
context_window=128000,
|
|
229
|
+
max_output=8192,
|
|
230
|
+
api_key_env="XAI_API_KEY",
|
|
231
|
+
cli_command="grok",
|
|
232
|
+
)
|
|
233
|
+
)
|
|
234
|
+
|
|
213
235
|
# Ollama models
|
|
214
|
-
self._register(
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
236
|
+
self._register(
|
|
237
|
+
ModelConfig(
|
|
238
|
+
full_name="ollama/llama-3.2-3b",
|
|
239
|
+
provider=ModelProvider.OLLAMA,
|
|
240
|
+
aliases={"llama", "llama-3.2", "llama3"},
|
|
241
|
+
supports_vision=False,
|
|
242
|
+
supports_tools=False,
|
|
243
|
+
context_window=128000,
|
|
244
|
+
max_output=4096,
|
|
245
|
+
api_key_env=None, # Local model
|
|
246
|
+
cli_command="ollama",
|
|
247
|
+
)
|
|
248
|
+
)
|
|
249
|
+
|
|
250
|
+
self._register(
|
|
251
|
+
ModelConfig(
|
|
252
|
+
full_name="ollama/mistral:7b",
|
|
253
|
+
provider=ModelProvider.MISTRAL,
|
|
254
|
+
aliases={"mistral", "mistral-7b"},
|
|
255
|
+
supports_vision=False,
|
|
256
|
+
supports_tools=False,
|
|
257
|
+
context_window=32000,
|
|
258
|
+
max_output=4096,
|
|
259
|
+
api_key_env=None, # Local model
|
|
260
|
+
cli_command="ollama",
|
|
261
|
+
)
|
|
262
|
+
)
|
|
263
|
+
|
|
238
264
|
# DeepSeek models
|
|
239
|
-
self._register(
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
265
|
+
self._register(
|
|
266
|
+
ModelConfig(
|
|
267
|
+
full_name="deepseek-coder-v2",
|
|
268
|
+
provider=ModelProvider.DEEPSEEK,
|
|
269
|
+
aliases={"deepseek", "deepseek-coder"},
|
|
270
|
+
supports_vision=False,
|
|
271
|
+
supports_tools=True,
|
|
272
|
+
context_window=128000,
|
|
273
|
+
max_output=8192,
|
|
274
|
+
api_key_env="DEEPSEEK_API_KEY",
|
|
275
|
+
cli_command="deepseek",
|
|
276
|
+
)
|
|
277
|
+
)
|
|
278
|
+
|
|
251
279
|
def _register(self, config: ModelConfig) -> None:
|
|
252
280
|
"""Register a model configuration.
|
|
253
|
-
|
|
281
|
+
|
|
254
282
|
Args:
|
|
255
283
|
config: Model configuration to register
|
|
256
284
|
"""
|
|
257
285
|
# Register by full name
|
|
258
286
|
self._models[config.full_name] = config
|
|
259
|
-
|
|
287
|
+
|
|
260
288
|
# Register all aliases
|
|
261
289
|
for alias in config.aliases:
|
|
262
290
|
self._models[alias.lower()] = config
|
|
263
|
-
|
|
291
|
+
|
|
264
292
|
def get(self, model_name: str) -> Optional[ModelConfig]:
|
|
265
293
|
"""Get model configuration by name or alias.
|
|
266
|
-
|
|
294
|
+
|
|
267
295
|
Args:
|
|
268
296
|
model_name: Model name or alias
|
|
269
|
-
|
|
297
|
+
|
|
270
298
|
Returns:
|
|
271
299
|
Model configuration or None if not found
|
|
272
300
|
"""
|
|
273
301
|
return self._models.get(model_name.lower())
|
|
274
|
-
|
|
302
|
+
|
|
275
303
|
def resolve(self, model_name: str) -> str:
|
|
276
304
|
"""Resolve model name or alias to full model name.
|
|
277
|
-
|
|
305
|
+
|
|
278
306
|
Args:
|
|
279
307
|
model_name: Model name or alias
|
|
280
|
-
|
|
308
|
+
|
|
281
309
|
Returns:
|
|
282
310
|
Full model name, or original if not found
|
|
283
311
|
"""
|
|
284
312
|
config = self.get(model_name)
|
|
285
313
|
return config.full_name if config else model_name
|
|
286
|
-
|
|
314
|
+
|
|
287
315
|
def get_by_provider(self, provider: ModelProvider) -> List[ModelConfig]:
|
|
288
316
|
"""Get all unique models for a specific provider.
|
|
289
|
-
|
|
317
|
+
|
|
290
318
|
Args:
|
|
291
319
|
provider: Model provider
|
|
292
|
-
|
|
320
|
+
|
|
293
321
|
Returns:
|
|
294
322
|
List of unique model configurations
|
|
295
323
|
"""
|
|
@@ -300,7 +328,7 @@ class ModelRegistry:
|
|
|
300
328
|
seen_names.add(config.full_name)
|
|
301
329
|
results.append(config)
|
|
302
330
|
return results
|
|
303
|
-
|
|
331
|
+
|
|
304
332
|
def get_models_supporting(
|
|
305
333
|
self,
|
|
306
334
|
vision: Optional[bool] = None,
|
|
@@ -308,61 +336,61 @@ class ModelRegistry:
|
|
|
308
336
|
streaming: Optional[bool] = None,
|
|
309
337
|
) -> List[ModelConfig]:
|
|
310
338
|
"""Get unique models supporting specific features.
|
|
311
|
-
|
|
339
|
+
|
|
312
340
|
Args:
|
|
313
341
|
vision: Filter by vision support
|
|
314
342
|
tools: Filter by tool support
|
|
315
343
|
streaming: Filter by streaming support
|
|
316
|
-
|
|
344
|
+
|
|
317
345
|
Returns:
|
|
318
346
|
List of unique matching model configurations
|
|
319
347
|
"""
|
|
320
348
|
seen_names = set()
|
|
321
349
|
results = []
|
|
322
|
-
|
|
350
|
+
|
|
323
351
|
for config in self._models.values():
|
|
324
352
|
if config.full_name in seen_names:
|
|
325
353
|
continue
|
|
326
|
-
|
|
354
|
+
|
|
327
355
|
if vision is not None and config.supports_vision != vision:
|
|
328
356
|
continue
|
|
329
357
|
if tools is not None and config.supports_tools != tools:
|
|
330
358
|
continue
|
|
331
359
|
if streaming is not None and config.supports_streaming != streaming:
|
|
332
360
|
continue
|
|
333
|
-
|
|
361
|
+
|
|
334
362
|
seen_names.add(config.full_name)
|
|
335
363
|
results.append(config)
|
|
336
|
-
|
|
364
|
+
|
|
337
365
|
return results
|
|
338
|
-
|
|
366
|
+
|
|
339
367
|
def get_api_key_env(self, model_name: str) -> Optional[str]:
|
|
340
368
|
"""Get the API key environment variable for a model.
|
|
341
|
-
|
|
369
|
+
|
|
342
370
|
Args:
|
|
343
371
|
model_name: Model name or alias
|
|
344
|
-
|
|
372
|
+
|
|
345
373
|
Returns:
|
|
346
374
|
Environment variable name or None
|
|
347
375
|
"""
|
|
348
376
|
config = self.get(model_name)
|
|
349
377
|
return config.api_key_env if config else None
|
|
350
|
-
|
|
378
|
+
|
|
351
379
|
def get_cli_command(self, model_name: str) -> Optional[str]:
|
|
352
380
|
"""Get the CLI command for a model.
|
|
353
|
-
|
|
381
|
+
|
|
354
382
|
Args:
|
|
355
383
|
model_name: Model name or alias
|
|
356
|
-
|
|
384
|
+
|
|
357
385
|
Returns:
|
|
358
386
|
CLI command or None
|
|
359
387
|
"""
|
|
360
388
|
config = self.get(model_name)
|
|
361
389
|
return config.cli_command if config else None
|
|
362
|
-
|
|
390
|
+
|
|
363
391
|
def list_all_models(self) -> List[str]:
|
|
364
392
|
"""List all unique model full names.
|
|
365
|
-
|
|
393
|
+
|
|
366
394
|
Returns:
|
|
367
395
|
Sorted list of unique full model names
|
|
368
396
|
"""
|
|
@@ -370,10 +398,10 @@ class ModelRegistry:
|
|
|
370
398
|
for config in self._models.values():
|
|
371
399
|
seen_names.add(config.full_name)
|
|
372
400
|
return sorted(list(seen_names))
|
|
373
|
-
|
|
401
|
+
|
|
374
402
|
def list_all_aliases(self) -> Dict[str, str]:
|
|
375
403
|
"""List all aliases and their full names.
|
|
376
|
-
|
|
404
|
+
|
|
377
405
|
Returns:
|
|
378
406
|
Dictionary mapping aliases to full names
|
|
379
407
|
"""
|
|
@@ -391,10 +419,10 @@ registry = ModelRegistry()
|
|
|
391
419
|
# Convenience functions
|
|
392
420
|
def resolve_model(model_name: str) -> str:
|
|
393
421
|
"""Resolve model name or alias to full model name.
|
|
394
|
-
|
|
422
|
+
|
|
395
423
|
Args:
|
|
396
424
|
model_name: Model name or alias
|
|
397
|
-
|
|
425
|
+
|
|
398
426
|
Returns:
|
|
399
427
|
Full model name
|
|
400
428
|
"""
|
|
@@ -403,10 +431,10 @@ def resolve_model(model_name: str) -> str:
|
|
|
403
431
|
|
|
404
432
|
def get_model_config(model_name: str) -> Optional[ModelConfig]:
|
|
405
433
|
"""Get model configuration.
|
|
406
|
-
|
|
434
|
+
|
|
407
435
|
Args:
|
|
408
436
|
model_name: Model name or alias
|
|
409
|
-
|
|
437
|
+
|
|
410
438
|
Returns:
|
|
411
439
|
Model configuration or None
|
|
412
440
|
"""
|
|
@@ -415,10 +443,10 @@ def get_model_config(model_name: str) -> Optional[ModelConfig]:
|
|
|
415
443
|
|
|
416
444
|
def get_api_key_env(model_name: str) -> Optional[str]:
|
|
417
445
|
"""Get API key environment variable for model.
|
|
418
|
-
|
|
446
|
+
|
|
419
447
|
Args:
|
|
420
448
|
model_name: Model name or alias
|
|
421
|
-
|
|
449
|
+
|
|
422
450
|
Returns:
|
|
423
451
|
Environment variable name or None
|
|
424
452
|
"""
|
|
@@ -433,4 +461,4 @@ __all__ = [
|
|
|
433
461
|
"resolve_model",
|
|
434
462
|
"get_model_config",
|
|
435
463
|
"get_api_key_env",
|
|
436
|
-
]
|
|
464
|
+
]
|
hanzo_mcp/dev_server.py
CHANGED
|
@@ -159,12 +159,8 @@ class DevServer:
|
|
|
159
159
|
# Since MCP servers run in the same process, we need to handle this differently
|
|
160
160
|
# For now, we'll log a message indicating a restart is needed
|
|
161
161
|
logger = logging.getLogger(__name__)
|
|
162
|
-
logger.warning(
|
|
163
|
-
|
|
164
|
-
)
|
|
165
|
-
logger.info(
|
|
166
|
-
"💡 Tip: In development, consider using the MCP test client for easier reloading."
|
|
167
|
-
)
|
|
162
|
+
logger.warning("\n⚠️ Server restart required. Please restart the MCP client to reload changes.")
|
|
163
|
+
logger.info("💡 Tip: In development, consider using the MCP test client for easier reloading.")
|
|
168
164
|
|
|
169
165
|
async def run_async(self, transport: str = "stdio"):
|
|
170
166
|
"""Run the development server asynchronously."""
|
|
@@ -218,12 +214,8 @@ def run_dev_server():
|
|
|
218
214
|
"""Entry point for development server."""
|
|
219
215
|
import argparse
|
|
220
216
|
|
|
221
|
-
parser = argparse.ArgumentParser(
|
|
222
|
-
|
|
223
|
-
)
|
|
224
|
-
parser.add_argument(
|
|
225
|
-
"--name", type=str, default="hanzo-dev", help="Name of the MCP server"
|
|
226
|
-
)
|
|
217
|
+
parser = argparse.ArgumentParser(description="Run Hanzo AI in development mode with hot reload")
|
|
218
|
+
parser.add_argument("--name", type=str, default="hanzo-dev", help="Name of the MCP server")
|
|
227
219
|
parser.add_argument("--project-dir", type=str, help="Project directory to serve")
|
|
228
220
|
parser.add_argument(
|
|
229
221
|
"--allowed-path",
|
|
@@ -239,9 +231,7 @@ def run_dev_server():
|
|
|
239
231
|
choices=["stdio", "sse"],
|
|
240
232
|
help="Transport type (default: stdio)",
|
|
241
233
|
)
|
|
242
|
-
parser.add_argument(
|
|
243
|
-
"--host", type=str, default="127.0.0.1", help="Host for SSE transport"
|
|
244
|
-
)
|
|
234
|
+
parser.add_argument("--host", type=str, default="127.0.0.1", help="Host for SSE transport")
|
|
245
235
|
parser.add_argument("--port", type=int, default=3000, help="Port for SSE transport")
|
|
246
236
|
|
|
247
237
|
args = parser.parse_args()
|