hanzo-mcp 0.3.4__tar.gz → 0.5.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.

Files changed (108) hide show
  1. {hanzo_mcp-0.3.4 → hanzo_mcp-0.5.0}/PKG-INFO +35 -3
  2. {hanzo_mcp-0.3.4 → hanzo_mcp-0.5.0}/README.md +33 -2
  3. {hanzo_mcp-0.3.4 → hanzo_mcp-0.5.0}/hanzo_mcp/__init__.py +1 -1
  4. hanzo_mcp-0.5.0/hanzo_mcp/cli.py +320 -0
  5. hanzo_mcp-0.5.0/hanzo_mcp/cli_enhanced.py +438 -0
  6. hanzo_mcp-0.5.0/hanzo_mcp/config/__init__.py +19 -0
  7. hanzo_mcp-0.5.0/hanzo_mcp/config/settings.py +388 -0
  8. hanzo_mcp-0.5.0/hanzo_mcp/config/tool_config.py +197 -0
  9. hanzo_mcp-0.5.0/hanzo_mcp/prompts/__init__.py +117 -0
  10. hanzo_mcp-0.5.0/hanzo_mcp/prompts/compact_conversation.py +77 -0
  11. hanzo_mcp-0.5.0/hanzo_mcp/prompts/create_release.py +38 -0
  12. hanzo_mcp-0.5.0/hanzo_mcp/prompts/project_system.py +120 -0
  13. hanzo_mcp-0.5.0/hanzo_mcp/prompts/project_todo_reminder.py +111 -0
  14. hanzo_mcp-0.5.0/hanzo_mcp/prompts/utils.py +286 -0
  15. hanzo_mcp-0.5.0/hanzo_mcp/server.py +204 -0
  16. hanzo_mcp-0.5.0/hanzo_mcp/tools/__init__.py +162 -0
  17. {hanzo_mcp-0.3.4 → hanzo_mcp-0.5.0}/hanzo_mcp/tools/agent/__init__.py +8 -11
  18. hanzo_mcp-0.5.0/hanzo_mcp/tools/agent/agent_tool.py +540 -0
  19. {hanzo_mcp-0.3.4 → hanzo_mcp-0.5.0}/hanzo_mcp/tools/agent/prompt.py +16 -13
  20. {hanzo_mcp-0.3.4 → hanzo_mcp-0.5.0}/hanzo_mcp/tools/agent/tool_adapter.py +9 -9
  21. hanzo_mcp-0.5.0/hanzo_mcp/tools/common/__init__.py +31 -0
  22. {hanzo_mcp-0.3.4 → hanzo_mcp-0.5.0}/hanzo_mcp/tools/common/base.py +79 -110
  23. hanzo_mcp-0.5.0/hanzo_mcp/tools/common/batch_tool.py +330 -0
  24. hanzo_mcp-0.5.0/hanzo_mcp/tools/common/context.py +182 -0
  25. {hanzo_mcp-0.3.4 → hanzo_mcp-0.5.0}/hanzo_mcp/tools/common/permissions.py +12 -12
  26. hanzo_mcp-0.5.0/hanzo_mcp/tools/common/thinking_tool.py +153 -0
  27. hanzo_mcp-0.5.0/hanzo_mcp/tools/common/validation.py +62 -0
  28. hanzo_mcp-0.5.0/hanzo_mcp/tools/filesystem/__init__.py +141 -0
  29. {hanzo_mcp-0.3.4 → hanzo_mcp-0.5.0}/hanzo_mcp/tools/filesystem/base.py +32 -24
  30. {hanzo_mcp-0.3.4 → hanzo_mcp-0.5.0}/hanzo_mcp/tools/filesystem/content_replace.py +114 -107
  31. {hanzo_mcp-0.3.4 → hanzo_mcp-0.5.0}/hanzo_mcp/tools/filesystem/directory_tree.py +129 -105
  32. hanzo_mcp-0.5.0/hanzo_mcp/tools/filesystem/edit.py +279 -0
  33. hanzo_mcp-0.5.0/hanzo_mcp/tools/filesystem/grep.py +458 -0
  34. hanzo_mcp-0.5.0/hanzo_mcp/tools/filesystem/grep_ast_tool.py +250 -0
  35. hanzo_mcp-0.5.0/hanzo_mcp/tools/filesystem/multi_edit.py +362 -0
  36. hanzo_mcp-0.5.0/hanzo_mcp/tools/filesystem/read.py +255 -0
  37. hanzo_mcp-0.5.0/hanzo_mcp/tools/filesystem/write.py +156 -0
  38. hanzo_mcp-0.5.0/hanzo_mcp/tools/jupyter/__init__.py +88 -0
  39. {hanzo_mcp-0.3.4 → hanzo_mcp-0.5.0}/hanzo_mcp/tools/jupyter/base.py +66 -57
  40. hanzo_mcp-0.3.4/hanzo_mcp/tools/jupyter/edit_notebook.py → hanzo_mcp-0.5.0/hanzo_mcp/tools/jupyter/notebook_edit.py +162 -139
  41. hanzo_mcp-0.5.0/hanzo_mcp/tools/jupyter/notebook_read.py +152 -0
  42. {hanzo_mcp-0.3.4 → hanzo_mcp-0.5.0}/hanzo_mcp/tools/shell/__init__.py +29 -20
  43. {hanzo_mcp-0.3.4 → hanzo_mcp-0.5.0}/hanzo_mcp/tools/shell/base.py +87 -45
  44. hanzo_mcp-0.5.0/hanzo_mcp/tools/shell/bash_session.py +731 -0
  45. hanzo_mcp-0.5.0/hanzo_mcp/tools/shell/bash_session_executor.py +295 -0
  46. {hanzo_mcp-0.3.4 → hanzo_mcp-0.5.0}/hanzo_mcp/tools/shell/command_executor.py +435 -384
  47. hanzo_mcp-0.5.0/hanzo_mcp/tools/shell/run_command.py +357 -0
  48. hanzo_mcp-0.5.0/hanzo_mcp/tools/shell/run_command_windows.py +328 -0
  49. hanzo_mcp-0.5.0/hanzo_mcp/tools/shell/session_manager.py +196 -0
  50. hanzo_mcp-0.5.0/hanzo_mcp/tools/shell/session_storage.py +325 -0
  51. hanzo_mcp-0.5.0/hanzo_mcp/tools/todo/__init__.py +66 -0
  52. hanzo_mcp-0.5.0/hanzo_mcp/tools/todo/base.py +319 -0
  53. hanzo_mcp-0.5.0/hanzo_mcp/tools/todo/todo_read.py +148 -0
  54. hanzo_mcp-0.5.0/hanzo_mcp/tools/todo/todo_write.py +378 -0
  55. hanzo_mcp-0.5.0/hanzo_mcp/tools/vector/__init__.py +95 -0
  56. hanzo_mcp-0.5.0/hanzo_mcp/tools/vector/infinity_store.py +365 -0
  57. hanzo_mcp-0.5.0/hanzo_mcp/tools/vector/project_manager.py +361 -0
  58. hanzo_mcp-0.5.0/hanzo_mcp/tools/vector/vector_index.py +115 -0
  59. hanzo_mcp-0.5.0/hanzo_mcp/tools/vector/vector_search.py +215 -0
  60. {hanzo_mcp-0.3.4 → hanzo_mcp-0.5.0}/hanzo_mcp.egg-info/PKG-INFO +35 -3
  61. hanzo_mcp-0.5.0/hanzo_mcp.egg-info/SOURCES.txt +69 -0
  62. {hanzo_mcp-0.3.4 → hanzo_mcp-0.5.0}/hanzo_mcp.egg-info/requires.txt +1 -0
  63. {hanzo_mcp-0.3.4 → hanzo_mcp-0.5.0}/pyproject.toml +9 -21
  64. hanzo_mcp-0.5.0/tests/test_async_support.py +24 -0
  65. {hanzo_mcp-0.3.4 → hanzo_mcp-0.5.0}/tests/test_cli.py +195 -8
  66. hanzo_mcp-0.3.4/hanzo_mcp/cli.py +0 -357
  67. hanzo_mcp-0.3.4/hanzo_mcp/server.py +0 -182
  68. hanzo_mcp-0.3.4/hanzo_mcp/tools/__init__.py +0 -86
  69. hanzo_mcp-0.3.4/hanzo_mcp/tools/agent/agent_tool.py +0 -474
  70. hanzo_mcp-0.3.4/hanzo_mcp/tools/agent/base_provider.py +0 -73
  71. hanzo_mcp-0.3.4/hanzo_mcp/tools/agent/litellm_provider.py +0 -45
  72. hanzo_mcp-0.3.4/hanzo_mcp/tools/agent/lmstudio_agent.py +0 -385
  73. hanzo_mcp-0.3.4/hanzo_mcp/tools/agent/lmstudio_provider.py +0 -219
  74. hanzo_mcp-0.3.4/hanzo_mcp/tools/agent/provider_registry.py +0 -120
  75. hanzo_mcp-0.3.4/hanzo_mcp/tools/common/__init__.py +0 -30
  76. hanzo_mcp-0.3.4/hanzo_mcp/tools/common/context.py +0 -448
  77. hanzo_mcp-0.3.4/hanzo_mcp/tools/common/error_handling.py +0 -86
  78. hanzo_mcp-0.3.4/hanzo_mcp/tools/common/logging_config.py +0 -115
  79. hanzo_mcp-0.3.4/hanzo_mcp/tools/common/session.py +0 -91
  80. hanzo_mcp-0.3.4/hanzo_mcp/tools/common/think_tool.py +0 -123
  81. hanzo_mcp-0.3.4/hanzo_mcp/tools/common/validation.py +0 -124
  82. hanzo_mcp-0.3.4/hanzo_mcp/tools/common/version_tool.py +0 -120
  83. hanzo_mcp-0.3.4/hanzo_mcp/tools/filesystem/__init__.py +0 -94
  84. hanzo_mcp-0.3.4/hanzo_mcp/tools/filesystem/edit_file.py +0 -287
  85. hanzo_mcp-0.3.4/hanzo_mcp/tools/filesystem/get_file_info.py +0 -170
  86. hanzo_mcp-0.3.4/hanzo_mcp/tools/filesystem/read_files.py +0 -198
  87. hanzo_mcp-0.3.4/hanzo_mcp/tools/filesystem/search_content.py +0 -275
  88. hanzo_mcp-0.3.4/hanzo_mcp/tools/filesystem/write_file.py +0 -162
  89. hanzo_mcp-0.3.4/hanzo_mcp/tools/jupyter/__init__.py +0 -76
  90. hanzo_mcp-0.3.4/hanzo_mcp/tools/jupyter/notebook_operations.py +0 -514
  91. hanzo_mcp-0.3.4/hanzo_mcp/tools/jupyter/read_notebook.py +0 -165
  92. hanzo_mcp-0.3.4/hanzo_mcp/tools/project/__init__.py +0 -64
  93. hanzo_mcp-0.3.4/hanzo_mcp/tools/project/analysis.py +0 -882
  94. hanzo_mcp-0.3.4/hanzo_mcp/tools/project/base.py +0 -66
  95. hanzo_mcp-0.3.4/hanzo_mcp/tools/project/project_analyze.py +0 -173
  96. hanzo_mcp-0.3.4/hanzo_mcp/tools/shell/run_command.py +0 -204
  97. hanzo_mcp-0.3.4/hanzo_mcp/tools/shell/run_script.py +0 -215
  98. hanzo_mcp-0.3.4/hanzo_mcp/tools/shell/script_tool.py +0 -244
  99. hanzo_mcp-0.3.4/hanzo_mcp.egg-info/SOURCES.txt +0 -61
  100. hanzo_mcp-0.3.4/tests/test_server.py +0 -191
  101. hanzo_mcp-0.3.4/tests/test_tools_registration.py +0 -180
  102. hanzo_mcp-0.3.4/tests/test_validation.py +0 -118
  103. {hanzo_mcp-0.3.4 → hanzo_mcp-0.5.0}/LICENSE +0 -0
  104. {hanzo_mcp-0.3.4 → hanzo_mcp-0.5.0}/hanzo_mcp.egg-info/dependency_links.txt +0 -0
  105. {hanzo_mcp-0.3.4 → hanzo_mcp-0.5.0}/hanzo_mcp.egg-info/entry_points.txt +0 -0
  106. {hanzo_mcp-0.3.4 → hanzo_mcp-0.5.0}/hanzo_mcp.egg-info/top_level.txt +0 -0
  107. {hanzo_mcp-0.3.4 → hanzo_mcp-0.5.0}/setup.cfg +0 -0
  108. {hanzo_mcp-0.3.4 → hanzo_mcp-0.5.0}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hanzo-mcp
3
- Version: 0.3.4
3
+ Version: 0.5.0
4
4
  Summary: MCP implementation of Hanzo capabilities
5
5
  Author-email: Hanzo Industries Inc <dev@hanzo.ai>
6
6
  License: MIT
@@ -20,6 +20,7 @@ Requires-Dist: uvicorn>=0.23.1
20
20
  Requires-Dist: openai>=1.50.0
21
21
  Requires-Dist: python-dotenv>=1.0.0
22
22
  Requires-Dist: litellm>=1.40.14
23
+ Requires-Dist: grep-ast>=0.8.1
23
24
  Provides-Extra: dev
24
25
  Requires-Dist: pytest>=7.0.0; extra == "dev"
25
26
  Requires-Dist: pytest-cov>=4.1.0; extra == "dev"
@@ -50,7 +51,7 @@ An implementation of Hanzo capabilities using the Model Context Protocol (MCP).
50
51
 
51
52
  This project provides an MCP server that implements Hanzo-like functionality, allowing Claude to directly execute instructions for modifying and improving project files. By leveraging the Model Context Protocol, this implementation enables seamless integration with various MCP clients including Claude Desktop.
52
53
 
53
- ![example](./doc/example.gif)
54
+ ![example](./docs/example.gif)
54
55
 
55
56
  ## Features
56
57
 
@@ -96,9 +97,40 @@ uv pip install hanzo-mcp
96
97
  pip install hanzo-mcp
97
98
  ```
98
99
 
100
+ ### Claude Desktop Integration
101
+
102
+ To install and configure hanzo-mcp for use with Claude Desktop:
103
+
104
+ ```bash
105
+ # Install the package globally
106
+ uv pip install hanzo-mcp
107
+
108
+ # Install configuration to Claude Desktop with default settings
109
+ hanzo-mcp --install
110
+ ```
111
+
112
+ For development, if you want to install your local version to Claude Desktop:
113
+
114
+ ```bash
115
+ # Clone and navigate to the repository
116
+ git clone https://github.com/hanzoai/mcp.git
117
+ cd mcp
118
+
119
+ # Install and configure for Claude Desktop
120
+ make install-desktop
121
+
122
+ # With custom paths and server name
123
+ make install-desktop ALLOWED_PATHS="/path/to/projects,/another/path" SERVER_NAME="hanzo-dev"
124
+
125
+ # Disable write tools (useful if you prefer using your IDE for edits)
126
+ make install-desktop DISABLE_WRITE=1
127
+ ```
128
+
129
+ After installation, restart Claude Desktop. You'll see "hanzo" (or your custom server name) available in the MCP server dropdown.
130
+
99
131
  For detailed installation and configuration instructions, please refer to the [documentation](./docs/).
100
132
 
101
- Of course, you can also read [USEFUL_PROMPTS](./doc/USEFUL_PROMPTS.md) for some inspiration on how to use hanzo-mcp.
133
+ Of course, you can also read [USEFUL_PROMPTS](./docs/USEFUL_PROMPTS.md) for some inspiration on how to use hanzo-mcp.
102
134
 
103
135
  ## Security
104
136
 
@@ -6,7 +6,7 @@ An implementation of Hanzo capabilities using the Model Context Protocol (MCP).
6
6
 
7
7
  This project provides an MCP server that implements Hanzo-like functionality, allowing Claude to directly execute instructions for modifying and improving project files. By leveraging the Model Context Protocol, this implementation enables seamless integration with various MCP clients including Claude Desktop.
8
8
 
9
- ![example](./doc/example.gif)
9
+ ![example](./docs/example.gif)
10
10
 
11
11
  ## Features
12
12
 
@@ -52,9 +52,40 @@ uv pip install hanzo-mcp
52
52
  pip install hanzo-mcp
53
53
  ```
54
54
 
55
+ ### Claude Desktop Integration
56
+
57
+ To install and configure hanzo-mcp for use with Claude Desktop:
58
+
59
+ ```bash
60
+ # Install the package globally
61
+ uv pip install hanzo-mcp
62
+
63
+ # Install configuration to Claude Desktop with default settings
64
+ hanzo-mcp --install
65
+ ```
66
+
67
+ For development, if you want to install your local version to Claude Desktop:
68
+
69
+ ```bash
70
+ # Clone and navigate to the repository
71
+ git clone https://github.com/hanzoai/mcp.git
72
+ cd mcp
73
+
74
+ # Install and configure for Claude Desktop
75
+ make install-desktop
76
+
77
+ # With custom paths and server name
78
+ make install-desktop ALLOWED_PATHS="/path/to/projects,/another/path" SERVER_NAME="hanzo-dev"
79
+
80
+ # Disable write tools (useful if you prefer using your IDE for edits)
81
+ make install-desktop DISABLE_WRITE=1
82
+ ```
83
+
84
+ After installation, restart Claude Desktop. You'll see "hanzo" (or your custom server name) available in the MCP server dropdown.
85
+
55
86
  For detailed installation and configuration instructions, please refer to the [documentation](./docs/).
56
87
 
57
- Of course, you can also read [USEFUL_PROMPTS](./doc/USEFUL_PROMPTS.md) for some inspiration on how to use hanzo-mcp.
88
+ Of course, you can also read [USEFUL_PROMPTS](./docs/USEFUL_PROMPTS.md) for some inspiration on how to use hanzo-mcp.
58
89
 
59
90
  ## Security
60
91
 
@@ -1,3 +1,3 @@
1
1
  """Hanzo MCP - Implementation of Hanzo capabilities using MCP."""
2
2
 
3
- __version__ = "0.3.4"
3
+ __version__ = "0.5.0"
@@ -0,0 +1,320 @@
1
+ """Command-line interface for the Hanzo MCP server."""
2
+
3
+ import argparse
4
+ import json
5
+ import os
6
+ import sys
7
+ from pathlib import Path
8
+ from typing import Any, cast
9
+
10
+ from hanzo_mcp.server import HanzoMCPServer
11
+
12
+
13
+ def main() -> None:
14
+ """Run the CLI for the Hanzo MCP server."""
15
+ parser = argparse.ArgumentParser(
16
+ description="MCP server implementing Hanzo AI capabilities"
17
+ )
18
+
19
+ _ = parser.add_argument(
20
+ "--transport",
21
+ choices=["stdio", "sse"],
22
+ default="stdio",
23
+ help="Transport protocol to use (default: stdio)",
24
+ )
25
+
26
+ _ = parser.add_argument(
27
+ "--name",
28
+ default="hanzo-mcp",
29
+ help="Name of the MCP server (default: hanzo-mcp)",
30
+ )
31
+
32
+ _ = parser.add_argument(
33
+ "--allow-path",
34
+ action="append",
35
+ dest="allowed_paths",
36
+ help="Add an allowed path (can be specified multiple times)",
37
+ )
38
+
39
+ _ = parser.add_argument(
40
+ "--project",
41
+ action="append",
42
+ dest="project_paths",
43
+ help="Add a project path for prompt generation (can be specified multiple times)",
44
+ )
45
+
46
+ _ = parser.add_argument(
47
+ "--agent-model",
48
+ dest="agent_model",
49
+ help="Specify the model name in LiteLLM format (e.g., 'openai/gpt-4o', 'anthropic/claude-4-sonnet')",
50
+ )
51
+
52
+ _ = parser.add_argument(
53
+ "--agent-max-tokens",
54
+ dest="agent_max_tokens",
55
+ type=int,
56
+ help="Specify the maximum tokens for agent responses",
57
+ )
58
+
59
+ _ = parser.add_argument(
60
+ "--agent-api-key",
61
+ dest="agent_api_key",
62
+ help="Specify the API key for the LLM provider (for development/testing only)",
63
+ )
64
+
65
+ _ = parser.add_argument(
66
+ "--agent-base-url",
67
+ dest="agent_base_url",
68
+ help="Specify the base URL for the LLM provider API endpoint (e.g., 'http://localhost:1234/v1')",
69
+ )
70
+
71
+ _ = parser.add_argument(
72
+ "--agent-max-iterations",
73
+ dest="agent_max_iterations",
74
+ type=int,
75
+ default=10,
76
+ help="Maximum number of iterations for agent (default: 10)",
77
+ )
78
+
79
+ _ = parser.add_argument(
80
+ "--agent-max-tool-uses",
81
+ dest="agent_max_tool_uses",
82
+ type=int,
83
+ default=30,
84
+ help="Maximum number of total tool uses for agent (default: 30)",
85
+ )
86
+
87
+ _ = parser.add_argument(
88
+ "--enable-agent-tool",
89
+ dest="enable_agent_tool",
90
+ action="store_true",
91
+ default=False,
92
+ help="Enable the agent tool (disabled by default)",
93
+ )
94
+
95
+ _ = parser.add_argument(
96
+ "--command-timeout",
97
+ dest="command_timeout",
98
+ type=float,
99
+ default=120.0,
100
+ help="Default timeout for command execution in seconds (default: 120.0)",
101
+ )
102
+
103
+ _ = parser.add_argument(
104
+ "--disable-write-tools",
105
+ dest="disable_write_tools",
106
+ action="store_true",
107
+ default=False,
108
+ help="Disable write tools (edit, write, etc.)",
109
+ )
110
+
111
+ _ = parser.add_argument(
112
+ "--disable-search-tools",
113
+ dest="disable_search_tools",
114
+ action="store_true",
115
+ default=False,
116
+ help="Disable search tools (grep, search_content, etc.)",
117
+ )
118
+
119
+ _ = parser.add_argument(
120
+ "--host",
121
+ dest="host",
122
+ default="127.0.0.1",
123
+ help="Host for SSE server (default: 127.0.0.1)",
124
+ )
125
+
126
+ _ = parser.add_argument(
127
+ "--port",
128
+ dest="port",
129
+ type=int,
130
+ default=3000,
131
+ help="Port for SSE server (default: 3000)",
132
+ )
133
+
134
+ _ = parser.add_argument(
135
+ "--log-level",
136
+ dest="log_level",
137
+ default="INFO",
138
+ choices=["DEBUG", "INFO", "WARNING", "ERROR"],
139
+ help="Logging level (default: INFO)",
140
+ )
141
+
142
+ _ = parser.add_argument(
143
+ "--project-dir",
144
+ dest="project_dir",
145
+ help="Single project directory (alias for --project)",
146
+ )
147
+
148
+ _ = parser.add_argument(
149
+ "--install",
150
+ action="store_true",
151
+ help="Install server configuration in Claude Desktop",
152
+ )
153
+
154
+ args = parser.parse_args()
155
+
156
+ # Cast args attributes to appropriate types to avoid 'Any' warnings
157
+ name: str = cast(str, args.name)
158
+ install: bool = cast(bool, args.install)
159
+ transport: str = cast(str, args.transport)
160
+ agent_model: str | None = cast(str | None, args.agent_model)
161
+ agent_max_tokens: int | None = cast(int | None, args.agent_max_tokens)
162
+ agent_api_key: str | None = cast(str | None, args.agent_api_key)
163
+ agent_base_url: str | None = cast(str | None, args.agent_base_url)
164
+ agent_max_iterations: int = cast(int, args.agent_max_iterations)
165
+ agent_max_tool_uses: int = cast(int, args.agent_max_tool_uses)
166
+ enable_agent_tool: bool = cast(bool, args.enable_agent_tool)
167
+ command_timeout: float = cast(float, args.command_timeout)
168
+ disable_write_tools: bool = cast(bool, args.disable_write_tools)
169
+ disable_search_tools: bool = cast(bool, args.disable_search_tools)
170
+ host: str = cast(str, args.host)
171
+ port: int = cast(int, args.port)
172
+ log_level: str = cast(str, args.log_level)
173
+ project_dir: str | None = cast(str | None, args.project_dir)
174
+ allowed_paths: list[str] = (
175
+ cast(list[str], args.allowed_paths) if args.allowed_paths else []
176
+ )
177
+ project_paths: list[str] = (
178
+ cast(list[str], args.project_paths) if args.project_paths else []
179
+ )
180
+
181
+ # Handle project_dir parameter (add to both allowed_paths and project_paths)
182
+ if project_dir:
183
+ if project_dir not in allowed_paths:
184
+ allowed_paths.append(project_dir)
185
+ if project_dir not in project_paths:
186
+ project_paths.append(project_dir)
187
+
188
+ if install:
189
+ install_claude_desktop_config(
190
+ name,
191
+ allowed_paths,
192
+ disable_write_tools,
193
+ disable_search_tools,
194
+ host,
195
+ port
196
+ )
197
+ return
198
+
199
+ # If no allowed paths are specified, use the current directory
200
+ if not allowed_paths:
201
+ allowed_paths = [os.getcwd()]
202
+
203
+ # Run the server
204
+ server = HanzoMCPServer(
205
+ name=name,
206
+ allowed_paths=allowed_paths,
207
+ project_dir=project_dir,
208
+ agent_model=agent_model,
209
+ agent_max_tokens=agent_max_tokens,
210
+ agent_api_key=agent_api_key,
211
+ agent_base_url=agent_base_url,
212
+ agent_max_iterations=agent_max_iterations,
213
+ agent_max_tool_uses=agent_max_tool_uses,
214
+ enable_agent_tool=enable_agent_tool,
215
+ disable_write_tools=disable_write_tools,
216
+ disable_search_tools=disable_search_tools,
217
+ host=host,
218
+ port=port,
219
+ )
220
+ # Transport will be automatically cast to Literal['stdio', 'sse'] by the server
221
+ server.run(transport=transport)
222
+
223
+
224
+ def install_claude_desktop_config(
225
+ name: str = "hanzo-mcp",
226
+ allowed_paths: list[str] | None = None,
227
+ disable_write_tools: bool = False,
228
+ disable_search_tools: bool = False,
229
+ host: str = "127.0.0.1",
230
+ port: int = 3000,
231
+ ) -> None:
232
+ """Install the server configuration in Claude Desktop.
233
+
234
+ Args:
235
+ name: The name to use for the server in the config
236
+ allowed_paths: Optional list of paths to allow
237
+ disable_write_tools: Whether to disable write tools
238
+ disable_search_tools: Whether to disable search tools
239
+ host: Host for SSE server
240
+ port: Port for SSE server
241
+ """
242
+ # Find the Claude Desktop config directory
243
+ home: Path = Path.home()
244
+
245
+ if sys.platform == "darwin": # macOS
246
+ config_dir: Path = home / "Library" / "Application Support" / "Claude"
247
+ elif sys.platform == "win32": # Windows
248
+ config_dir = Path(os.environ.get("APPDATA", "")) / "Claude"
249
+ else: # Linux and others
250
+ config_dir = home / ".config" / "claude"
251
+
252
+ config_file: Path = config_dir / "claude_desktop_config.json"
253
+
254
+ # Create directory if it doesn't exist
255
+ config_dir.mkdir(parents=True, exist_ok=True)
256
+
257
+ # Get current script path
258
+ script_path: Path = Path(sys.executable)
259
+
260
+ # Create args array
261
+ args: list[str] = ["-m", "hanzo_mcp.cli"]
262
+
263
+ # Add allowed paths if specified
264
+ if allowed_paths:
265
+ for path in allowed_paths:
266
+ args.extend(["--allow-path", path])
267
+ else:
268
+ # Allow home directory by default
269
+ args.extend(["--allow-path", str(home)])
270
+
271
+ # Add tool disable flags if specified
272
+ if disable_write_tools:
273
+ args.append("--disable-write-tools")
274
+
275
+ if disable_search_tools:
276
+ args.append("--disable-search-tools")
277
+
278
+ # Create config object
279
+ config: dict[str, Any] = {
280
+ "mcpServers": {name: {"command": script_path.as_posix(), "args": args}}
281
+ }
282
+
283
+ # Check if the file already exists
284
+ if config_file.exists():
285
+ try:
286
+ with open(config_file, "r") as f:
287
+ existing_config: dict[str, Any] = json.load(f)
288
+
289
+ # Update the existing config
290
+ if "mcpServers" not in existing_config:
291
+ existing_config["mcpServers"] = {}
292
+
293
+ existing_config["mcpServers"][name] = config["mcpServers"][name]
294
+ config = existing_config
295
+ except Exception as e:
296
+ print(f"Error reading existing config: {e}")
297
+ print("Creating new config file.")
298
+
299
+ # Write the config file
300
+ with open(config_file, mode="w") as f:
301
+ json.dump(config, f, indent=2)
302
+
303
+ print(f"Successfully installed {name} in Claude Desktop configuration.")
304
+ print(f"Config file: {config_file}")
305
+
306
+ if allowed_paths:
307
+ print("\nAllowed paths:")
308
+ for path in allowed_paths:
309
+ print(f"- {path}")
310
+ else:
311
+ print(f"\nDefault allowed path: {home}")
312
+
313
+ print(
314
+ "\nYou can modify allowed paths in the config file directly."
315
+ )
316
+ print("Restart Claude Desktop for changes to take effect.")
317
+
318
+
319
+ if __name__ == "__main__":
320
+ main()