hanzo-mcp 0.7.6__py3-none-any.whl → 0.8.0__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 (178) hide show
  1. hanzo_mcp/__init__.py +7 -1
  2. hanzo_mcp/__main__.py +1 -1
  3. hanzo_mcp/analytics/__init__.py +2 -2
  4. hanzo_mcp/analytics/posthog_analytics.py +76 -82
  5. hanzo_mcp/cli.py +31 -36
  6. hanzo_mcp/cli_enhanced.py +94 -72
  7. hanzo_mcp/cli_plugin.py +27 -17
  8. hanzo_mcp/config/__init__.py +2 -2
  9. hanzo_mcp/config/settings.py +112 -88
  10. hanzo_mcp/config/tool_config.py +32 -34
  11. hanzo_mcp/dev_server.py +66 -67
  12. hanzo_mcp/prompts/__init__.py +94 -12
  13. hanzo_mcp/prompts/enhanced_prompts.py +809 -0
  14. hanzo_mcp/prompts/example_custom_prompt.py +6 -5
  15. hanzo_mcp/prompts/project_todo_reminder.py +0 -1
  16. hanzo_mcp/prompts/tool_explorer.py +10 -7
  17. hanzo_mcp/server.py +17 -21
  18. hanzo_mcp/server_enhanced.py +15 -22
  19. hanzo_mcp/tools/__init__.py +56 -28
  20. hanzo_mcp/tools/agent/__init__.py +16 -19
  21. hanzo_mcp/tools/agent/agent.py +82 -65
  22. hanzo_mcp/tools/agent/agent_tool.py +152 -122
  23. hanzo_mcp/tools/agent/agent_tool_v1_deprecated.py +66 -62
  24. hanzo_mcp/tools/agent/clarification_protocol.py +55 -50
  25. hanzo_mcp/tools/agent/clarification_tool.py +11 -10
  26. hanzo_mcp/tools/agent/claude_cli_tool.py +21 -20
  27. hanzo_mcp/tools/agent/claude_desktop_auth.py +130 -144
  28. hanzo_mcp/tools/agent/cli_agent_base.py +59 -53
  29. hanzo_mcp/tools/agent/code_auth.py +102 -107
  30. hanzo_mcp/tools/agent/code_auth_tool.py +28 -27
  31. hanzo_mcp/tools/agent/codex_cli_tool.py +20 -19
  32. hanzo_mcp/tools/agent/critic_tool.py +86 -73
  33. hanzo_mcp/tools/agent/gemini_cli_tool.py +21 -20
  34. hanzo_mcp/tools/agent/grok_cli_tool.py +21 -20
  35. hanzo_mcp/tools/agent/iching_tool.py +404 -139
  36. hanzo_mcp/tools/agent/network_tool.py +89 -73
  37. hanzo_mcp/tools/agent/prompt.py +2 -1
  38. hanzo_mcp/tools/agent/review_tool.py +101 -98
  39. hanzo_mcp/tools/agent/swarm_alias.py +87 -0
  40. hanzo_mcp/tools/agent/swarm_tool.py +246 -161
  41. hanzo_mcp/tools/agent/swarm_tool_v1_deprecated.py +134 -92
  42. hanzo_mcp/tools/agent/tool_adapter.py +21 -11
  43. hanzo_mcp/tools/common/__init__.py +1 -1
  44. hanzo_mcp/tools/common/base.py +3 -5
  45. hanzo_mcp/tools/common/batch_tool.py +46 -39
  46. hanzo_mcp/tools/common/config_tool.py +120 -84
  47. hanzo_mcp/tools/common/context.py +1 -5
  48. hanzo_mcp/tools/common/context_fix.py +5 -3
  49. hanzo_mcp/tools/common/critic_tool.py +4 -8
  50. hanzo_mcp/tools/common/decorators.py +58 -56
  51. hanzo_mcp/tools/common/enhanced_base.py +29 -32
  52. hanzo_mcp/tools/common/fastmcp_pagination.py +91 -94
  53. hanzo_mcp/tools/common/forgiving_edit.py +91 -87
  54. hanzo_mcp/tools/common/mode.py +15 -17
  55. hanzo_mcp/tools/common/mode_loader.py +27 -24
  56. hanzo_mcp/tools/common/paginated_base.py +61 -53
  57. hanzo_mcp/tools/common/paginated_response.py +72 -79
  58. hanzo_mcp/tools/common/pagination.py +50 -53
  59. hanzo_mcp/tools/common/permissions.py +4 -4
  60. hanzo_mcp/tools/common/personality.py +186 -138
  61. hanzo_mcp/tools/common/plugin_loader.py +54 -54
  62. hanzo_mcp/tools/common/stats.py +65 -47
  63. hanzo_mcp/tools/common/test_helpers.py +31 -0
  64. hanzo_mcp/tools/common/thinking_tool.py +4 -8
  65. hanzo_mcp/tools/common/tool_disable.py +17 -12
  66. hanzo_mcp/tools/common/tool_enable.py +13 -14
  67. hanzo_mcp/tools/common/tool_list.py +36 -28
  68. hanzo_mcp/tools/common/truncate.py +23 -23
  69. hanzo_mcp/tools/config/__init__.py +4 -4
  70. hanzo_mcp/tools/config/config_tool.py +42 -29
  71. hanzo_mcp/tools/config/index_config.py +37 -34
  72. hanzo_mcp/tools/config/mode_tool.py +175 -55
  73. hanzo_mcp/tools/database/__init__.py +15 -12
  74. hanzo_mcp/tools/database/database_manager.py +77 -75
  75. hanzo_mcp/tools/database/graph.py +137 -91
  76. hanzo_mcp/tools/database/graph_add.py +30 -18
  77. hanzo_mcp/tools/database/graph_query.py +178 -102
  78. hanzo_mcp/tools/database/graph_remove.py +33 -28
  79. hanzo_mcp/tools/database/graph_search.py +97 -75
  80. hanzo_mcp/tools/database/graph_stats.py +91 -59
  81. hanzo_mcp/tools/database/sql.py +107 -79
  82. hanzo_mcp/tools/database/sql_query.py +30 -24
  83. hanzo_mcp/tools/database/sql_search.py +29 -25
  84. hanzo_mcp/tools/database/sql_stats.py +47 -35
  85. hanzo_mcp/tools/editor/neovim_command.py +25 -28
  86. hanzo_mcp/tools/editor/neovim_edit.py +21 -23
  87. hanzo_mcp/tools/editor/neovim_session.py +60 -54
  88. hanzo_mcp/tools/filesystem/__init__.py +31 -30
  89. hanzo_mcp/tools/filesystem/ast_multi_edit.py +329 -249
  90. hanzo_mcp/tools/filesystem/ast_tool.py +4 -4
  91. hanzo_mcp/tools/filesystem/base.py +1 -1
  92. hanzo_mcp/tools/filesystem/batch_search.py +316 -224
  93. hanzo_mcp/tools/filesystem/content_replace.py +4 -4
  94. hanzo_mcp/tools/filesystem/diff.py +71 -59
  95. hanzo_mcp/tools/filesystem/directory_tree.py +7 -7
  96. hanzo_mcp/tools/filesystem/directory_tree_paginated.py +49 -37
  97. hanzo_mcp/tools/filesystem/edit.py +4 -4
  98. hanzo_mcp/tools/filesystem/find.py +173 -80
  99. hanzo_mcp/tools/filesystem/find_files.py +73 -52
  100. hanzo_mcp/tools/filesystem/git_search.py +157 -104
  101. hanzo_mcp/tools/filesystem/grep.py +8 -8
  102. hanzo_mcp/tools/filesystem/multi_edit.py +4 -8
  103. hanzo_mcp/tools/filesystem/read.py +12 -10
  104. hanzo_mcp/tools/filesystem/rules_tool.py +59 -43
  105. hanzo_mcp/tools/filesystem/search_tool.py +263 -207
  106. hanzo_mcp/tools/filesystem/symbols_tool.py +94 -54
  107. hanzo_mcp/tools/filesystem/tree.py +35 -33
  108. hanzo_mcp/tools/filesystem/unix_aliases.py +13 -18
  109. hanzo_mcp/tools/filesystem/watch.py +37 -36
  110. hanzo_mcp/tools/filesystem/write.py +4 -8
  111. hanzo_mcp/tools/jupyter/__init__.py +4 -4
  112. hanzo_mcp/tools/jupyter/base.py +4 -5
  113. hanzo_mcp/tools/jupyter/jupyter.py +67 -47
  114. hanzo_mcp/tools/jupyter/notebook_edit.py +4 -4
  115. hanzo_mcp/tools/jupyter/notebook_read.py +4 -7
  116. hanzo_mcp/tools/llm/__init__.py +5 -7
  117. hanzo_mcp/tools/llm/consensus_tool.py +72 -52
  118. hanzo_mcp/tools/llm/llm_manage.py +101 -60
  119. hanzo_mcp/tools/llm/llm_tool.py +226 -166
  120. hanzo_mcp/tools/llm/provider_tools.py +25 -26
  121. hanzo_mcp/tools/lsp/__init__.py +1 -1
  122. hanzo_mcp/tools/lsp/lsp_tool.py +228 -143
  123. hanzo_mcp/tools/mcp/__init__.py +2 -3
  124. hanzo_mcp/tools/mcp/mcp_add.py +27 -25
  125. hanzo_mcp/tools/mcp/mcp_remove.py +7 -8
  126. hanzo_mcp/tools/mcp/mcp_stats.py +23 -22
  127. hanzo_mcp/tools/mcp/mcp_tool.py +129 -98
  128. hanzo_mcp/tools/memory/__init__.py +39 -21
  129. hanzo_mcp/tools/memory/knowledge_tools.py +124 -99
  130. hanzo_mcp/tools/memory/memory_tools.py +90 -108
  131. hanzo_mcp/tools/search/__init__.py +7 -2
  132. hanzo_mcp/tools/search/find_tool.py +297 -212
  133. hanzo_mcp/tools/search/unified_search.py +366 -314
  134. hanzo_mcp/tools/shell/__init__.py +8 -7
  135. hanzo_mcp/tools/shell/auto_background.py +56 -49
  136. hanzo_mcp/tools/shell/base.py +1 -1
  137. hanzo_mcp/tools/shell/base_process.py +75 -75
  138. hanzo_mcp/tools/shell/bash_session.py +2 -2
  139. hanzo_mcp/tools/shell/bash_session_executor.py +4 -4
  140. hanzo_mcp/tools/shell/bash_tool.py +24 -31
  141. hanzo_mcp/tools/shell/command_executor.py +12 -12
  142. hanzo_mcp/tools/shell/logs.py +43 -33
  143. hanzo_mcp/tools/shell/npx.py +13 -13
  144. hanzo_mcp/tools/shell/npx_background.py +24 -21
  145. hanzo_mcp/tools/shell/npx_tool.py +18 -22
  146. hanzo_mcp/tools/shell/open.py +19 -21
  147. hanzo_mcp/tools/shell/pkill.py +31 -26
  148. hanzo_mcp/tools/shell/process_tool.py +32 -32
  149. hanzo_mcp/tools/shell/processes.py +57 -58
  150. hanzo_mcp/tools/shell/run_background.py +24 -25
  151. hanzo_mcp/tools/shell/run_command.py +5 -5
  152. hanzo_mcp/tools/shell/run_command_windows.py +5 -5
  153. hanzo_mcp/tools/shell/session_storage.py +3 -3
  154. hanzo_mcp/tools/shell/streaming_command.py +141 -126
  155. hanzo_mcp/tools/shell/uvx.py +24 -25
  156. hanzo_mcp/tools/shell/uvx_background.py +35 -33
  157. hanzo_mcp/tools/shell/uvx_tool.py +18 -22
  158. hanzo_mcp/tools/todo/__init__.py +6 -2
  159. hanzo_mcp/tools/todo/todo.py +50 -37
  160. hanzo_mcp/tools/todo/todo_read.py +5 -8
  161. hanzo_mcp/tools/todo/todo_write.py +5 -7
  162. hanzo_mcp/tools/vector/__init__.py +40 -28
  163. hanzo_mcp/tools/vector/ast_analyzer.py +176 -143
  164. hanzo_mcp/tools/vector/git_ingester.py +170 -179
  165. hanzo_mcp/tools/vector/index_tool.py +96 -44
  166. hanzo_mcp/tools/vector/infinity_store.py +283 -228
  167. hanzo_mcp/tools/vector/mock_infinity.py +39 -40
  168. hanzo_mcp/tools/vector/project_manager.py +88 -78
  169. hanzo_mcp/tools/vector/vector.py +59 -42
  170. hanzo_mcp/tools/vector/vector_index.py +30 -27
  171. hanzo_mcp/tools/vector/vector_search.py +64 -45
  172. hanzo_mcp/types.py +6 -4
  173. {hanzo_mcp-0.7.6.dist-info → hanzo_mcp-0.8.0.dist-info}/METADATA +1 -1
  174. hanzo_mcp-0.8.0.dist-info/RECORD +185 -0
  175. hanzo_mcp-0.7.6.dist-info/RECORD +0 -182
  176. {hanzo_mcp-0.7.6.dist-info → hanzo_mcp-0.8.0.dist-info}/WHEEL +0 -0
  177. {hanzo_mcp-0.7.6.dist-info → hanzo_mcp-0.8.0.dist-info}/entry_points.txt +0 -0
  178. {hanzo_mcp-0.7.6.dist-info → hanzo_mcp-0.8.0.dist-info}/top_level.txt +0 -0
@@ -3,16 +3,15 @@
3
3
  This module provides the CriticTool for Claude to engage in critical analysis and code review.
4
4
  """
5
5
 
6
- from typing import Annotated, TypedDict, Unpack, final, override
6
+ from typing import Unpack, Annotated, TypedDict, final, override
7
7
 
8
- from mcp.server.fastmcp import Context as MCPContext
9
- from mcp.server import FastMCP
10
8
  from pydantic import Field
9
+ from mcp.server import FastMCP
10
+ from mcp.server.fastmcp import Context as MCPContext
11
11
 
12
12
  from hanzo_mcp.tools.common.base import BaseTool
13
13
  from hanzo_mcp.tools.common.context import create_tool_context
14
14
 
15
-
16
15
  Analysis = Annotated[
17
16
  str,
18
17
  Field(
@@ -189,8 +188,5 @@ Continue with improvements based on this critical review."""
189
188
  tool_self = self # Create a reference to self for use in the closure
190
189
 
191
190
  @mcp_server.tool(name=self.name, description=self.description)
192
- async def critic(
193
- analysis: Analysis,
194
- ctx: MCPContext
195
- ) -> str:
191
+ async def critic(analysis: Analysis, ctx: MCPContext) -> str:
196
192
  return await tool_self.call(ctx, analysis=analysis)
@@ -4,47 +4,44 @@ This module provides decorators that handle common cross-cutting concerns
4
4
  for MCP tools, such as context normalization and error handling.
5
5
  """
6
6
 
7
- import functools
8
7
  import inspect
9
- from typing import Any, Callable, TypeVar, cast
10
- from collections.abc import Awaitable, Coroutine
11
-
12
- from mcp.server.fastmcp import Context as MCPContext
8
+ import functools
9
+ from typing import Any, TypeVar, Callable, cast
13
10
 
14
- F = TypeVar('F', bound=Callable[..., Any])
11
+ F = TypeVar("F", bound=Callable[..., Any])
15
12
 
16
13
 
17
14
  class MockContext:
18
15
  """Mock context for when no real context is available.
19
-
16
+
20
17
  This is used when tools are called externally through the MCP protocol
21
18
  and the Context parameter is not properly serialized.
22
19
  """
23
-
20
+
24
21
  def __init__(self):
25
22
  self.request_id = "external-request"
26
23
  self.client_id = "external-client"
27
-
24
+
28
25
  async def info(self, message: str) -> None:
29
26
  """Mock info logging - no-op for external calls."""
30
27
  pass
31
-
28
+
32
29
  async def debug(self, message: str) -> None:
33
30
  """Mock debug logging - no-op for external calls."""
34
31
  pass
35
-
32
+
36
33
  async def warning(self, message: str) -> None:
37
34
  """Mock warning logging - no-op for external calls."""
38
35
  pass
39
-
36
+
40
37
  async def error(self, message: str) -> None:
41
38
  """Mock error logging - no-op for external calls."""
42
39
  pass
43
-
40
+
44
41
  async def report_progress(self, current: int, total: int) -> None:
45
42
  """Mock progress reporting - no-op for external calls."""
46
43
  pass
47
-
44
+
48
45
  async def read_resource(self, uri: str) -> Any:
49
46
  """Mock resource reading - returns empty result."""
50
47
  return []
@@ -52,11 +49,11 @@ class MockContext:
52
49
 
53
50
  def with_context_normalization(func: F) -> F:
54
51
  """Decorator that normalizes the context parameter for MCP tools.
55
-
52
+
56
53
  This decorator intercepts the ctx parameter and ensures it's a valid
57
54
  MCPContext object, even when called externally where it might be
58
55
  passed as a string, dict, or None.
59
-
56
+
60
57
  Usage:
61
58
  @server.tool()
62
59
  @with_context_normalization
@@ -64,138 +61,143 @@ def with_context_normalization(func: F) -> F:
64
61
  # ctx is guaranteed to be a valid context object
65
62
  await ctx.info("Processing...")
66
63
  return "result"
67
-
64
+
68
65
  Args:
69
66
  func: The async function to decorate
70
-
67
+
71
68
  Returns:
72
69
  The decorated function with context normalization
73
70
  """
71
+
74
72
  @functools.wraps(func)
75
73
  async def wrapper(*args: Any, **kwargs: Any) -> Any:
76
74
  # Get function signature to find ctx parameter
77
75
  sig = inspect.signature(func)
78
76
  params = list(sig.parameters.keys())
79
-
77
+
80
78
  # Handle ctx in kwargs
81
- if 'ctx' in kwargs:
82
- ctx_value = kwargs['ctx']
79
+ if "ctx" in kwargs:
80
+ ctx_value = kwargs["ctx"]
83
81
  if not _is_valid_context(ctx_value):
84
- kwargs['ctx'] = MockContext()
85
-
82
+ kwargs["ctx"] = MockContext()
83
+
86
84
  # Handle ctx in args (positional)
87
- elif 'ctx' in params:
88
- ctx_index = params.index('ctx')
85
+ elif "ctx" in params:
86
+ ctx_index = params.index("ctx")
89
87
  if ctx_index < len(args):
90
88
  ctx_value = args[ctx_index]
91
89
  if not _is_valid_context(ctx_value):
92
90
  args_list = list(args)
93
91
  args_list[ctx_index] = MockContext()
94
92
  args = tuple(args_list)
95
-
93
+
96
94
  # Call the original function
97
95
  return await func(*args, **kwargs)
98
-
96
+
99
97
  return cast(F, wrapper)
100
98
 
101
99
 
102
100
  def _is_valid_context(ctx: Any) -> bool:
103
101
  """Check if an object is a valid MCPContext.
104
-
102
+
105
103
  Args:
106
104
  ctx: The object to check
107
-
105
+
108
106
  Returns:
109
107
  True if ctx is a valid context object
110
108
  """
111
109
  # Check for required context methods
112
110
  return (
113
- hasattr(ctx, 'info') and
114
- hasattr(ctx, 'debug') and
115
- hasattr(ctx, 'warning') and
116
- hasattr(ctx, 'error') and
117
- hasattr(ctx, 'report_progress') and
111
+ hasattr(ctx, "info")
112
+ and hasattr(ctx, "debug")
113
+ and hasattr(ctx, "warning")
114
+ and hasattr(ctx, "error")
115
+ and hasattr(ctx, "report_progress")
116
+ and
118
117
  # Ensure they're callable
119
- callable(getattr(ctx, 'info', None)) and
120
- callable(getattr(ctx, 'debug', None))
118
+ callable(getattr(ctx, "info", None))
119
+ and callable(getattr(ctx, "debug", None))
121
120
  )
122
121
 
123
122
 
124
123
  def mcp_tool(
125
- server: Any,
126
- name: str | None = None,
127
- description: str | None = None
124
+ server: Any, name: str | None = None, description: str | None = None
128
125
  ) -> Callable[[F], F]:
129
126
  """Enhanced MCP tool decorator that includes context normalization.
130
-
127
+
131
128
  This decorator combines the standard MCP tool registration with
132
129
  automatic context normalization, providing a single-point solution
133
130
  for all tools.
134
-
131
+
135
132
  Usage:
136
133
  @mcp_tool(server, name="my_tool", description="Does something")
137
134
  async def my_tool(ctx: MCPContext, param: str) -> str:
138
135
  await ctx.info("Processing...")
139
136
  return "result"
140
-
137
+
141
138
  Args:
142
139
  server: The MCP server instance
143
140
  name: Optional tool name (defaults to function name)
144
141
  description: Optional tool description
145
-
142
+
146
143
  Returns:
147
144
  Decorator function
148
145
  """
146
+
149
147
  def decorator(func: F) -> F:
150
148
  # Apply context normalization first
151
149
  normalized_func = with_context_normalization(func)
152
-
150
+
153
151
  # Then apply the server's tool decorator
154
- if hasattr(server, 'tool'):
152
+ if hasattr(server, "tool"):
155
153
  # Use the server's tool decorator
156
154
  server_decorator = server.tool(name=name, description=description)
157
155
  return server_decorator(normalized_func)
158
156
  else:
159
157
  # Fallback if server doesn't have tool method
160
158
  return normalized_func
161
-
159
+
162
160
  return decorator
163
161
 
164
162
 
165
163
  def create_tool_handler(server: Any, tool: Any) -> Callable[[], None]:
166
164
  """Create a standardized tool registration handler.
167
-
165
+
168
166
  This function creates a registration method that automatically applies
169
167
  context normalization to any tool handler registered with the server.
170
-
168
+
171
169
  Usage:
172
170
  class MyTool(BaseTool):
173
171
  def register(self, mcp_server):
174
172
  register = create_tool_handler(mcp_server, self)
175
173
  register()
176
-
174
+
177
175
  Args:
178
176
  server: The MCP server instance
179
177
  tool: The tool instance with name, description, and handler
180
-
178
+
181
179
  Returns:
182
180
  A function that registers the tool with context normalization
183
181
  """
182
+
184
183
  def register_with_normalization():
185
184
  # Get the original register method
186
185
  original_register = tool.__class__.register
187
-
186
+
188
187
  # Temporarily replace server.tool to wrap with normalization
189
188
  original_tool_decorator = server.tool
190
-
189
+
191
190
  def normalized_tool_decorator(name=None, description=None):
192
191
  def decorator(func):
193
192
  # Apply context normalization
194
193
  normalized = with_context_normalization(func)
195
194
  # Apply original decorator
196
- return original_tool_decorator(name=name, description=description)(normalized)
195
+ return original_tool_decorator(name=name, description=description)(
196
+ normalized
197
+ )
198
+
197
199
  return decorator
198
-
200
+
199
201
  # Monkey-patch temporarily
200
202
  server.tool = normalized_tool_decorator
201
203
  try:
@@ -204,5 +206,5 @@ def create_tool_handler(server: Any, tool: Any) -> Callable[[], None]:
204
206
  finally:
205
207
  # Restore original
206
208
  server.tool = original_tool_decorator
207
-
208
- return register_with_normalization
209
+
210
+ return register_with_normalization
@@ -5,9 +5,9 @@ context normalization and other cross-cutting concerns, ensuring
5
5
  consistent behavior across all tools.
6
6
  """
7
7
 
8
- from abc import ABC, abstractmethod
9
- from typing import Any, get_type_hints, get_args, get_origin
10
8
  import inspect
9
+ from abc import ABC, abstractmethod
10
+ from typing import Any, get_type_hints
11
11
 
12
12
  from mcp.server import FastMCP
13
13
  from mcp.server.fastmcp import Context as MCPContext
@@ -18,40 +18,37 @@ from hanzo_mcp.tools.common.decorators import with_context_normalization
18
18
 
19
19
  class EnhancedBaseTool(BaseTool, ABC):
20
20
  """Enhanced base class for MCP tools with automatic context normalization.
21
-
21
+
22
22
  This base class automatically wraps the tool registration to include
23
23
  context normalization, ensuring that all tools handle external calls
24
24
  properly without requiring manual decoration or copy-pasted code.
25
25
  """
26
-
26
+
27
27
  def register(self, mcp_server: FastMCP) -> None:
28
28
  """Register this tool with automatic context normalization.
29
-
29
+
30
30
  This method automatically applies context normalization to the tool
31
31
  handler, ensuring it works properly when called externally.
32
-
32
+
33
33
  Args:
34
34
  mcp_server: The FastMCP server instance
35
35
  """
36
36
  # Get the tool method from the subclass
37
37
  tool_method = self._create_tool_handler()
38
-
38
+
39
39
  # Apply context normalization decorator
40
40
  normalized_method = with_context_normalization(tool_method)
41
-
41
+
42
42
  # Register with the server
43
- mcp_server.tool(
44
- name=self.name,
45
- description=self.description
46
- )(normalized_method)
47
-
43
+ mcp_server.tool(name=self.name, description=self.description)(normalized_method)
44
+
48
45
  @abstractmethod
49
46
  def _create_tool_handler(self) -> Any:
50
47
  """Create the tool handler function.
51
-
48
+
52
49
  Subclasses must implement this to return an async function
53
50
  that will be registered as the tool handler.
54
-
51
+
55
52
  Returns:
56
53
  An async function that handles tool calls
57
54
  """
@@ -60,47 +57,47 @@ class EnhancedBaseTool(BaseTool, ABC):
60
57
 
61
58
  class AutoRegisterTool(BaseTool, ABC):
62
59
  """Base class that automatically generates tool handlers from the call method.
63
-
60
+
64
61
  This base class inspects the call method signature and automatically
65
62
  creates a properly typed tool handler with context normalization.
66
63
  """
67
-
64
+
68
65
  def register(self, mcp_server: FastMCP) -> None:
69
66
  """Register this tool with automatic handler generation.
70
-
67
+
71
68
  This method inspects the call method signature and automatically
72
69
  creates a tool handler with the correct parameters and types.
73
-
70
+
74
71
  Args:
75
72
  mcp_server: The FastMCP server instance
76
73
  """
77
74
  # Get the call method signature
78
75
  call_method = self.call
79
76
  sig = inspect.signature(call_method)
80
-
77
+
81
78
  # Get type hints for proper typing
82
79
  hints = get_type_hints(call_method)
83
-
80
+
84
81
  # Create a dynamic handler function
85
82
  tool_self = self
86
-
83
+
87
84
  # Build the handler dynamically based on the call signature
88
85
  params = list(sig.parameters.items())
89
-
86
+
90
87
  # Skip 'self' and 'ctx' parameters
91
- tool_params = [(name, param) for name, param in params
92
- if name not in ('self', 'ctx')]
93
-
88
+ tool_params = [
89
+ (name, param) for name, param in params if name not in ("self", "ctx")
90
+ ]
91
+
94
92
  # Create the handler function dynamically
95
93
  async def handler(ctx: MCPContext, **kwargs: Any) -> Any:
96
94
  # Call the tool's call method with the context and parameters
97
95
  return await tool_self.call(ctx, **kwargs)
98
-
96
+
99
97
  # Apply context normalization
100
98
  normalized_handler = with_context_normalization(handler)
101
-
99
+
102
100
  # Register with the server
103
- mcp_server.tool(
104
- name=self.name,
105
- description=self.description
106
- )(normalized_handler)
101
+ mcp_server.tool(name=self.name, description=self.description)(
102
+ normalized_handler
103
+ )