kailash 0.6.2__py3-none-any.whl → 0.6.4__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.
Files changed (131) hide show
  1. kailash/__init__.py +3 -3
  2. kailash/api/custom_nodes_secure.py +3 -3
  3. kailash/api/gateway.py +1 -1
  4. kailash/api/studio.py +2 -3
  5. kailash/api/workflow_api.py +3 -4
  6. kailash/core/resilience/bulkhead.py +460 -0
  7. kailash/core/resilience/circuit_breaker.py +92 -10
  8. kailash/edge/discovery.py +86 -0
  9. kailash/mcp_server/__init__.py +334 -0
  10. kailash/mcp_server/advanced_features.py +1022 -0
  11. kailash/{mcp → mcp_server}/ai_registry_server.py +29 -4
  12. kailash/mcp_server/auth.py +789 -0
  13. kailash/mcp_server/client.py +712 -0
  14. kailash/mcp_server/discovery.py +1593 -0
  15. kailash/mcp_server/errors.py +673 -0
  16. kailash/mcp_server/oauth.py +1727 -0
  17. kailash/mcp_server/protocol.py +1126 -0
  18. kailash/mcp_server/registry_integration.py +587 -0
  19. kailash/mcp_server/server.py +1747 -0
  20. kailash/{mcp → mcp_server}/servers/ai_registry.py +2 -2
  21. kailash/mcp_server/transports.py +1169 -0
  22. kailash/mcp_server/utils/cache.py +510 -0
  23. kailash/middleware/auth/auth_manager.py +3 -3
  24. kailash/middleware/communication/api_gateway.py +2 -9
  25. kailash/middleware/communication/realtime.py +1 -1
  26. kailash/middleware/mcp/client_integration.py +1 -1
  27. kailash/middleware/mcp/enhanced_server.py +2 -2
  28. kailash/nodes/__init__.py +2 -0
  29. kailash/nodes/admin/audit_log.py +6 -6
  30. kailash/nodes/admin/permission_check.py +8 -8
  31. kailash/nodes/admin/role_management.py +32 -28
  32. kailash/nodes/admin/schema.sql +6 -1
  33. kailash/nodes/admin/schema_manager.py +13 -13
  34. kailash/nodes/admin/security_event.py +16 -20
  35. kailash/nodes/admin/tenant_isolation.py +3 -3
  36. kailash/nodes/admin/transaction_utils.py +3 -3
  37. kailash/nodes/admin/user_management.py +21 -22
  38. kailash/nodes/ai/a2a.py +11 -11
  39. kailash/nodes/ai/ai_providers.py +9 -12
  40. kailash/nodes/ai/embedding_generator.py +13 -14
  41. kailash/nodes/ai/intelligent_agent_orchestrator.py +19 -19
  42. kailash/nodes/ai/iterative_llm_agent.py +3 -3
  43. kailash/nodes/ai/llm_agent.py +213 -36
  44. kailash/nodes/ai/self_organizing.py +2 -2
  45. kailash/nodes/alerts/discord.py +4 -4
  46. kailash/nodes/api/graphql.py +6 -6
  47. kailash/nodes/api/http.py +12 -17
  48. kailash/nodes/api/rate_limiting.py +4 -4
  49. kailash/nodes/api/rest.py +15 -15
  50. kailash/nodes/auth/mfa.py +3 -4
  51. kailash/nodes/auth/risk_assessment.py +2 -2
  52. kailash/nodes/auth/session_management.py +5 -5
  53. kailash/nodes/auth/sso.py +143 -0
  54. kailash/nodes/base.py +6 -2
  55. kailash/nodes/base_async.py +16 -2
  56. kailash/nodes/base_with_acl.py +2 -2
  57. kailash/nodes/cache/__init__.py +9 -0
  58. kailash/nodes/cache/cache.py +1172 -0
  59. kailash/nodes/cache/cache_invalidation.py +870 -0
  60. kailash/nodes/cache/redis_pool_manager.py +595 -0
  61. kailash/nodes/code/async_python.py +2 -1
  62. kailash/nodes/code/python.py +196 -35
  63. kailash/nodes/compliance/data_retention.py +6 -6
  64. kailash/nodes/compliance/gdpr.py +5 -5
  65. kailash/nodes/data/__init__.py +10 -0
  66. kailash/nodes/data/optimistic_locking.py +906 -0
  67. kailash/nodes/data/readers.py +8 -8
  68. kailash/nodes/data/redis.py +349 -0
  69. kailash/nodes/data/sql.py +314 -3
  70. kailash/nodes/data/streaming.py +21 -0
  71. kailash/nodes/enterprise/__init__.py +8 -0
  72. kailash/nodes/enterprise/audit_logger.py +285 -0
  73. kailash/nodes/enterprise/batch_processor.py +22 -3
  74. kailash/nodes/enterprise/data_lineage.py +1 -1
  75. kailash/nodes/enterprise/mcp_executor.py +205 -0
  76. kailash/nodes/enterprise/service_discovery.py +150 -0
  77. kailash/nodes/enterprise/tenant_assignment.py +108 -0
  78. kailash/nodes/logic/async_operations.py +2 -2
  79. kailash/nodes/logic/convergence.py +1 -1
  80. kailash/nodes/logic/operations.py +1 -1
  81. kailash/nodes/monitoring/__init__.py +11 -1
  82. kailash/nodes/monitoring/health_check.py +456 -0
  83. kailash/nodes/monitoring/log_processor.py +817 -0
  84. kailash/nodes/monitoring/metrics_collector.py +627 -0
  85. kailash/nodes/monitoring/performance_benchmark.py +137 -11
  86. kailash/nodes/rag/advanced.py +7 -7
  87. kailash/nodes/rag/agentic.py +49 -2
  88. kailash/nodes/rag/conversational.py +3 -3
  89. kailash/nodes/rag/evaluation.py +3 -3
  90. kailash/nodes/rag/federated.py +3 -3
  91. kailash/nodes/rag/graph.py +3 -3
  92. kailash/nodes/rag/multimodal.py +3 -3
  93. kailash/nodes/rag/optimized.py +5 -5
  94. kailash/nodes/rag/privacy.py +3 -3
  95. kailash/nodes/rag/query_processing.py +6 -6
  96. kailash/nodes/rag/realtime.py +1 -1
  97. kailash/nodes/rag/registry.py +2 -6
  98. kailash/nodes/rag/router.py +1 -1
  99. kailash/nodes/rag/similarity.py +7 -7
  100. kailash/nodes/rag/strategies.py +4 -4
  101. kailash/nodes/security/abac_evaluator.py +6 -6
  102. kailash/nodes/security/behavior_analysis.py +5 -6
  103. kailash/nodes/security/credential_manager.py +1 -1
  104. kailash/nodes/security/rotating_credentials.py +11 -11
  105. kailash/nodes/security/threat_detection.py +8 -8
  106. kailash/nodes/testing/credential_testing.py +2 -2
  107. kailash/nodes/transform/processors.py +5 -5
  108. kailash/runtime/local.py +162 -14
  109. kailash/runtime/parameter_injection.py +425 -0
  110. kailash/runtime/parameter_injector.py +657 -0
  111. kailash/runtime/testing.py +2 -2
  112. kailash/testing/fixtures.py +2 -2
  113. kailash/workflow/builder.py +99 -18
  114. kailash/workflow/builder_improvements.py +207 -0
  115. kailash/workflow/input_handling.py +170 -0
  116. {kailash-0.6.2.dist-info → kailash-0.6.4.dist-info}/METADATA +21 -8
  117. {kailash-0.6.2.dist-info → kailash-0.6.4.dist-info}/RECORD +126 -101
  118. kailash/mcp/__init__.py +0 -53
  119. kailash/mcp/client.py +0 -445
  120. kailash/mcp/server.py +0 -292
  121. kailash/mcp/server_enhanced.py +0 -449
  122. kailash/mcp/utils/cache.py +0 -267
  123. /kailash/{mcp → mcp_server}/client_new.py +0 -0
  124. /kailash/{mcp → mcp_server}/utils/__init__.py +0 -0
  125. /kailash/{mcp → mcp_server}/utils/config.py +0 -0
  126. /kailash/{mcp → mcp_server}/utils/formatters.py +0 -0
  127. /kailash/{mcp → mcp_server}/utils/metrics.py +0 -0
  128. {kailash-0.6.2.dist-info → kailash-0.6.4.dist-info}/WHEEL +0 -0
  129. {kailash-0.6.2.dist-info → kailash-0.6.4.dist-info}/entry_points.txt +0 -0
  130. {kailash-0.6.2.dist-info → kailash-0.6.4.dist-info}/licenses/LICENSE +0 -0
  131. {kailash-0.6.2.dist-info → kailash-0.6.4.dist-info}/top_level.txt +0 -0
kailash/mcp/client.py DELETED
@@ -1,445 +0,0 @@
1
- """MCP Client Service using official Anthropic SDK.
2
-
3
- This module provides a comprehensive interface to the Model Context Protocol
4
- using the official Anthropic MCP Python SDK. It enables seamless integration
5
- with MCP servers for tool discovery, resource access, and dynamic capability
6
- extension in workflow nodes.
7
-
8
- Note:
9
- This module requires the official Anthropic MCP SDK to be installed.
10
- Install with: pip install mcp
11
-
12
- Examples:
13
- Basic tool discovery and execution:
14
-
15
- >>> client = MCPClient()
16
- >>> # Discover available tools
17
- >>> tools = await client.discover_tools({
18
- ... "transport": "stdio",
19
- ... "command": "python",
20
- ... "args": ["-m", "my_mcp_server"]
21
- ... })
22
- >>> # Execute a tool
23
- >>> result = await client.call_tool(
24
- ... server_config,
25
- ... "search_knowledge",
26
- ... {"query": "workflow optimization"}
27
- ... )
28
-
29
- Resource access:
30
-
31
- >>> # List available resources
32
- >>> resources = await client.list_resources(server_config)
33
- >>> # Read specific resource
34
- >>> content = await client.read_resource(
35
- ... server_config,
36
- ... "file:///docs/api.md"
37
- ... )
38
- """
39
-
40
- import json
41
- import logging
42
- import os
43
- from contextlib import AsyncExitStack
44
- from typing import Any
45
-
46
- logger = logging.getLogger(__name__)
47
-
48
-
49
- class MCPClient:
50
- """MCP client service using official Anthropic SDK.
51
-
52
- This is a service class that provides MCP functionality to nodes.
53
- It handles connection management, tool discovery, and tool execution
54
- using the official MCP Python SDK.
55
-
56
- Examples:
57
- Used internally by LLMAgentNode:
58
-
59
- >>> client = MCPClient()
60
- >>> tools = await client.discover_tools("http://localhost:8080")
61
- >>> result = await client.call_tool(
62
- ... "http://localhost:8080",
63
- ... "search",
64
- ... {"query": "AI applications"}
65
- ... )
66
- """
67
-
68
- def __init__(self):
69
- """Initialize the MCP client."""
70
- self._sessions = {} # Cache active sessions
71
- self._discovered_tools = {} # Cache discovered tools
72
- self._discovered_resources = {} # Cache discovered resources
73
-
74
- async def discover_tools(
75
- self, server_config: str | dict[str, Any]
76
- ) -> list[dict[str, Any]]:
77
- """Discover available tools from an MCP server.
78
-
79
- Args:
80
- server_config: Either a URL string or server configuration dict.
81
- For stdio servers, use dict with 'transport', 'command', 'args'.
82
-
83
- Returns:
84
- List of tool definitions with name, description, and parameters.
85
- Returns empty list if server unavailable or on error.
86
-
87
- Examples:
88
- >>> config = {
89
- ... "transport": "stdio",
90
- ... "command": "python",
91
- ... "args": ["-m", "my_server"]
92
- ... }
93
- >>> tools = await client.discover_tools(config)
94
- >>> print([tool["name"] for tool in tools])
95
- """
96
- server_key = self._get_server_key(server_config)
97
-
98
- # Return cached tools if available
99
- if server_key in self._discovered_tools:
100
- return self._discovered_tools[server_key]
101
-
102
- try:
103
- # Import MCP SDK
104
- from mcp import ClientSession, StdioServerParameters
105
- from mcp.client.stdio import stdio_client
106
-
107
- # Parse server configuration
108
- if isinstance(server_config, str):
109
- # URL-based server (not implemented in this example)
110
- logger.warning(
111
- f"URL-based MCP servers not yet supported: {server_config}"
112
- )
113
- return []
114
-
115
- # Extract stdio configuration
116
- transport = server_config.get("transport", "stdio")
117
- if transport != "stdio":
118
- logger.warning(
119
- f"Only stdio transport currently supported, got: {transport}"
120
- )
121
- return []
122
-
123
- command = server_config.get("command", "python")
124
- args = server_config.get("args", [])
125
- env = server_config.get("env", {})
126
-
127
- # Merge environment
128
- server_env = os.environ.copy()
129
- server_env.update(env)
130
-
131
- # Create server parameters
132
- server_params = StdioServerParameters(
133
- command=command, args=args, env=server_env
134
- )
135
-
136
- # Connect and discover tools
137
- async with AsyncExitStack() as stack:
138
- stdio = await stack.enter_async_context(stdio_client(server_params))
139
- session = await stack.enter_async_context(
140
- ClientSession(stdio[0], stdio[1])
141
- )
142
-
143
- # Initialize session
144
- await session.initialize()
145
-
146
- # List tools
147
- result = await session.list_tools()
148
-
149
- tools = []
150
- for tool in result.tools:
151
- tools.append(
152
- {
153
- "name": tool.name,
154
- "description": tool.description,
155
- "parameters": tool.inputSchema,
156
- }
157
- )
158
-
159
- # Cache the tools
160
- self._discovered_tools[server_key] = tools
161
- return tools
162
-
163
- except ImportError:
164
- logger.error("MCP SDK not available. Install with: pip install mcp")
165
- return []
166
- except Exception as e:
167
- logger.error(f"Failed to discover tools: {e}")
168
- return []
169
-
170
- async def call_tool(
171
- self,
172
- server_config: str | dict[str, Any],
173
- tool_name: str,
174
- arguments: dict[str, Any],
175
- ) -> Any:
176
- """Call a tool on an MCP server.
177
-
178
- Args:
179
- server_config: Either a URL string or server configuration dict.
180
- tool_name: Name of the tool to call.
181
- arguments: Arguments to pass to the tool.
182
-
183
- Returns:
184
- Dict containing tool execution result. On success, includes
185
- 'success': True and 'content' or 'result'. On error, includes
186
- 'error' with description.
187
-
188
- Examples:
189
- >>> result = await client.call_tool(
190
- ... server_config,
191
- ... "search",
192
- ... {"query": "python examples"}
193
- ... )
194
- >>> if result.get("success"):
195
- ... print(result["content"])
196
- """
197
- try:
198
- # Import MCP SDK
199
- from mcp import ClientSession, StdioServerParameters
200
- from mcp.client.stdio import stdio_client
201
-
202
- # Parse server configuration
203
- if isinstance(server_config, str):
204
- logger.warning(
205
- f"URL-based MCP servers not yet supported: {server_config}"
206
- )
207
- return {"error": "URL-based servers not supported"}
208
-
209
- # Extract stdio configuration
210
- transport = server_config.get("transport", "stdio")
211
- if transport != "stdio":
212
- logger.warning(
213
- f"Only stdio transport currently supported, got: {transport}"
214
- )
215
- return {"error": f"Transport {transport} not supported"}
216
-
217
- command = server_config.get("command", "python")
218
- args = server_config.get("args", [])
219
- env = server_config.get("env", {})
220
-
221
- # Merge environment
222
- server_env = os.environ.copy()
223
- server_env.update(env)
224
-
225
- # Create server parameters
226
- server_params = StdioServerParameters(
227
- command=command, args=args, env=server_env
228
- )
229
-
230
- # Connect and call tool
231
- async with AsyncExitStack() as stack:
232
- stdio = await stack.enter_async_context(stdio_client(server_params))
233
- session = await stack.enter_async_context(
234
- ClientSession(stdio[0], stdio[1])
235
- )
236
-
237
- # Initialize session
238
- await session.initialize()
239
-
240
- # Call tool
241
- result = await session.call_tool(name=tool_name, arguments=arguments)
242
-
243
- # Extract content from result
244
- if hasattr(result, "content"):
245
- content = []
246
- for item in result.content:
247
- if hasattr(item, "text"):
248
- content.append(item.text)
249
- else:
250
- content.append(str(item))
251
- return {"success": True, "content": content}
252
- else:
253
- return {"success": True, "result": str(result)}
254
-
255
- except ImportError:
256
- logger.error("MCP SDK not available. Install with: pip install mcp")
257
- return {"error": "MCP SDK not available"}
258
- except Exception as e:
259
- logger.error(f"Failed to call tool: {e}")
260
- return {"error": str(e)}
261
-
262
- async def list_resources(
263
- self, server_config: str | dict[str, Any]
264
- ) -> list[dict[str, Any]]:
265
- """List available resources from an MCP server.
266
-
267
- Args:
268
- server_config: Either a URL string or server configuration dict.
269
-
270
- Returns:
271
- List of resource definitions with uri, name, description, mimeType.
272
- Returns empty list if server unavailable or on error.
273
-
274
- Examples:
275
- >>> resources = await client.list_resources(server_config)
276
- >>> for resource in resources:
277
- ... print(f"Resource: {resource['name']} ({resource['uri']})")
278
- """
279
- server_key = self._get_server_key(server_config)
280
-
281
- # Return cached resources if available
282
- if server_key in self._discovered_resources:
283
- return self._discovered_resources[server_key]
284
-
285
- try:
286
- # Import MCP SDK
287
- from mcp import ClientSession, StdioServerParameters
288
- from mcp.client.stdio import stdio_client
289
-
290
- # Parse server configuration (similar to discover_tools)
291
- if isinstance(server_config, str):
292
- logger.warning(
293
- f"URL-based MCP servers not yet supported: {server_config}"
294
- )
295
- return []
296
-
297
- # Extract stdio configuration
298
- transport = server_config.get("transport", "stdio")
299
- if transport != "stdio":
300
- logger.warning(
301
- f"Only stdio transport currently supported, got: {transport}"
302
- )
303
- return []
304
-
305
- command = server_config.get("command", "python")
306
- args = server_config.get("args", [])
307
- env = server_config.get("env", {})
308
-
309
- # Merge environment
310
- server_env = os.environ.copy()
311
- server_env.update(env)
312
-
313
- # Create server parameters
314
- server_params = StdioServerParameters(
315
- command=command, args=args, env=server_env
316
- )
317
-
318
- # Connect and list resources
319
- async with AsyncExitStack() as stack:
320
- stdio = await stack.enter_async_context(stdio_client(server_params))
321
- session = await stack.enter_async_context(
322
- ClientSession(stdio[0], stdio[1])
323
- )
324
-
325
- # Initialize session
326
- await session.initialize()
327
-
328
- # List resources
329
- result = await session.list_resources()
330
-
331
- resources = []
332
- for resource in result.resources:
333
- resources.append(
334
- {
335
- "uri": resource.uri,
336
- "name": resource.name,
337
- "description": resource.description,
338
- "mimeType": resource.mimeType,
339
- }
340
- )
341
-
342
- # Cache the resources
343
- self._discovered_resources[server_key] = resources
344
- return resources
345
-
346
- except ImportError:
347
- logger.error("MCP SDK not available. Install with: pip install mcp")
348
- return []
349
- except Exception as e:
350
- logger.error(f"Failed to list resources: {e}")
351
- return []
352
-
353
- async def read_resource(self, server_config: str | dict[str, Any], uri: str) -> Any:
354
- """Read a resource from an MCP server.
355
-
356
- Args:
357
- server_config: Either a URL string or server configuration dict.
358
- uri: URI of the resource to read.
359
-
360
- Returns:
361
- Dict containing resource content. On success, includes 'success': True,
362
- 'content', and 'uri'. On error, includes 'error' with description.
363
-
364
- Examples:
365
- >>> content = await client.read_resource(
366
- ... server_config,
367
- ... "file:///docs/readme.md"
368
- ... )
369
- >>> if content.get("success"):
370
- ... print(content["content"])
371
- """
372
- try:
373
- # Import MCP SDK
374
- from mcp import ClientSession, StdioServerParameters
375
- from mcp.client.stdio import stdio_client
376
-
377
- # Parse server configuration (similar to call_tool)
378
- if isinstance(server_config, str):
379
- logger.warning(
380
- f"URL-based MCP servers not yet supported: {server_config}"
381
- )
382
- return {"error": "URL-based servers not supported"}
383
-
384
- # Extract stdio configuration
385
- transport = server_config.get("transport", "stdio")
386
- if transport != "stdio":
387
- logger.warning(
388
- f"Only stdio transport currently supported, got: {transport}"
389
- )
390
- return {"error": f"Transport {transport} not supported"}
391
-
392
- command = server_config.get("command", "python")
393
- args = server_config.get("args", [])
394
- env = server_config.get("env", {})
395
-
396
- # Merge environment
397
- server_env = os.environ.copy()
398
- server_env.update(env)
399
-
400
- # Create server parameters
401
- server_params = StdioServerParameters(
402
- command=command, args=args, env=server_env
403
- )
404
-
405
- # Connect and read resource
406
- async with AsyncExitStack() as stack:
407
- stdio = await stack.enter_async_context(stdio_client(server_params))
408
- session = await stack.enter_async_context(
409
- ClientSession(stdio[0], stdio[1])
410
- )
411
-
412
- # Initialize session
413
- await session.initialize()
414
-
415
- # Read resource
416
- result = await session.read_resource(uri=uri)
417
-
418
- # Extract content
419
- if hasattr(result, "contents"):
420
- content = []
421
- for item in result.contents:
422
- if hasattr(item, "text"):
423
- content.append(item.text)
424
- elif hasattr(item, "blob"):
425
- content.append({"blob": item.blob})
426
- else:
427
- content.append(str(item))
428
- return {"success": True, "content": content, "uri": uri}
429
- else:
430
- return {"success": True, "result": str(result), "uri": uri}
431
-
432
- except ImportError:
433
- logger.error("MCP SDK not available. Install with: pip install mcp")
434
- return {"error": "MCP SDK not available"}
435
- except Exception as e:
436
- logger.error(f"Failed to read resource: {e}")
437
- return {"error": str(e)}
438
-
439
- def _get_server_key(self, server_config: str | dict[str, Any]) -> str:
440
- """Generate a unique key for caching server data."""
441
- if isinstance(server_config, str):
442
- return server_config
443
- else:
444
- # Create a key from server config
445
- return json.dumps(server_config, sort_keys=True)