hanzo-mcp 0.9.0__py3-none-any.whl → 0.9.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


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

Files changed (135) hide show
  1. hanzo_mcp/__init__.py +1 -1
  2. hanzo_mcp/analytics/posthog_analytics.py +14 -1
  3. hanzo_mcp/cli.py +108 -4
  4. hanzo_mcp/server.py +11 -0
  5. hanzo_mcp/tools/__init__.py +3 -16
  6. hanzo_mcp/tools/agent/__init__.py +5 -0
  7. hanzo_mcp/tools/agent/agent.py +5 -0
  8. hanzo_mcp/tools/agent/agent_tool.py +3 -17
  9. hanzo_mcp/tools/agent/agent_tool_v1_deprecated.py +623 -0
  10. hanzo_mcp/tools/agent/clarification_tool.py +7 -1
  11. hanzo_mcp/tools/agent/claude_desktop_auth.py +16 -6
  12. hanzo_mcp/tools/agent/cli_agent_base.py +5 -0
  13. hanzo_mcp/tools/agent/cli_tools.py +26 -0
  14. hanzo_mcp/tools/agent/code_auth_tool.py +5 -0
  15. hanzo_mcp/tools/agent/critic_tool.py +7 -1
  16. hanzo_mcp/tools/agent/iching_tool.py +5 -0
  17. hanzo_mcp/tools/agent/network_tool.py +5 -0
  18. hanzo_mcp/tools/agent/review_tool.py +7 -1
  19. hanzo_mcp/tools/agent/swarm_alias.py +5 -0
  20. hanzo_mcp/tools/agent/swarm_tool.py +701 -0
  21. hanzo_mcp/tools/agent/swarm_tool_v1_deprecated.py +554 -0
  22. hanzo_mcp/tools/agent/unified_cli_tools.py +5 -0
  23. hanzo_mcp/tools/common/auto_timeout.py +234 -0
  24. hanzo_mcp/tools/common/base.py +4 -0
  25. hanzo_mcp/tools/common/batch_tool.py +5 -0
  26. hanzo_mcp/tools/common/config_tool.py +5 -0
  27. hanzo_mcp/tools/common/critic_tool.py +5 -0
  28. hanzo_mcp/tools/common/paginated_base.py +4 -0
  29. hanzo_mcp/tools/common/permissions.py +38 -12
  30. hanzo_mcp/tools/common/personality.py +673 -980
  31. hanzo_mcp/tools/common/stats.py +5 -0
  32. hanzo_mcp/tools/common/thinking_tool.py +5 -0
  33. hanzo_mcp/tools/common/timeout_parser.py +103 -0
  34. hanzo_mcp/tools/common/tool_disable.py +5 -0
  35. hanzo_mcp/tools/common/tool_enable.py +5 -0
  36. hanzo_mcp/tools/common/tool_list.py +5 -0
  37. hanzo_mcp/tools/config/config_tool.py +5 -0
  38. hanzo_mcp/tools/config/mode_tool.py +5 -0
  39. hanzo_mcp/tools/database/graph.py +5 -0
  40. hanzo_mcp/tools/database/graph_add.py +5 -0
  41. hanzo_mcp/tools/database/graph_query.py +5 -0
  42. hanzo_mcp/tools/database/graph_remove.py +5 -0
  43. hanzo_mcp/tools/database/graph_search.py +5 -0
  44. hanzo_mcp/tools/database/graph_stats.py +5 -0
  45. hanzo_mcp/tools/database/sql.py +5 -0
  46. hanzo_mcp/tools/database/sql_query.py +2 -0
  47. hanzo_mcp/tools/database/sql_search.py +5 -0
  48. hanzo_mcp/tools/database/sql_stats.py +5 -0
  49. hanzo_mcp/tools/editor/neovim_command.py +5 -0
  50. hanzo_mcp/tools/editor/neovim_edit.py +7 -2
  51. hanzo_mcp/tools/editor/neovim_session.py +5 -0
  52. hanzo_mcp/tools/filesystem/__init__.py +23 -26
  53. hanzo_mcp/tools/filesystem/ast_tool.py +2 -3
  54. hanzo_mcp/tools/filesystem/base.py +0 -16
  55. hanzo_mcp/tools/filesystem/batch_search.py +825 -0
  56. hanzo_mcp/tools/filesystem/content_replace.py +5 -3
  57. hanzo_mcp/tools/filesystem/diff.py +5 -0
  58. hanzo_mcp/tools/filesystem/directory_tree.py +34 -281
  59. hanzo_mcp/tools/filesystem/directory_tree_paginated.py +345 -0
  60. hanzo_mcp/tools/filesystem/edit.py +5 -4
  61. hanzo_mcp/tools/filesystem/find.py +177 -311
  62. hanzo_mcp/tools/filesystem/find_files.py +370 -0
  63. hanzo_mcp/tools/filesystem/git_search.py +5 -3
  64. hanzo_mcp/tools/filesystem/grep.py +454 -0
  65. hanzo_mcp/tools/filesystem/multi_edit.py +5 -4
  66. hanzo_mcp/tools/filesystem/read.py +11 -8
  67. hanzo_mcp/tools/filesystem/rules_tool.py +5 -3
  68. hanzo_mcp/tools/filesystem/search_tool.py +728 -0
  69. hanzo_mcp/tools/filesystem/symbols_tool.py +510 -0
  70. hanzo_mcp/tools/filesystem/tree.py +273 -0
  71. hanzo_mcp/tools/filesystem/watch.py +6 -1
  72. hanzo_mcp/tools/filesystem/write.py +12 -6
  73. hanzo_mcp/tools/jupyter/jupyter.py +30 -2
  74. hanzo_mcp/tools/jupyter/notebook_edit.py +298 -0
  75. hanzo_mcp/tools/jupyter/notebook_read.py +148 -0
  76. hanzo_mcp/tools/llm/consensus_tool.py +8 -6
  77. hanzo_mcp/tools/llm/llm_manage.py +5 -0
  78. hanzo_mcp/tools/llm/llm_tool.py +2 -0
  79. hanzo_mcp/tools/llm/llm_unified.py +5 -0
  80. hanzo_mcp/tools/llm/provider_tools.py +5 -0
  81. hanzo_mcp/tools/lsp/lsp_tool.py +475 -622
  82. hanzo_mcp/tools/mcp/mcp_add.py +7 -2
  83. hanzo_mcp/tools/mcp/mcp_remove.py +15 -2
  84. hanzo_mcp/tools/mcp/mcp_stats.py +5 -0
  85. hanzo_mcp/tools/mcp/mcp_tool.py +5 -0
  86. hanzo_mcp/tools/memory/knowledge_tools.py +14 -0
  87. hanzo_mcp/tools/memory/memory_tools.py +17 -0
  88. hanzo_mcp/tools/search/find_tool.py +5 -3
  89. hanzo_mcp/tools/search/unified_search.py +3 -1
  90. hanzo_mcp/tools/shell/__init__.py +2 -14
  91. hanzo_mcp/tools/shell/base_process.py +4 -2
  92. hanzo_mcp/tools/shell/bash_tool.py +2 -0
  93. hanzo_mcp/tools/shell/command_executor.py +7 -7
  94. hanzo_mcp/tools/shell/logs.py +5 -0
  95. hanzo_mcp/tools/shell/npx.py +5 -0
  96. hanzo_mcp/tools/shell/npx_background.py +5 -0
  97. hanzo_mcp/tools/shell/npx_tool.py +5 -0
  98. hanzo_mcp/tools/shell/open.py +5 -0
  99. hanzo_mcp/tools/shell/pkill.py +5 -0
  100. hanzo_mcp/tools/shell/process_tool.py +5 -0
  101. hanzo_mcp/tools/shell/processes.py +5 -0
  102. hanzo_mcp/tools/shell/run_background.py +5 -0
  103. hanzo_mcp/tools/shell/run_command.py +2 -0
  104. hanzo_mcp/tools/shell/run_command_windows.py +5 -0
  105. hanzo_mcp/tools/shell/streaming_command.py +5 -0
  106. hanzo_mcp/tools/shell/uvx.py +5 -0
  107. hanzo_mcp/tools/shell/uvx_background.py +5 -0
  108. hanzo_mcp/tools/shell/uvx_tool.py +5 -0
  109. hanzo_mcp/tools/shell/zsh_tool.py +3 -0
  110. hanzo_mcp/tools/todo/todo.py +5 -0
  111. hanzo_mcp/tools/todo/todo_read.py +142 -0
  112. hanzo_mcp/tools/todo/todo_write.py +367 -0
  113. hanzo_mcp/tools/vector/__init__.py +42 -95
  114. hanzo_mcp/tools/vector/index_tool.py +5 -0
  115. hanzo_mcp/tools/vector/vector.py +5 -0
  116. hanzo_mcp/tools/vector/vector_index.py +5 -0
  117. hanzo_mcp/tools/vector/vector_search.py +5 -0
  118. {hanzo_mcp-0.9.0.dist-info → hanzo_mcp-0.9.1.dist-info}/METADATA +1 -1
  119. hanzo_mcp-0.9.1.dist-info/RECORD +195 -0
  120. hanzo_mcp/tools/common/path_utils.py +0 -34
  121. hanzo_mcp/tools/compiler/__init__.py +0 -8
  122. hanzo_mcp/tools/compiler/sandboxed_compiler.py +0 -681
  123. hanzo_mcp/tools/environment/__init__.py +0 -8
  124. hanzo_mcp/tools/environment/environment_detector.py +0 -594
  125. hanzo_mcp/tools/filesystem/search.py +0 -1160
  126. hanzo_mcp/tools/framework/__init__.py +0 -8
  127. hanzo_mcp/tools/framework/framework_modes.py +0 -714
  128. hanzo_mcp/tools/memory/conversation_memory.py +0 -636
  129. hanzo_mcp/tools/shell/run_tool.py +0 -56
  130. hanzo_mcp/tools/vector/node_tool.py +0 -538
  131. hanzo_mcp/tools/vector/unified_vector.py +0 -384
  132. hanzo_mcp-0.9.0.dist-info/RECORD +0 -191
  133. {hanzo_mcp-0.9.0.dist-info → hanzo_mcp-0.9.1.dist-info}/WHEEL +0 -0
  134. {hanzo_mcp-0.9.0.dist-info → hanzo_mcp-0.9.1.dist-info}/entry_points.txt +0 -0
  135. {hanzo_mcp-0.9.0.dist-info → hanzo_mcp-0.9.1.dist-info}/top_level.txt +0 -0
@@ -9,6 +9,8 @@ from pathlib import Path
9
9
 
10
10
  from pydantic import Field
11
11
  from mcp.server import FastMCP
12
+
13
+ from hanzo_mcp.tools.common.auto_timeout import auto_timeout
12
14
  from mcp.server.fastmcp import Context as MCPContext
13
15
 
14
16
  from hanzo_mcp.tools.filesystem.base import FilesystemBaseTool
@@ -101,6 +103,9 @@ Can be run in dry-run mode to preview changes without applying them.
101
103
  Only works within allowed directories."""
102
104
 
103
105
  @override
106
+ @auto_timeout("content_replace")
107
+
108
+
104
109
  async def call(
105
110
  self,
106
111
  ctx: MCPContext,
@@ -121,9 +126,6 @@ Only works within allowed directories."""
121
126
  pattern: Pattern = params["pattern"]
122
127
  replacement: Replacement = params["replacement"]
123
128
  path: SearchPath = params["path"]
124
-
125
- # Expand path (handles ~, $HOME, etc.)
126
- path = self.expand_path(path)
127
129
  file_pattern = params.get("file_pattern", "*") # Default to all files
128
130
  dry_run = params.get("dry_run", False) # Default to False
129
131
 
@@ -5,6 +5,8 @@ from typing import override
5
5
  from pathlib import Path
6
6
 
7
7
  from mcp.server import FastMCP
8
+
9
+ from hanzo_mcp.tools.common.auto_timeout import auto_timeout
8
10
  from mcp.server.fastmcp import Context as MCPContext
9
11
 
10
12
  from hanzo_mcp.tools.common.base import BaseTool
@@ -200,6 +202,9 @@ diff a.json b.json --ignore-whitespace"""
200
202
  show_line_numbers=show_line_numbers,
201
203
  )
202
204
 
205
+ @auto_timeout("diff")
206
+
207
+
203
208
  async def call(self, ctx: MCPContext, **params) -> str:
204
209
  """Call the tool with arguments."""
205
210
  return await self.run(
@@ -1,23 +1,19 @@
1
1
  """Directory tree tool implementation.
2
2
 
3
- This module provides the DirectoryTreeTool for viewing file and directory structures
4
- with optional pagination and different display styles.
3
+ This module provides the DirectoryTreeTool for viewing file and directory structures.
5
4
  """
6
5
 
7
- from typing import Any, Dict, List, Union, Unpack, Optional, Literal, Annotated, TypedDict, final, override
6
+ from typing import Any, Unpack, Annotated, TypedDict, final, override
8
7
  from pathlib import Path
9
- import fnmatch
10
8
 
11
9
  from pydantic import Field
12
10
  from mcp.server import FastMCP
11
+
12
+ from hanzo_mcp.tools.common.auto_timeout import auto_timeout
13
13
  from mcp.server.fastmcp import Context as MCPContext
14
14
 
15
15
  from hanzo_mcp.tools.common.truncate import truncate_response
16
16
  from hanzo_mcp.tools.filesystem.base import FilesystemBaseTool
17
- from hanzo_mcp.tools.common.pagination import (
18
- CursorManager,
19
- paginate_list,
20
- )
21
17
 
22
18
  DirectoryPath = Annotated[
23
19
  str,
@@ -45,52 +41,19 @@ IncludeFiltered = Annotated[
45
41
  ),
46
42
  ]
47
43
 
48
- PageSize = Annotated[
49
- Optional[int],
50
- Field(
51
- default=None,
52
- description="Number of entries per page (enables pagination when set)",
53
- title="Page Size",
54
- ),
55
- ]
56
-
57
- Page = Annotated[
58
- int,
59
- Field(
60
- default=1,
61
- description="Page number for pagination",
62
- title="Page",
63
- ),
64
- ]
65
-
66
- Style = Annotated[
67
- Literal["compact", "detailed", "unix"],
68
- Field(
69
- default="compact",
70
- description="Display style: compact (default), detailed (with sizes), or unix (tree-like)",
71
- title="Style",
72
- ),
73
- ]
74
-
75
44
 
76
- class DirectoryTreeToolParams(TypedDict, total=False):
45
+ class DirectoryTreeToolParams(TypedDict):
77
46
  """Parameters for the DirectoryTreeTool.
78
47
 
79
48
  Attributes:
80
49
  path: The path to the directory to view
81
50
  depth: The maximum depth to traverse (0 for unlimited)
82
51
  include_filtered: Include directories that are normally filtered
83
- page_size: Number of entries per page (enables pagination when set)
84
- page: Page number for pagination
85
- style: Display style (compact, detailed, unix)
86
52
  """
87
53
 
88
- path: str
89
- depth: int
90
- include_filtered: bool
91
- page_size: Optional[int]
92
- page: int
93
- style: Literal["compact", "detailed", "unix"]
54
+ path: DirectoryPath
55
+ depth: Depth
56
+ include_filtered: IncludeFiltered
94
57
 
95
58
 
96
59
  @final
@@ -121,21 +84,17 @@ Returns a structured view of the directory tree with files and subdirectories.
121
84
  Directories are marked with trailing slashes. The output is formatted as an
122
85
  indented list for readability. By default, common development directories like
123
86
  .git, node_modules, and venv are noted but not traversed unless explicitly
124
- requested. Only works within allowed directories.
87
+ requested. Only works within allowed directories."""
125
88
 
126
- Supports multiple display styles:
127
- - compact: Simple indented list (default)
128
- - detailed: Includes file sizes and additional metadata
129
- - unix: Traditional unix tree command style with ASCII art
89
+ @override
90
+ @auto_timeout("directory_tree")
130
91
 
131
- Optional pagination is available by setting page_size parameter."""
132
92
 
133
- @override
134
93
  async def call(
135
94
  self,
136
95
  ctx: MCPContext,
137
96
  **params: Unpack[DirectoryTreeToolParams],
138
- ) -> Union[str, Dict[str, Any]]:
97
+ ) -> str:
139
98
  """Execute the tool with the given parameters.
140
99
 
141
100
  Args:
@@ -148,18 +107,9 @@ Optional pagination is available by setting page_size parameter."""
148
107
  tool_ctx = self.create_tool_context(ctx)
149
108
 
150
109
  # Extract parameters
151
- path: str = params["path"]
110
+ path: DirectoryPath = params["path"]
152
111
  depth = params.get("depth", 3) # Default depth is 3
153
112
  include_filtered = params.get("include_filtered", False) # Default to False
154
- page_size = params.get("page_size") # Optional pagination
155
- page = params.get("page", 1)
156
- style = params.get("style", "compact")
157
-
158
- # Expand path (handles ~, $HOME, etc.)
159
- path = self.expand_path(path)
160
-
161
- # For pagination, we need to use offset-based pagination
162
- offset = (page - 1) * page_size if page_size else None
163
113
 
164
114
  # Validate path parameter
165
115
  path_validation = self.validate_path(path)
@@ -167,8 +117,7 @@ Optional pagination is available by setting page_size parameter."""
167
117
  await tool_ctx.error(path_validation.error_message)
168
118
  return f"Error: {path_validation.error_message}"
169
119
 
170
- pagination_info = f" (page {page}, size {page_size})" if page_size else ""
171
- await tool_ctx.info(f"Getting directory tree: {path} (depth: {depth}, include_filtered: {include_filtered}, style: {style}){pagination_info}")
120
+ await tool_ctx.info(f"Getting directory tree: {path} (depth: {depth}, include_filtered: {include_filtered})")
172
121
 
173
122
  # Check if path is allowed
174
123
  allowed, error_msg = await self.check_path_allowed(path, tool_ctx)
@@ -227,115 +176,7 @@ Optional pagination is available by setting page_size parameter."""
227
176
  "skipped_filtered": 0,
228
177
  }
229
178
 
230
- # If pagination is enabled, collect entries in a flat list
231
- if page_size:
232
- all_entries: List[Dict[str, Any]] = []
233
-
234
- async def collect_entries(current_path: Path, current_depth: int = 0, parent_path: str = "") -> None:
235
- """Collect entries in a flat list for pagination."""
236
- if not self.is_path_allowed(str(current_path)):
237
- return
238
-
239
- try:
240
- # Sort entries: directories first, then files alphabetically
241
- entries = sorted(current_path.iterdir(), key=lambda x: (not x.is_dir(), x.name))
242
-
243
- for entry in entries:
244
- if not self.is_path_allowed(str(entry)):
245
- continue
246
-
247
- # Calculate relative path for display
248
- relative_path = f"{parent_path}/{entry.name}" if parent_path else entry.name
249
-
250
- if entry.is_dir():
251
- stats["directories"] += 1
252
- entry_data: Dict[str, Any] = {
253
- "path": relative_path,
254
- "name": entry.name,
255
- "type": "directory",
256
- "depth": current_depth,
257
- }
258
-
259
- # Add size info for detailed style
260
- if style == "detailed":
261
- try:
262
- entry_data["size"] = sum(f.stat().st_size for f in entry.rglob('*') if f.is_file())
263
- except Exception:
264
- entry_data["size"] = 0
265
-
266
- # Check if we should filter this directory
267
- if should_filter(entry):
268
- entry_data["skipped"] = "filtered-directory"
269
- stats["skipped_filtered"] += 1
270
- all_entries.append(entry_data)
271
- continue
272
-
273
- # Check depth limit
274
- if depth > 0 and current_depth >= depth:
275
- entry_data["skipped"] = "depth-limit"
276
- stats["skipped_depth"] += 1
277
- all_entries.append(entry_data)
278
- continue
279
-
280
- # Add directory entry
281
- all_entries.append(entry_data)
282
-
283
- # Process children recursively
284
- await collect_entries(entry, current_depth + 1, relative_path)
285
- else:
286
- # Add file entry
287
- if depth <= 0 or current_depth < depth:
288
- stats["files"] += 1
289
- file_data = {
290
- "path": relative_path,
291
- "name": entry.name,
292
- "type": "file",
293
- "depth": current_depth,
294
- }
295
-
296
- # Add size info for detailed style
297
- if style == "detailed":
298
- try:
299
- file_data["size"] = entry.stat().st_size
300
- except Exception:
301
- file_data["size"] = 0
302
-
303
- all_entries.append(file_data)
304
-
305
- except Exception as e:
306
- await tool_ctx.warning(f"Error processing {current_path}: {str(e)}")
307
-
308
- # Collect all entries
309
- await tool_ctx.info("Collecting directory entries for pagination...")
310
- await collect_entries(dir_path)
311
-
312
- # Apply pagination using offset
313
- start_idx = offset if offset else 0
314
- end_idx = start_idx + page_size
315
- paginated_entries = all_entries[start_idx:end_idx]
316
-
317
- # Format entries based on style
318
- formatted_entries = self._format_entries(paginated_entries, style)
319
-
320
- # Build paginated response
321
- response = {
322
- "entries": formatted_entries,
323
- "total_entries": len(all_entries),
324
- "page": page,
325
- "page_size": page_size,
326
- "total_pages": (len(all_entries) + page_size - 1) // page_size,
327
- "has_next": end_idx < len(all_entries),
328
- "stats": {
329
- "directories": stats["directories"],
330
- "files": stats["files"],
331
- "skipped_depth": stats["skipped_depth"],
332
- "skipped_filtered": stats["skipped_filtered"],
333
- }
334
- }
335
-
336
- return response
337
-
338
- # Non-paginated: Build the tree recursively
179
+ # Build the tree recursively
339
180
  async def build_tree(current_path: Path, current_depth: int = 0) -> list[dict[str, Any]]:
340
181
  result: list[dict[str, Any]] = []
341
182
 
@@ -358,13 +199,6 @@ Optional pagination is available by setting page_size parameter."""
358
199
  "name": entry.name,
359
200
  "type": "directory",
360
201
  }
361
-
362
- # Add size info for detailed style
363
- if style == "detailed":
364
- try:
365
- entry_data["size"] = sum(f.stat().st_size for f in entry.rglob('*') if f.is_file())
366
- except Exception:
367
- entry_data["size"] = 0
368
202
 
369
203
  # Check if we should filter this directory
370
204
  if should_filter(entry):
@@ -387,80 +221,42 @@ Optional pagination is available by setting page_size parameter."""
387
221
  # Files should be at the same level check as directories
388
222
  if depth <= 0 or current_depth < depth:
389
223
  stats["files"] += 1
390
- file_data = {"name": entry.name, "type": "file"}
391
-
392
- # Add size info for detailed style
393
- if style == "detailed":
394
- try:
395
- file_data["size"] = entry.stat().st_size
396
- except Exception:
397
- file_data["size"] = 0
398
-
399
- result.append(file_data)
224
+ # Add file entry
225
+ result.append({"name": entry.name, "type": "file"})
400
226
 
401
227
  except Exception as e:
402
228
  await tool_ctx.warning(f"Error processing {current_path}: {str(e)}")
403
229
 
404
230
  return result
405
231
 
406
- # Format the tree based on style
407
- def format_tree(tree_data: list[dict[str, Any]], level: int = 0, prefix: str = "", is_last: bool = True) -> list[str]:
232
+ # Format the tree as a simple indented structure
233
+ def format_tree(tree_data: list[dict[str, Any]], level: int = 0) -> list[str]:
408
234
  lines = []
409
235
 
410
- for i, item in enumerate(tree_data):
411
- is_last_item = i == len(tree_data) - 1
412
-
413
- if style == "unix":
414
- # Unix tree style with ASCII art
415
- if level == 0:
416
- current_prefix = ""
417
- next_prefix = ""
418
- else:
419
- if is_last_item:
420
- current_prefix = prefix + "└── "
421
- next_prefix = prefix + " "
422
- else:
423
- current_prefix = prefix + "├── "
424
- next_prefix = prefix + "│ "
425
- else:
426
- # Compact or detailed style with simple indentation
427
- current_prefix = " " * level
428
- next_prefix = " " * (level + 1)
236
+ for item in tree_data:
237
+ # Indentation based on level
238
+ indent = " " * level
429
239
 
430
240
  # Format based on type
431
241
  if item["type"] == "directory":
432
242
  if "skipped" in item:
433
- line = f"{current_prefix}{item['name']}/ [skipped - {item['skipped']}]"
243
+ lines.append(f"{indent}{item['name']}/ [skipped - {item['skipped']}]")
434
244
  else:
435
- line = f"{current_prefix}{item['name']}/"
436
- if style == "detailed" and "size" in item:
437
- line += f" ({self._format_size(item['size'])})"
438
- lines.append(line)
439
-
440
- # Add children with increased indentation if present
441
- if "children" in item and "skipped" not in item:
442
- lines.extend(format_tree(item["children"], level + 1, next_prefix, is_last_item))
245
+ lines.append(f"{indent}{item['name']}/")
246
+ # Add children with increased indentation if present
247
+ if "children" in item:
248
+ lines.extend(format_tree(item["children"], level + 1))
443
249
  else:
444
250
  # File
445
- line = f"{current_prefix}{item['name']}"
446
- if style == "detailed" and "size" in item:
447
- line += f" ({self._format_size(item['size'])})"
448
- lines.append(line)
251
+ lines.append(f"{indent}{item['name']}")
449
252
 
450
253
  return lines
451
254
 
452
255
  # Build tree starting from the requested directory
453
256
  tree_data = await build_tree(dir_path)
454
257
 
455
- # Format based on style
456
- if style == "unix":
457
- # Start with the root directory name
458
- formatted_lines = [str(dir_path)]
459
- formatted_lines.extend(format_tree(tree_data))
460
- else:
461
- formatted_lines = format_tree(tree_data)
462
-
463
- formatted_output = "\n".join(formatted_lines)
258
+ # Format as simple text
259
+ formatted_output = "\n".join(format_tree(tree_data))
464
260
 
465
261
  # Add stats summary
466
262
  summary = (
@@ -470,7 +266,7 @@ Optional pagination is available by setting page_size parameter."""
470
266
  )
471
267
 
472
268
  await tool_ctx.info(
473
- f"Generated directory tree for {path} (depth: {depth}, include_filtered: {include_filtered}, style: {style})"
269
+ f"Generated directory tree for {path} (depth: {depth}, include_filtered: {include_filtered})"
474
270
  )
475
271
 
476
272
  # Truncate response to stay within token limits
@@ -478,43 +274,11 @@ Optional pagination is available by setting page_size parameter."""
478
274
  return truncate_response(
479
275
  full_response,
480
276
  max_tokens=25000,
481
- truncation_message="\n\n[Response truncated due to token limit. Please use pagination (page_size parameter) or a smaller depth.]",
277
+ truncation_message="\n\n[Response truncated due to token limit. Please use a smaller depth, specific subdirectory, or the paginated version of this tool.]",
482
278
  )
483
279
  except Exception as e:
484
280
  await tool_ctx.error(f"Error generating directory tree: {str(e)}")
485
- if page_size:
486
- return {"error": f"Error generating directory tree: {str(e)}"}
487
281
  return f"Error generating directory tree: {str(e)}"
488
-
489
- def _format_entries(self, entries: List[Dict[str, Any]], style: str) -> List[str]:
490
- """Format entries for paginated output."""
491
- formatted = []
492
- for entry in entries:
493
- indent = " " * entry["depth"]
494
- name = entry["name"]
495
-
496
- if entry["type"] == "directory":
497
- if "skipped" in entry:
498
- line = f"{indent}{name}/ [skipped - {entry['skipped']}]"
499
- else:
500
- line = f"{indent}{name}/"
501
- if style == "detailed" and "size" in entry:
502
- line += f" ({self._format_size(entry['size'])})"
503
- else:
504
- line = f"{indent}{name}"
505
- if style == "detailed" and "size" in entry:
506
- line += f" ({self._format_size(entry['size'])})"
507
-
508
- formatted.append(line)
509
- return formatted
510
-
511
- def _format_size(self, size: int) -> str:
512
- """Format file size in human-readable format."""
513
- for unit in ["B", "KB", "MB", "GB", "TB"]:
514
- if size < 1024.0:
515
- return f"{size:.1f}{unit}"
516
- size /= 1024.0
517
- return f"{size:.1f}PB"
518
282
 
519
283
  @override
520
284
  def register(self, mcp_server: FastMCP) -> None:
@@ -534,16 +298,5 @@ Optional pagination is available by setting page_size parameter."""
534
298
  path: DirectoryPath,
535
299
  depth: Depth = 3,
536
300
  include_filtered: IncludeFiltered = False,
537
- page_size: PageSize = None,
538
- page: Page = 1,
539
- style: Style = "compact",
540
- ) -> Union[str, Dict[str, Any]]:
541
- return await tool_self.call(
542
- ctx,
543
- path=path,
544
- depth=depth,
545
- include_filtered=include_filtered,
546
- page_size=page_size,
547
- page=page,
548
- style=style
549
- )
301
+ ) -> str:
302
+ return await tool_self.call(ctx, path=path, depth=depth, include_filtered=include_filtered)