chuk-tool-processor 0.6__py3-none-any.whl → 0.6.2__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 chuk-tool-processor might be problematic. Click here for more details.

@@ -1,55 +1,57 @@
1
1
  #!/usr/bin/env python
2
2
  # chuk_tool_processor/mcp/register_mcp_tools.py
3
3
  """
4
- Discover the remote MCP tools exposed by a :class:`~chuk_tool_processor.mcp.stream_manager.StreamManager`
5
- instance and register them in the local CHUK registry.
4
+ Discover the remote MCP tools exposed by a StreamManager and register them locally.
6
5
 
7
- The helper is now **async-native** - call it with ``await``.
6
+ CLEAN & SIMPLE: Just the essentials - create MCPTool wrappers for remote tools.
8
7
  """
9
8
 
10
9
  from __future__ import annotations
11
10
 
12
- from typing import Any, Dict, List
11
+ from typing import Any, Dict, List, Optional
13
12
 
14
13
  from chuk_tool_processor.logging import get_logger
15
- from chuk_tool_processor.mcp.mcp_tool import MCPTool
14
+ from chuk_tool_processor.mcp.mcp_tool import MCPTool, RecoveryConfig
16
15
  from chuk_tool_processor.mcp.stream_manager import StreamManager
17
16
  from chuk_tool_processor.registry.provider import ToolRegistryProvider
18
17
 
19
18
  logger = get_logger("chuk_tool_processor.mcp.register")
20
19
 
21
20
 
22
- # --------------------------------------------------------------------------- #
23
- # public API
24
- # --------------------------------------------------------------------------- #
25
21
  async def register_mcp_tools(
26
22
  stream_manager: StreamManager,
27
23
  namespace: str = "mcp",
24
+ *,
25
+ # Optional resilience configuration
26
+ default_timeout: float = 30.0,
27
+ enable_resilience: bool = True,
28
+ recovery_config: Optional[RecoveryConfig] = None,
28
29
  ) -> List[str]:
29
30
  """
30
- Pull the *remote* tool catalogue from *stream_manager* and create a local
31
- async wrapper (:class:`MCPTool`) for each entry.
31
+ Pull the remote tool catalogue and create local MCPTool wrappers.
32
32
 
33
33
  Parameters
34
34
  ----------
35
35
  stream_manager
36
- An **initialised** :class:`~chuk_tool_processor.mcp.stream_manager.StreamManager`.
36
+ An initialised StreamManager.
37
37
  namespace
38
- All tools are registered twice:
39
-
40
- * under their original name in *namespace* (e.g. ``"mcp.echo"``), and
41
- * mirrored into the ``"default"`` namespace as ``"{namespace}.{name}"``
42
- so that parsers may reference them unambiguously.
38
+ Tools are registered under their original name in the specified namespace.
39
+ default_timeout
40
+ Default timeout for tool execution
41
+ enable_resilience
42
+ Whether to enable resilience features (circuit breaker, retries)
43
+ recovery_config
44
+ Optional custom recovery configuration
43
45
 
44
46
  Returns
45
47
  -------
46
48
  list[str]
47
- The *plain* tool names that were registered (duplicates are ignored).
49
+ The tool names that were registered.
48
50
  """
49
51
  registry = await ToolRegistryProvider.get_registry()
50
52
  registered: List[str] = []
51
53
 
52
- # 1️⃣ ask the stream-manager for its catalogue
54
+ # Get the remote tool catalogue
53
55
  mcp_tools: List[Dict[str, Any]] = stream_manager.get_all_tools()
54
56
 
55
57
  for tool_def in mcp_tools:
@@ -67,9 +69,15 @@ async def register_mcp_tools(
67
69
  }
68
70
 
69
71
  try:
70
- wrapper = MCPTool(tool_name, stream_manager)
72
+ # Create MCPTool wrapper with optional resilience configuration
73
+ wrapper = MCPTool(
74
+ tool_name=tool_name,
75
+ stream_manager=stream_manager,
76
+ default_timeout=default_timeout,
77
+ enable_resilience=enable_resilience,
78
+ recovery_config=recovery_config,
79
+ )
71
80
 
72
- # ── primary registration ──────────────────────────────────────
73
81
  await registry.register_tool(
74
82
  wrapper,
75
83
  name=tool_name,
@@ -77,24 +85,63 @@ async def register_mcp_tools(
77
85
  metadata=meta,
78
86
  )
79
87
 
80
- # ── mirror into "default" namespace with dotted name ──────────
81
- dotted_name = f"{namespace}.{tool_name}"
82
- await registry.register_tool(
83
- wrapper,
84
- name=dotted_name,
85
- namespace="default",
86
- metadata={**meta, "tags": meta["tags"] | {"namespaced"}},
87
- )
88
-
89
88
  registered.append(tool_name)
90
89
  logger.debug(
91
- "MCP tool '%s' registered (as '%s' & '%s')",
90
+ "MCP tool '%s' registered as '%s:%s'",
91
+ tool_name,
92
+ namespace,
92
93
  tool_name,
93
- f"{namespace}:{tool_name}",
94
- f"default:{dotted_name}",
95
94
  )
96
- except Exception as exc: # noqa: BLE001
95
+ except Exception as exc:
97
96
  logger.error("Failed to register MCP tool '%s': %s", tool_name, exc)
98
97
 
99
98
  logger.info("MCP registration complete - %d tool(s) available", len(registered))
100
99
  return registered
100
+
101
+
102
+ async def update_mcp_tools_stream_manager(
103
+ namespace: str,
104
+ new_stream_manager: Optional[StreamManager],
105
+ ) -> int:
106
+ """
107
+ Update the StreamManager reference for all MCP tools in a namespace.
108
+
109
+ Useful for reconnecting tools after StreamManager recovery at the service level.
110
+
111
+ Parameters
112
+ ----------
113
+ namespace
114
+ The namespace containing MCP tools to update
115
+ new_stream_manager
116
+ The new StreamManager to use, or None to disconnect
117
+
118
+ Returns
119
+ -------
120
+ int
121
+ Number of tools updated
122
+ """
123
+ registry = await ToolRegistryProvider.get_registry()
124
+ updated_count = 0
125
+
126
+ try:
127
+ # List all tools in the namespace
128
+ all_tools = await registry.list_tools()
129
+ namespace_tools = [name for ns, name in all_tools if ns == namespace]
130
+
131
+ for tool_name in namespace_tools:
132
+ try:
133
+ tool = await registry.get_tool(tool_name, namespace)
134
+ if tool and hasattr(tool, 'set_stream_manager'):
135
+ tool.set_stream_manager(new_stream_manager)
136
+ updated_count += 1
137
+ logger.debug(f"Updated StreamManager for tool '{namespace}:{tool_name}'")
138
+ except Exception as e:
139
+ logger.warning(f"Failed to update StreamManager for tool '{namespace}:{tool_name}': {e}")
140
+
141
+ action = "connected" if new_stream_manager else "disconnected"
142
+ logger.info(f"StreamManager {action} for {updated_count} tools in namespace '{namespace}'")
143
+
144
+ except Exception as e:
145
+ logger.error(f"Failed to update tools in namespace '{namespace}': {e}")
146
+
147
+ return updated_count