chuk-tool-processor 0.5__py3-none-any.whl → 0.5.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.
- chuk_tool_processor/mcp/transport/stdio_transport.py +320 -122
- {chuk_tool_processor-0.5.dist-info → chuk_tool_processor-0.5.2.dist-info}/METADATA +2 -2
- {chuk_tool_processor-0.5.dist-info → chuk_tool_processor-0.5.2.dist-info}/RECORD +5 -5
- {chuk_tool_processor-0.5.dist-info → chuk_tool_processor-0.5.2.dist-info}/WHEEL +0 -0
- {chuk_tool_processor-0.5.dist-info → chuk_tool_processor-0.5.2.dist-info}/top_level.txt +0 -0
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# chuk_tool_processor/mcp/transport/stdio_transport.py
|
|
2
2
|
from __future__ import annotations
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
import asyncio
|
|
5
5
|
import json
|
|
6
6
|
from typing import Dict, Any, List, Optional
|
|
7
|
-
import
|
|
7
|
+
import logging
|
|
8
8
|
|
|
9
9
|
# ------------------------------------------------------------------ #
|
|
10
10
|
# Local import #
|
|
@@ -12,184 +12,382 @@ import asyncio
|
|
|
12
12
|
from .base_transport import MCPBaseTransport
|
|
13
13
|
|
|
14
14
|
# ------------------------------------------------------------------ #
|
|
15
|
-
# chuk-
|
|
15
|
+
# New chuk-mcp API imports only #
|
|
16
16
|
# ------------------------------------------------------------------ #
|
|
17
|
-
from chuk_mcp.
|
|
18
|
-
from chuk_mcp.
|
|
19
|
-
from chuk_mcp.mcp_client.messages.ping.send_messages import send_ping
|
|
17
|
+
from chuk_mcp.transports.stdio import stdio_client
|
|
18
|
+
from chuk_mcp.transports.stdio.parameters import StdioParameters
|
|
20
19
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
20
|
+
from chuk_mcp.protocol.messages import (
|
|
21
|
+
send_initialize,
|
|
22
|
+
send_ping,
|
|
24
23
|
send_tools_list,
|
|
24
|
+
send_tools_call,
|
|
25
25
|
)
|
|
26
26
|
|
|
27
|
-
#
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
27
|
+
# Try to import resources and prompts if available
|
|
28
|
+
try:
|
|
29
|
+
from chuk_mcp.protocol.messages import (
|
|
30
|
+
send_resources_list,
|
|
31
|
+
send_resources_read,
|
|
32
|
+
)
|
|
33
|
+
HAS_RESOURCES = True
|
|
34
|
+
except ImportError:
|
|
35
|
+
HAS_RESOURCES = False
|
|
36
|
+
|
|
37
|
+
try:
|
|
38
|
+
from chuk_mcp.protocol.messages import (
|
|
39
|
+
send_prompts_list,
|
|
40
|
+
send_prompts_get,
|
|
41
|
+
)
|
|
42
|
+
HAS_PROMPTS = True
|
|
43
|
+
except ImportError:
|
|
44
|
+
HAS_PROMPTS = False
|
|
45
|
+
|
|
46
|
+
logger = logging.getLogger(__name__)
|
|
34
47
|
|
|
35
48
|
|
|
36
49
|
class StdioTransport(MCPBaseTransport):
|
|
37
50
|
"""
|
|
38
|
-
|
|
51
|
+
STDIO transport for MCP communication using new chuk-mcp APIs.
|
|
39
52
|
"""
|
|
40
53
|
|
|
41
54
|
def __init__(self, server_params):
|
|
42
|
-
|
|
55
|
+
"""
|
|
56
|
+
Initialize STDIO transport.
|
|
57
|
+
|
|
58
|
+
Args:
|
|
59
|
+
server_params: Either a dict with 'command' and 'args',
|
|
60
|
+
or a StdioParameters object
|
|
61
|
+
"""
|
|
62
|
+
# Convert dict format to StdioParameters
|
|
63
|
+
if isinstance(server_params, dict):
|
|
64
|
+
self.server_params = StdioParameters(
|
|
65
|
+
command=server_params.get('command', 'python'),
|
|
66
|
+
args=server_params.get('args', [])
|
|
67
|
+
)
|
|
68
|
+
else:
|
|
69
|
+
self.server_params = server_params
|
|
70
|
+
|
|
43
71
|
self.read_stream = None
|
|
44
72
|
self.write_stream = None
|
|
45
|
-
self.
|
|
73
|
+
self._client_context = None
|
|
46
74
|
|
|
47
75
|
# --------------------------------------------------------------------- #
|
|
48
76
|
# Connection management #
|
|
49
77
|
# --------------------------------------------------------------------- #
|
|
50
78
|
async def initialize(self) -> bool:
|
|
79
|
+
"""Initialize the STDIO transport."""
|
|
51
80
|
try:
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
self.read_stream, self.write_stream = await self.
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
81
|
+
logger.info("Initializing STDIO transport...")
|
|
82
|
+
|
|
83
|
+
# Use the new stdio_client context manager
|
|
84
|
+
self._client_context = stdio_client(self.server_params)
|
|
85
|
+
self.read_stream, self.write_stream = await self._client_context.__aenter__()
|
|
86
|
+
|
|
87
|
+
# Send initialize message
|
|
88
|
+
logger.debug("Sending initialize message...")
|
|
60
89
|
init_result = await send_initialize(self.read_stream, self.write_stream)
|
|
61
|
-
|
|
90
|
+
|
|
91
|
+
if init_result:
|
|
92
|
+
logger.info("STDIO transport initialized successfully")
|
|
93
|
+
return True
|
|
94
|
+
else:
|
|
95
|
+
logger.error("Initialize message failed")
|
|
96
|
+
await self._cleanup()
|
|
97
|
+
return False
|
|
62
98
|
|
|
63
|
-
except Exception as e:
|
|
64
|
-
|
|
99
|
+
except Exception as e:
|
|
100
|
+
logger.error(f"Error initializing STDIO transport: {e}", exc_info=True)
|
|
101
|
+
await self._cleanup()
|
|
102
|
+
return False
|
|
65
103
|
|
|
66
|
-
|
|
67
|
-
|
|
104
|
+
async def close(self) -> None:
|
|
105
|
+
"""Close the transport with proper error handling."""
|
|
106
|
+
try:
|
|
107
|
+
# Handle both old _context_stack and new _client_context for test compatibility
|
|
108
|
+
if hasattr(self, '_context_stack') and self._context_stack:
|
|
68
109
|
try:
|
|
69
110
|
await self._context_stack.__aexit__(None, None, None)
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
111
|
+
logger.debug("Context stack closed")
|
|
112
|
+
except asyncio.CancelledError:
|
|
113
|
+
# Expected during shutdown - don't log as error
|
|
114
|
+
logger.debug("Context stack close cancelled during shutdown")
|
|
115
|
+
except Exception as e:
|
|
116
|
+
logger.error(f"Error closing context stack: {e}")
|
|
117
|
+
elif self._client_context:
|
|
118
|
+
try:
|
|
119
|
+
await self._client_context.__aexit__(None, None, None)
|
|
120
|
+
logger.debug("STDIO client context closed")
|
|
121
|
+
except asyncio.CancelledError:
|
|
122
|
+
# Expected during shutdown - don't log as error
|
|
123
|
+
logger.debug("Client context close cancelled during shutdown")
|
|
124
|
+
except Exception as e:
|
|
125
|
+
logger.error(f"Error closing client context: {e}")
|
|
126
|
+
except Exception as e:
|
|
127
|
+
logger.error(f"Error during transport cleanup: {e}")
|
|
128
|
+
finally:
|
|
129
|
+
await self._cleanup()
|
|
73
130
|
|
|
74
|
-
async def
|
|
75
|
-
"""
|
|
76
|
-
#
|
|
77
|
-
self
|
|
131
|
+
async def _cleanup(self) -> None:
|
|
132
|
+
"""Internal cleanup method."""
|
|
133
|
+
# Clean up both old and new context attributes for test compatibility
|
|
134
|
+
if hasattr(self, '_context_stack'):
|
|
135
|
+
self._context_stack = None
|
|
136
|
+
self._client_context = None
|
|
78
137
|
self.read_stream = None
|
|
79
138
|
self.write_stream = None
|
|
80
139
|
|
|
81
140
|
# --------------------------------------------------------------------- #
|
|
82
|
-
#
|
|
141
|
+
# Core MCP Operations #
|
|
83
142
|
# --------------------------------------------------------------------- #
|
|
84
143
|
async def send_ping(self) -> bool:
|
|
144
|
+
"""Send a ping."""
|
|
85
145
|
if not self.read_stream or not self.write_stream:
|
|
146
|
+
logger.error("Cannot send ping: streams not available")
|
|
147
|
+
return False
|
|
148
|
+
|
|
149
|
+
try:
|
|
150
|
+
result = await send_ping(self.read_stream, self.write_stream)
|
|
151
|
+
logger.debug(f"Ping result: {result}")
|
|
152
|
+
return bool(result)
|
|
153
|
+
except Exception as e:
|
|
154
|
+
logger.error(f"Ping failed: {e}")
|
|
86
155
|
return False
|
|
87
|
-
return await send_ping(self.read_stream, self.write_stream)
|
|
88
156
|
|
|
89
157
|
async def get_tools(self) -> List[Dict[str, Any]]:
|
|
158
|
+
"""Get list of available tools."""
|
|
90
159
|
if not self.read_stream or not self.write_stream:
|
|
160
|
+
logger.error("Cannot get tools: streams not available")
|
|
161
|
+
return []
|
|
162
|
+
|
|
163
|
+
try:
|
|
164
|
+
tools_response = await send_tools_list(self.read_stream, self.write_stream)
|
|
165
|
+
|
|
166
|
+
# Handle both dict response and direct tools list
|
|
167
|
+
if isinstance(tools_response, dict):
|
|
168
|
+
tools = tools_response.get("tools", [])
|
|
169
|
+
elif isinstance(tools_response, list):
|
|
170
|
+
tools = tools_response
|
|
171
|
+
else:
|
|
172
|
+
logger.warning(f"Unexpected tools response type: {type(tools_response)}")
|
|
173
|
+
tools = []
|
|
174
|
+
|
|
175
|
+
logger.debug(f"Retrieved {len(tools)} tools")
|
|
176
|
+
return tools
|
|
177
|
+
|
|
178
|
+
except Exception as e:
|
|
179
|
+
logger.error(f"Error getting tools: {e}")
|
|
91
180
|
return []
|
|
92
|
-
tools_response = await send_tools_list(self.read_stream, self.write_stream)
|
|
93
|
-
return tools_response.get("tools", [])
|
|
94
181
|
|
|
95
|
-
|
|
96
|
-
# Resources / Prompts #
|
|
97
|
-
# --------------------------------------------------------------------- #
|
|
98
|
-
async def list_resources(self) -> Dict[str, Any]:
|
|
182
|
+
async def call_tool(self, tool_name: str, arguments: Dict[str, Any]) -> Dict[str, Any]:
|
|
99
183
|
"""
|
|
100
|
-
|
|
101
|
-
|
|
184
|
+
Execute a tool.
|
|
185
|
+
|
|
186
|
+
Returns normalized response in format:
|
|
187
|
+
{
|
|
188
|
+
"isError": bool,
|
|
189
|
+
"content": Any, # Result data if successful
|
|
190
|
+
"error": str # Error message if failed
|
|
191
|
+
}
|
|
102
192
|
"""
|
|
103
193
|
if not self.read_stream or not self.write_stream:
|
|
194
|
+
return {
|
|
195
|
+
"isError": True,
|
|
196
|
+
"error": "Transport not initialized"
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
try:
|
|
200
|
+
logger.debug(f"Calling tool {tool_name} with args: {arguments}")
|
|
201
|
+
|
|
202
|
+
raw_response = await send_tools_call(
|
|
203
|
+
self.read_stream,
|
|
204
|
+
self.write_stream,
|
|
205
|
+
tool_name,
|
|
206
|
+
arguments
|
|
207
|
+
)
|
|
208
|
+
|
|
209
|
+
logger.debug(f"Tool {tool_name} raw response: {raw_response}")
|
|
210
|
+
return self._normalize_tool_response(raw_response)
|
|
211
|
+
|
|
212
|
+
except Exception as e:
|
|
213
|
+
logger.error(f"Error calling tool {tool_name}: {e}")
|
|
214
|
+
return {
|
|
215
|
+
"isError": True,
|
|
216
|
+
"error": f"Tool execution failed: {str(e)}"
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
def _normalize_tool_response(self, raw_response: Dict[str, Any]) -> Dict[str, Any]:
|
|
220
|
+
"""Normalize tool response to consistent format."""
|
|
221
|
+
# Handle explicit error in response
|
|
222
|
+
if "error" in raw_response:
|
|
223
|
+
error_info = raw_response["error"]
|
|
224
|
+
if isinstance(error_info, dict):
|
|
225
|
+
error_msg = error_info.get("message", "Unknown error")
|
|
226
|
+
else:
|
|
227
|
+
error_msg = str(error_info)
|
|
228
|
+
|
|
229
|
+
return {
|
|
230
|
+
"isError": True,
|
|
231
|
+
"error": error_msg
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
# Handle successful response with result (MCP standard)
|
|
235
|
+
if "result" in raw_response:
|
|
236
|
+
result = raw_response["result"]
|
|
237
|
+
|
|
238
|
+
# If result has content, extract it
|
|
239
|
+
if isinstance(result, dict) and "content" in result:
|
|
240
|
+
return {
|
|
241
|
+
"isError": False,
|
|
242
|
+
"content": self._extract_content(result["content"])
|
|
243
|
+
}
|
|
244
|
+
else:
|
|
245
|
+
return {
|
|
246
|
+
"isError": False,
|
|
247
|
+
"content": result
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
# Handle direct content-based response
|
|
251
|
+
if "content" in raw_response:
|
|
252
|
+
return {
|
|
253
|
+
"isError": False,
|
|
254
|
+
"content": self._extract_content(raw_response["content"])
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
# Fallback: return whatever the server sent
|
|
258
|
+
return {
|
|
259
|
+
"isError": False,
|
|
260
|
+
"content": raw_response
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
def _extract_content(self, content_list: Any) -> Any:
|
|
264
|
+
"""Extract content from MCP content list format."""
|
|
265
|
+
if not isinstance(content_list, list) or not content_list:
|
|
266
|
+
return content_list
|
|
267
|
+
|
|
268
|
+
# Handle single content item (most common)
|
|
269
|
+
if len(content_list) == 1:
|
|
270
|
+
content_item = content_list[0]
|
|
271
|
+
if isinstance(content_item, dict):
|
|
272
|
+
if content_item.get("type") == "text":
|
|
273
|
+
text_content = content_item.get("text", "")
|
|
274
|
+
# Try to parse JSON, fall back to plain text
|
|
275
|
+
try:
|
|
276
|
+
return json.loads(text_content)
|
|
277
|
+
except json.JSONDecodeError:
|
|
278
|
+
return text_content
|
|
279
|
+
else:
|
|
280
|
+
# Non-text content (image, audio, etc.)
|
|
281
|
+
return content_item
|
|
282
|
+
|
|
283
|
+
# Multiple content items - return the list
|
|
284
|
+
return content_list
|
|
285
|
+
|
|
286
|
+
# --------------------------------------------------------------------- #
|
|
287
|
+
# Resources Operations (if available) #
|
|
288
|
+
# --------------------------------------------------------------------- #
|
|
289
|
+
async def list_resources(self) -> Dict[str, Any]:
|
|
290
|
+
"""Get list of available resources."""
|
|
291
|
+
if not HAS_RESOURCES:
|
|
292
|
+
logger.warning("Resources not supported in current chuk-mcp version")
|
|
293
|
+
return {}
|
|
294
|
+
|
|
295
|
+
if not self.read_stream or not self.write_stream:
|
|
296
|
+
logger.error("Cannot list resources: streams not available")
|
|
104
297
|
return {}
|
|
298
|
+
|
|
105
299
|
try:
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
300
|
+
response = await send_resources_list(self.read_stream, self.write_stream)
|
|
301
|
+
return response if isinstance(response, dict) else {}
|
|
302
|
+
except Exception as e:
|
|
303
|
+
logger.error(f"Error listing resources: {e}")
|
|
304
|
+
return {}
|
|
109
305
|
|
|
110
|
-
|
|
306
|
+
async def read_resource(self, uri: str) -> Dict[str, Any]:
|
|
307
|
+
"""Read a specific resource by URI."""
|
|
308
|
+
if not HAS_RESOURCES:
|
|
309
|
+
logger.warning("Resources not supported in current chuk-mcp version")
|
|
310
|
+
return {}
|
|
311
|
+
|
|
312
|
+
if not self.read_stream or not self.write_stream:
|
|
313
|
+
logger.error("Cannot read resource: streams not available")
|
|
314
|
+
return {}
|
|
315
|
+
|
|
316
|
+
try:
|
|
317
|
+
response = await send_resources_read(self.read_stream, self.write_stream, uri)
|
|
318
|
+
return response if isinstance(response, dict) else {}
|
|
319
|
+
except Exception as e:
|
|
320
|
+
logger.error(f"Error reading resource {uri}: {e}")
|
|
111
321
|
return {}
|
|
112
322
|
|
|
323
|
+
# --------------------------------------------------------------------- #
|
|
324
|
+
# Prompts Operations (if available) #
|
|
325
|
+
# --------------------------------------------------------------------- #
|
|
113
326
|
async def list_prompts(self) -> Dict[str, Any]:
|
|
114
|
-
"""
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
327
|
+
"""Get list of available prompts."""
|
|
328
|
+
if not HAS_PROMPTS:
|
|
329
|
+
logger.warning("Prompts not supported in current chuk-mcp version")
|
|
330
|
+
return {}
|
|
331
|
+
|
|
118
332
|
if not self.read_stream or not self.write_stream:
|
|
333
|
+
logger.error("Cannot list prompts: streams not available")
|
|
119
334
|
return {}
|
|
335
|
+
|
|
120
336
|
try:
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
337
|
+
response = await send_prompts_list(self.read_stream, self.write_stream)
|
|
338
|
+
return response if isinstance(response, dict) else {}
|
|
339
|
+
except Exception as e:
|
|
340
|
+
logger.error(f"Error listing prompts: {e}")
|
|
341
|
+
return {}
|
|
124
342
|
|
|
125
|
-
|
|
343
|
+
async def get_prompt(self, name: str, arguments: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
|
|
344
|
+
"""Get a specific prompt by name."""
|
|
345
|
+
if not HAS_PROMPTS:
|
|
346
|
+
logger.warning("Prompts not supported in current chuk-mcp version")
|
|
347
|
+
return {}
|
|
348
|
+
|
|
349
|
+
if not self.read_stream or not self.write_stream:
|
|
350
|
+
logger.error("Cannot get prompt: streams not available")
|
|
351
|
+
return {}
|
|
352
|
+
|
|
353
|
+
try:
|
|
354
|
+
response = await send_prompts_get(
|
|
355
|
+
self.read_stream,
|
|
356
|
+
self.write_stream,
|
|
357
|
+
name,
|
|
358
|
+
arguments or {}
|
|
359
|
+
)
|
|
360
|
+
return response if isinstance(response, dict) else {}
|
|
361
|
+
except Exception as e:
|
|
362
|
+
logger.error(f"Error getting prompt {name}: {e}")
|
|
126
363
|
return {}
|
|
127
364
|
|
|
128
|
-
#
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
return a single-element list when the transport is active.
|
|
134
|
-
"""
|
|
365
|
+
# --------------------------------------------------------------------- #
|
|
366
|
+
# Utility Methods #
|
|
367
|
+
# --------------------------------------------------------------------- #
|
|
368
|
+
def get_streams(self) -> List[tuple]:
|
|
369
|
+
"""Get the underlying streams for advanced usage."""
|
|
135
370
|
if self.read_stream and self.write_stream:
|
|
136
371
|
return [(self.read_stream, self.write_stream)]
|
|
137
372
|
return []
|
|
138
373
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
async def call_tool(
|
|
143
|
-
self, tool_name: str, arguments: Dict[str, Any]
|
|
144
|
-
) -> Dict[str, Any]:
|
|
145
|
-
"""
|
|
146
|
-
Execute *tool_name* with *arguments* and normalise the server's reply.
|
|
147
|
-
|
|
148
|
-
The echo-server often returns:
|
|
149
|
-
{
|
|
150
|
-
"content": [{"type":"text","text":"{\"message\":\"…\"}"}],
|
|
151
|
-
"isError": false
|
|
152
|
-
}
|
|
153
|
-
We unwrap that so callers just receive either a dict or a plain string.
|
|
154
|
-
"""
|
|
155
|
-
if not self.read_stream or not self.write_stream:
|
|
156
|
-
return {"isError": True, "error": "Transport not initialized"}
|
|
374
|
+
def is_connected(self) -> bool:
|
|
375
|
+
"""Check if transport is connected and ready."""
|
|
376
|
+
return self.read_stream is not None and self.write_stream is not None
|
|
157
377
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
378
|
+
async def __aenter__(self):
|
|
379
|
+
"""Async context manager entry."""
|
|
380
|
+
success = await self.initialize()
|
|
381
|
+
if not success:
|
|
382
|
+
raise RuntimeError("Failed to initialize STDIO transport")
|
|
383
|
+
return self
|
|
162
384
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
"isError": True,
|
|
167
|
-
"error": raw["error"].get("message", "Unknown error"),
|
|
168
|
-
}
|
|
385
|
+
async def __aexit__(self, exc_type, exc_val, exc_tb):
|
|
386
|
+
"""Async context manager exit."""
|
|
387
|
+
await self.close()
|
|
169
388
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
if "content" in raw:
|
|
176
|
-
clist = raw["content"]
|
|
177
|
-
if isinstance(clist, list) and clist:
|
|
178
|
-
first = clist[0]
|
|
179
|
-
if isinstance(first, dict) and first.get("type") == "text":
|
|
180
|
-
text = first.get("text", "")
|
|
181
|
-
# Try to parse as JSON; fall back to plain string
|
|
182
|
-
try:
|
|
183
|
-
parsed = json.loads(text)
|
|
184
|
-
return {"isError": False, "content": parsed}
|
|
185
|
-
except json.JSONDecodeError:
|
|
186
|
-
return {"isError": False, "content": text}
|
|
187
|
-
|
|
188
|
-
# Fallback: give caller whatever the server sent
|
|
189
|
-
return {"isError": False, "content": raw}
|
|
190
|
-
|
|
191
|
-
except Exception as e: # pragma: no cover
|
|
192
|
-
import logging
|
|
193
|
-
|
|
194
|
-
logging.error(f"Error calling tool {tool_name}: {e}")
|
|
195
|
-
return {"isError": True, "error": str(e)}
|
|
389
|
+
def __repr__(self) -> str:
|
|
390
|
+
"""String representation for debugging."""
|
|
391
|
+
status = "connected" if self.is_connected() else "disconnected"
|
|
392
|
+
cmd_info = f"command={getattr(self.server_params, 'command', 'unknown')}"
|
|
393
|
+
return f"StdioTransport(status={status}, {cmd_info})"
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: chuk-tool-processor
|
|
3
|
-
Version: 0.5
|
|
3
|
+
Version: 0.5.2
|
|
4
4
|
Summary: Add your description here
|
|
5
5
|
Requires-Python: >=3.11
|
|
6
6
|
Description-Content-Type: text/markdown
|
|
7
|
-
Requires-Dist: chuk-mcp>=0.2
|
|
7
|
+
Requires-Dist: chuk-mcp>=0.2.3
|
|
8
8
|
Requires-Dist: dotenv>=0.9.9
|
|
9
9
|
Requires-Dist: pydantic>=2.11.3
|
|
10
10
|
Requires-Dist: uuid>=1.30
|
|
@@ -25,7 +25,7 @@ chuk_tool_processor/mcp/stream_manager.py,sha256=FRTvvSBzBxU6-kPU1mZOjGCaqi8hHk5
|
|
|
25
25
|
chuk_tool_processor/mcp/transport/__init__.py,sha256=7QQqeSKVKv0N9GcyJuYF0R4FDZeooii5RjggvFFg5GY,296
|
|
26
26
|
chuk_tool_processor/mcp/transport/base_transport.py,sha256=bqId34OMQMxzMXtrKq_86sot0_x0NS_ecaIllsCyy6I,3423
|
|
27
27
|
chuk_tool_processor/mcp/transport/sse_transport.py,sha256=nzzMgCgfUV_-Owga2rqJFEc5WLdgXZ922V9maLMwRBI,19408
|
|
28
|
-
chuk_tool_processor/mcp/transport/stdio_transport.py,sha256=
|
|
28
|
+
chuk_tool_processor/mcp/transport/stdio_transport.py,sha256=YIXVd2Lwjl0wT1Jdi3MYzeaBmIE_ae-WgsAQQKMDCI8,15209
|
|
29
29
|
chuk_tool_processor/models/__init__.py,sha256=TC__rdVa0lQsmJHM_hbLDPRgToa_pQT_UxRcPZk6iVw,40
|
|
30
30
|
chuk_tool_processor/models/execution_strategy.py,sha256=UVW35YIeMY2B3mpIKZD2rAkyOPayI6ckOOUALyf0YiQ,2115
|
|
31
31
|
chuk_tool_processor/models/streaming_tool.py,sha256=0v2PSPTgZ5TS_PpVdohvVhh99fPwPQM_R_z4RU0mlLM,3541
|
|
@@ -52,7 +52,7 @@ chuk_tool_processor/registry/providers/__init__.py,sha256=eigwG_So11j7WbDGSWaKd3
|
|
|
52
52
|
chuk_tool_processor/registry/providers/memory.py,sha256=6cMtUwLO6zrk3pguQRgxJ2CReHAzewgZsizWZhsoStk,5184
|
|
53
53
|
chuk_tool_processor/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
54
54
|
chuk_tool_processor/utils/validation.py,sha256=V5N1dH9sJlHepFIbiI2k2MU82o7nvnh0hKyIt2jdgww,4136
|
|
55
|
-
chuk_tool_processor-0.5.dist-info/METADATA,sha256=
|
|
56
|
-
chuk_tool_processor-0.5.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
57
|
-
chuk_tool_processor-0.5.dist-info/top_level.txt,sha256=7lTsnuRx4cOW4U2sNJWNxl4ZTt_J1ndkjTbj3pHPY5M,20
|
|
58
|
-
chuk_tool_processor-0.5.dist-info/RECORD,,
|
|
55
|
+
chuk_tool_processor-0.5.2.dist-info/METADATA,sha256=fy84gk4wov0A1cSWhXpb3AKsmxr8A4uOOn_XxHvLKIo,24283
|
|
56
|
+
chuk_tool_processor-0.5.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
57
|
+
chuk_tool_processor-0.5.2.dist-info/top_level.txt,sha256=7lTsnuRx4cOW4U2sNJWNxl4ZTt_J1ndkjTbj3pHPY5M,20
|
|
58
|
+
chuk_tool_processor-0.5.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|