kailash 0.3.1__py3-none-any.whl → 0.4.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.
- kailash/__init__.py +33 -1
- kailash/access_control/__init__.py +129 -0
- kailash/access_control/managers.py +461 -0
- kailash/access_control/rule_evaluators.py +467 -0
- kailash/access_control_abac.py +825 -0
- kailash/config/__init__.py +27 -0
- kailash/config/database_config.py +359 -0
- kailash/database/__init__.py +28 -0
- kailash/database/execution_pipeline.py +499 -0
- kailash/middleware/__init__.py +306 -0
- kailash/middleware/auth/__init__.py +33 -0
- kailash/middleware/auth/access_control.py +436 -0
- kailash/middleware/auth/auth_manager.py +422 -0
- kailash/middleware/auth/jwt_auth.py +477 -0
- kailash/middleware/auth/kailash_jwt_auth.py +616 -0
- kailash/middleware/communication/__init__.py +37 -0
- kailash/middleware/communication/ai_chat.py +989 -0
- kailash/middleware/communication/api_gateway.py +802 -0
- kailash/middleware/communication/events.py +470 -0
- kailash/middleware/communication/realtime.py +710 -0
- kailash/middleware/core/__init__.py +21 -0
- kailash/middleware/core/agent_ui.py +890 -0
- kailash/middleware/core/schema.py +643 -0
- kailash/middleware/core/workflows.py +396 -0
- kailash/middleware/database/__init__.py +63 -0
- kailash/middleware/database/base.py +113 -0
- kailash/middleware/database/base_models.py +525 -0
- kailash/middleware/database/enums.py +106 -0
- kailash/middleware/database/migrations.py +12 -0
- kailash/{api/database.py → middleware/database/models.py} +183 -291
- kailash/middleware/database/repositories.py +685 -0
- kailash/middleware/database/session_manager.py +19 -0
- kailash/middleware/mcp/__init__.py +38 -0
- kailash/middleware/mcp/client_integration.py +585 -0
- kailash/middleware/mcp/enhanced_server.py +576 -0
- kailash/nodes/__init__.py +25 -3
- kailash/nodes/admin/__init__.py +35 -0
- kailash/nodes/admin/audit_log.py +794 -0
- kailash/nodes/admin/permission_check.py +864 -0
- kailash/nodes/admin/role_management.py +823 -0
- kailash/nodes/admin/security_event.py +1519 -0
- kailash/nodes/admin/user_management.py +944 -0
- kailash/nodes/ai/a2a.py +24 -7
- kailash/nodes/ai/ai_providers.py +1 -0
- kailash/nodes/ai/embedding_generator.py +11 -11
- kailash/nodes/ai/intelligent_agent_orchestrator.py +99 -11
- kailash/nodes/ai/llm_agent.py +407 -2
- kailash/nodes/ai/self_organizing.py +85 -10
- kailash/nodes/api/auth.py +287 -6
- kailash/nodes/api/rest.py +151 -0
- kailash/nodes/auth/__init__.py +17 -0
- kailash/nodes/auth/directory_integration.py +1228 -0
- kailash/nodes/auth/enterprise_auth_provider.py +1328 -0
- kailash/nodes/auth/mfa.py +2338 -0
- kailash/nodes/auth/risk_assessment.py +872 -0
- kailash/nodes/auth/session_management.py +1093 -0
- kailash/nodes/auth/sso.py +1040 -0
- kailash/nodes/base.py +344 -13
- kailash/nodes/base_cycle_aware.py +4 -2
- kailash/nodes/base_with_acl.py +1 -1
- kailash/nodes/code/python.py +293 -12
- kailash/nodes/compliance/__init__.py +9 -0
- kailash/nodes/compliance/data_retention.py +1888 -0
- kailash/nodes/compliance/gdpr.py +2004 -0
- kailash/nodes/data/__init__.py +22 -2
- kailash/nodes/data/async_connection.py +469 -0
- kailash/nodes/data/async_sql.py +757 -0
- kailash/nodes/data/async_vector.py +598 -0
- kailash/nodes/data/readers.py +767 -0
- kailash/nodes/data/retrieval.py +360 -1
- kailash/nodes/data/sharepoint_graph.py +397 -21
- kailash/nodes/data/sql.py +94 -5
- kailash/nodes/data/streaming.py +68 -8
- kailash/nodes/data/vector_db.py +54 -4
- kailash/nodes/enterprise/__init__.py +13 -0
- kailash/nodes/enterprise/batch_processor.py +741 -0
- kailash/nodes/enterprise/data_lineage.py +497 -0
- kailash/nodes/logic/convergence.py +31 -9
- kailash/nodes/logic/operations.py +14 -3
- kailash/nodes/mixins/__init__.py +8 -0
- kailash/nodes/mixins/event_emitter.py +201 -0
- kailash/nodes/mixins/mcp.py +9 -4
- kailash/nodes/mixins/security.py +165 -0
- kailash/nodes/monitoring/__init__.py +7 -0
- kailash/nodes/monitoring/performance_benchmark.py +2497 -0
- kailash/nodes/rag/__init__.py +284 -0
- kailash/nodes/rag/advanced.py +1615 -0
- kailash/nodes/rag/agentic.py +773 -0
- kailash/nodes/rag/conversational.py +999 -0
- kailash/nodes/rag/evaluation.py +875 -0
- kailash/nodes/rag/federated.py +1188 -0
- kailash/nodes/rag/graph.py +721 -0
- kailash/nodes/rag/multimodal.py +671 -0
- kailash/nodes/rag/optimized.py +933 -0
- kailash/nodes/rag/privacy.py +1059 -0
- kailash/nodes/rag/query_processing.py +1335 -0
- kailash/nodes/rag/realtime.py +764 -0
- kailash/nodes/rag/registry.py +547 -0
- kailash/nodes/rag/router.py +837 -0
- kailash/nodes/rag/similarity.py +1854 -0
- kailash/nodes/rag/strategies.py +566 -0
- kailash/nodes/rag/workflows.py +575 -0
- kailash/nodes/security/__init__.py +19 -0
- kailash/nodes/security/abac_evaluator.py +1411 -0
- kailash/nodes/security/audit_log.py +91 -0
- kailash/nodes/security/behavior_analysis.py +1893 -0
- kailash/nodes/security/credential_manager.py +401 -0
- kailash/nodes/security/rotating_credentials.py +760 -0
- kailash/nodes/security/security_event.py +132 -0
- kailash/nodes/security/threat_detection.py +1103 -0
- kailash/nodes/testing/__init__.py +9 -0
- kailash/nodes/testing/credential_testing.py +499 -0
- kailash/nodes/transform/__init__.py +10 -2
- kailash/nodes/transform/chunkers.py +592 -1
- kailash/nodes/transform/processors.py +484 -14
- kailash/nodes/validation.py +321 -0
- kailash/runtime/access_controlled.py +1 -1
- kailash/runtime/async_local.py +41 -7
- kailash/runtime/docker.py +1 -1
- kailash/runtime/local.py +474 -55
- kailash/runtime/parallel.py +1 -1
- kailash/runtime/parallel_cyclic.py +1 -1
- kailash/runtime/testing.py +210 -2
- kailash/utils/migrations/__init__.py +25 -0
- kailash/utils/migrations/generator.py +433 -0
- kailash/utils/migrations/models.py +231 -0
- kailash/utils/migrations/runner.py +489 -0
- kailash/utils/secure_logging.py +342 -0
- kailash/workflow/__init__.py +16 -0
- kailash/workflow/cyclic_runner.py +3 -4
- kailash/workflow/graph.py +70 -2
- kailash/workflow/resilience.py +249 -0
- kailash/workflow/templates.py +726 -0
- {kailash-0.3.1.dist-info → kailash-0.4.0.dist-info}/METADATA +253 -20
- kailash-0.4.0.dist-info/RECORD +223 -0
- kailash/api/__init__.py +0 -17
- kailash/api/__main__.py +0 -6
- kailash/api/studio_secure.py +0 -893
- kailash/mcp/__main__.py +0 -13
- kailash/mcp/server_new.py +0 -336
- kailash/mcp/servers/__init__.py +0 -12
- kailash-0.3.1.dist-info/RECORD +0 -136
- {kailash-0.3.1.dist-info → kailash-0.4.0.dist-info}/WHEEL +0 -0
- {kailash-0.3.1.dist-info → kailash-0.4.0.dist-info}/entry_points.txt +0 -0
- {kailash-0.3.1.dist-info → kailash-0.4.0.dist-info}/licenses/LICENSE +0 -0
- {kailash-0.3.1.dist-info → kailash-0.4.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,576 @@
|
|
1
|
+
"""
|
2
|
+
Enhanced MCP Server for Kailash Middleware
|
3
|
+
|
4
|
+
Built entirely with Kailash SDK components - consolidates existing MCP
|
5
|
+
implementations with middleware-specific features for enterprise use.
|
6
|
+
"""
|
7
|
+
|
8
|
+
import asyncio
|
9
|
+
import json
|
10
|
+
import logging
|
11
|
+
import uuid
|
12
|
+
from datetime import datetime, timezone
|
13
|
+
from typing import Any, Callable, Dict, List, Optional
|
14
|
+
|
15
|
+
from kailash.nodes.ai import LLMAgentNode
|
16
|
+
|
17
|
+
# Import Kailash SDK components
|
18
|
+
from kailash.nodes.base import Node, NodeParameter
|
19
|
+
from kailash.nodes.code import PythonCodeNode
|
20
|
+
from kailash.nodes.data import JSONReaderNode
|
21
|
+
from kailash.nodes.logic import SwitchNode
|
22
|
+
from kailash.runtime.local import LocalRuntime
|
23
|
+
from kailash.workflow.builder import WorkflowBuilder
|
24
|
+
|
25
|
+
# Import existing Kailash MCP components
|
26
|
+
try:
|
27
|
+
from kailash.mcp import MCPServer, SimpleMCPServer
|
28
|
+
from kailash.mcp.utils import CacheManager, ConfigManager, MetricsCollector
|
29
|
+
|
30
|
+
_KAILASH_MCP_AVAILABLE = True
|
31
|
+
except ImportError:
|
32
|
+
_KAILASH_MCP_AVAILABLE = False
|
33
|
+
|
34
|
+
# Import middleware components
|
35
|
+
from ..communication.events import EventStream, EventType
|
36
|
+
from ..core.agent_ui import AgentUIMiddleware
|
37
|
+
|
38
|
+
logger = logging.getLogger(__name__)
|
39
|
+
|
40
|
+
|
41
|
+
class MCPServerConfig:
|
42
|
+
"""Configuration for Middleware MCP Server using Kailash patterns."""
|
43
|
+
|
44
|
+
def __init__(self):
|
45
|
+
self.name = "kailash-middleware-mcp"
|
46
|
+
self.version = "1.0.0"
|
47
|
+
self.description = "Enhanced MCP server built with Kailash SDK"
|
48
|
+
|
49
|
+
# Kailash-specific settings
|
50
|
+
self.enable_caching = True
|
51
|
+
self.cache_ttl = 300
|
52
|
+
self.enable_metrics = True
|
53
|
+
self.enable_events = True
|
54
|
+
|
55
|
+
# Server settings
|
56
|
+
self.max_tools = 100
|
57
|
+
self.max_resources = 50
|
58
|
+
self.enable_streaming = True
|
59
|
+
|
60
|
+
|
61
|
+
class MCPToolNode(Node):
|
62
|
+
"""Kailash node representing an MCP tool."""
|
63
|
+
|
64
|
+
def __init__(
|
65
|
+
self,
|
66
|
+
name: str,
|
67
|
+
tool_name: str,
|
68
|
+
description: str = "",
|
69
|
+
parameters_schema: Dict[str, Any] = None,
|
70
|
+
):
|
71
|
+
super().__init__(name)
|
72
|
+
self.tool_name = tool_name
|
73
|
+
self.description = description
|
74
|
+
self.parameters_schema = parameters_schema or {}
|
75
|
+
self.execution_count = 0
|
76
|
+
self.last_executed = None
|
77
|
+
|
78
|
+
def get_parameters(self) -> Dict[str, NodeParameter]:
|
79
|
+
"""Generate parameters from tool schema."""
|
80
|
+
params = {}
|
81
|
+
|
82
|
+
# Always include tool input parameter
|
83
|
+
params["tool_input"] = NodeParameter(
|
84
|
+
name="tool_input",
|
85
|
+
type=dict,
|
86
|
+
required=True,
|
87
|
+
description="Input data for the MCP tool",
|
88
|
+
)
|
89
|
+
|
90
|
+
# Add schema-specific parameters
|
91
|
+
for param_name, param_info in self.parameters_schema.items():
|
92
|
+
params[param_name] = NodeParameter(
|
93
|
+
name=param_name,
|
94
|
+
type=param_info.get("type", str),
|
95
|
+
required=param_info.get("required", False),
|
96
|
+
description=param_info.get("description", f"Parameter {param_name}"),
|
97
|
+
)
|
98
|
+
|
99
|
+
return params
|
100
|
+
|
101
|
+
def process(self, inputs: Dict[str, Any]) -> Dict[str, Any]:
|
102
|
+
"""Process MCP tool execution."""
|
103
|
+
self.execution_count += 1
|
104
|
+
self.last_executed = datetime.now(timezone.utc)
|
105
|
+
|
106
|
+
# This would be overridden by specific tool implementations
|
107
|
+
return {
|
108
|
+
"tool_result": f"Executed MCP tool {self.tool_name}",
|
109
|
+
"execution_count": self.execution_count,
|
110
|
+
"executed_at": self.last_executed.isoformat(),
|
111
|
+
}
|
112
|
+
|
113
|
+
|
114
|
+
class MCPResourceNode(Node):
|
115
|
+
"""Kailash node representing an MCP resource."""
|
116
|
+
|
117
|
+
def __init__(
|
118
|
+
self,
|
119
|
+
name: str,
|
120
|
+
resource_uri: str,
|
121
|
+
resource_type: str = "text",
|
122
|
+
description: str = "",
|
123
|
+
):
|
124
|
+
super().__init__(name)
|
125
|
+
self.resource_uri = resource_uri
|
126
|
+
self.resource_type = resource_type
|
127
|
+
self.description = description
|
128
|
+
self.access_count = 0
|
129
|
+
|
130
|
+
def get_parameters(self) -> Dict[str, NodeParameter]:
|
131
|
+
return {
|
132
|
+
"resource_uri": NodeParameter(
|
133
|
+
name="resource_uri",
|
134
|
+
type=str,
|
135
|
+
required=False,
|
136
|
+
default=self.resource_uri,
|
137
|
+
description="URI of the resource to access",
|
138
|
+
)
|
139
|
+
}
|
140
|
+
|
141
|
+
def process(self, inputs: Dict[str, Any]) -> Dict[str, Any]:
|
142
|
+
"""Process MCP resource access."""
|
143
|
+
self.access_count += 1
|
144
|
+
|
145
|
+
# This would be overridden by specific resource implementations
|
146
|
+
return {
|
147
|
+
"resource_content": f"Content from {self.resource_uri}",
|
148
|
+
"resource_type": self.resource_type,
|
149
|
+
"access_count": self.access_count,
|
150
|
+
}
|
151
|
+
|
152
|
+
|
153
|
+
class MiddlewareMCPServer:
|
154
|
+
"""
|
155
|
+
Enhanced MCP Server built with Kailash SDK components.
|
156
|
+
|
157
|
+
Integrates with the middleware layer for real-time events,
|
158
|
+
session management, and AI agent communication.
|
159
|
+
"""
|
160
|
+
|
161
|
+
def __init__(
|
162
|
+
self,
|
163
|
+
config: MCPServerConfig = None,
|
164
|
+
event_stream: EventStream = None,
|
165
|
+
agent_ui: AgentUIMiddleware = None,
|
166
|
+
):
|
167
|
+
self.config = config or MCPServerConfig()
|
168
|
+
self.event_stream = event_stream
|
169
|
+
self.agent_ui = agent_ui
|
170
|
+
|
171
|
+
# Kailash components
|
172
|
+
self.runtime = LocalRuntime()
|
173
|
+
self.workflows: Dict[str, WorkflowBuilder] = {}
|
174
|
+
|
175
|
+
# MCP registry using Kailash patterns
|
176
|
+
self.tools: Dict[str, MCPToolNode] = {}
|
177
|
+
self.resources: Dict[str, MCPResourceNode] = {}
|
178
|
+
self.prompts: Dict[str, Dict[str, Any]] = {}
|
179
|
+
|
180
|
+
# State management
|
181
|
+
self.server_id = str(uuid.uuid4())
|
182
|
+
self.started_at = None
|
183
|
+
self.client_connections: Dict[str, Dict[str, Any]] = {}
|
184
|
+
|
185
|
+
# Use existing Kailash MCP server if available
|
186
|
+
self.base_server = None
|
187
|
+
if _KAILASH_MCP_AVAILABLE:
|
188
|
+
try:
|
189
|
+
self.base_server = MCPServer(self.config.name)
|
190
|
+
except Exception as e:
|
191
|
+
logger.warning(f"Could not initialize base MCP server: {e}")
|
192
|
+
|
193
|
+
# Create MCP management workflows
|
194
|
+
self._create_management_workflows()
|
195
|
+
|
196
|
+
def _create_management_workflows(self):
|
197
|
+
"""Create Kailash workflows for MCP operations."""
|
198
|
+
|
199
|
+
# Tool Registration Workflow
|
200
|
+
self.tool_register_workflow = WorkflowBuilder()
|
201
|
+
|
202
|
+
validator = PythonCodeNode(
|
203
|
+
name="validate_tool",
|
204
|
+
code="""
|
205
|
+
# Validate tool registration using Kailash patterns
|
206
|
+
tool_data = input_data.get('tool_data', {})
|
207
|
+
|
208
|
+
required_fields = ['name', 'description']
|
209
|
+
missing_fields = [f for f in required_fields if not tool_data.get(f)]
|
210
|
+
|
211
|
+
if missing_fields:
|
212
|
+
result = {
|
213
|
+
'valid': False,
|
214
|
+
'error': f'Missing required fields: {missing_fields}',
|
215
|
+
'tool_data': tool_data
|
216
|
+
}
|
217
|
+
else:
|
218
|
+
result = {
|
219
|
+
'valid': True,
|
220
|
+
'tool_data': tool_data,
|
221
|
+
'validation_passed': True
|
222
|
+
}
|
223
|
+
""",
|
224
|
+
)
|
225
|
+
|
226
|
+
register_handler = PythonCodeNode(
|
227
|
+
name="register_tool",
|
228
|
+
code="""
|
229
|
+
# Register tool using Kailash patterns
|
230
|
+
validation_result = input_data.get('validation_result', {})
|
231
|
+
|
232
|
+
if not validation_result.get('valid'):
|
233
|
+
result = {
|
234
|
+
'success': False,
|
235
|
+
'error': validation_result.get('error', 'Validation failed'),
|
236
|
+
'tool_registered': False
|
237
|
+
}
|
238
|
+
else:
|
239
|
+
tool_data = validation_result.get('tool_data', {})
|
240
|
+
result = {
|
241
|
+
'success': True,
|
242
|
+
'tool_name': tool_data.get('name'),
|
243
|
+
'tool_registered': True,
|
244
|
+
'registration_time': datetime.now().isoformat()
|
245
|
+
}
|
246
|
+
""",
|
247
|
+
)
|
248
|
+
|
249
|
+
self.tool_register_workflow.add_node(validator)
|
250
|
+
self.tool_register_workflow.add_node(register_handler)
|
251
|
+
self.tool_register_workflow.connect(
|
252
|
+
validator, register_handler, mapping={"result": "validation_result"}
|
253
|
+
)
|
254
|
+
|
255
|
+
# Tool Execution Workflow
|
256
|
+
self.tool_execute_workflow = WorkflowBuilder()
|
257
|
+
|
258
|
+
executor = PythonCodeNode(
|
259
|
+
name="execute_tool",
|
260
|
+
code="""
|
261
|
+
# Execute MCP tool using Kailash patterns
|
262
|
+
tool_name = input_data.get('tool_name')
|
263
|
+
tool_args = input_data.get('arguments', {})
|
264
|
+
|
265
|
+
# Simulate tool execution
|
266
|
+
execution_result = {
|
267
|
+
'tool_name': tool_name,
|
268
|
+
'arguments': tool_args,
|
269
|
+
'result': f'Executed {tool_name} with args: {tool_args}',
|
270
|
+
'execution_time': datetime.now().isoformat(),
|
271
|
+
'success': True
|
272
|
+
}
|
273
|
+
|
274
|
+
result = {'execution_result': execution_result}
|
275
|
+
""",
|
276
|
+
)
|
277
|
+
|
278
|
+
self.tool_execute_workflow.add_node(executor)
|
279
|
+
|
280
|
+
async def register_tool(
|
281
|
+
self,
|
282
|
+
name: str,
|
283
|
+
description: str,
|
284
|
+
handler: Callable = None,
|
285
|
+
parameters_schema: Dict[str, Any] = None,
|
286
|
+
) -> Dict[str, Any]:
|
287
|
+
"""Register MCP tool using Kailash workflow."""
|
288
|
+
|
289
|
+
# Use Kailash workflow for tool registration
|
290
|
+
tool_data = {
|
291
|
+
"name": name,
|
292
|
+
"description": description,
|
293
|
+
"parameters_schema": parameters_schema or {},
|
294
|
+
}
|
295
|
+
|
296
|
+
workflow = self.tool_register_workflow.build()
|
297
|
+
results, _ = self.runtime.execute(workflow, parameters={"tool_data": tool_data})
|
298
|
+
|
299
|
+
registration_result = results.get("register_tool", {})
|
300
|
+
|
301
|
+
if registration_result.get("success"):
|
302
|
+
# Create Kailash tool node
|
303
|
+
tool_node = MCPToolNode(
|
304
|
+
name=f"mcp_tool_{name}",
|
305
|
+
tool_name=name,
|
306
|
+
description=description,
|
307
|
+
parameters_schema=parameters_schema,
|
308
|
+
)
|
309
|
+
|
310
|
+
# Override process method if handler provided
|
311
|
+
if handler:
|
312
|
+
original_process = tool_node.process
|
313
|
+
|
314
|
+
def custom_process(inputs):
|
315
|
+
try:
|
316
|
+
# Call the custom handler
|
317
|
+
result = handler(inputs.get("tool_input", {}))
|
318
|
+
return {"tool_result": result}
|
319
|
+
except Exception as e:
|
320
|
+
return {"tool_result": None, "error": str(e)}
|
321
|
+
|
322
|
+
tool_node.process = custom_process
|
323
|
+
|
324
|
+
self.tools[name] = tool_node
|
325
|
+
|
326
|
+
# Emit middleware event
|
327
|
+
if self.event_stream:
|
328
|
+
await self._emit_mcp_event(
|
329
|
+
"tool_registered", {"tool_name": name, "description": description}
|
330
|
+
)
|
331
|
+
|
332
|
+
logger.info(f"Registered MCP tool: {name}")
|
333
|
+
|
334
|
+
return registration_result
|
335
|
+
|
336
|
+
async def register_resource(
|
337
|
+
self,
|
338
|
+
uri: str,
|
339
|
+
resource_type: str = "text",
|
340
|
+
description: str = "",
|
341
|
+
handler: Callable = None,
|
342
|
+
) -> Dict[str, Any]:
|
343
|
+
"""Register MCP resource using Kailash patterns."""
|
344
|
+
|
345
|
+
resource_node = MCPResourceNode(
|
346
|
+
name=f"mcp_resource_{uri.replace('/', '_')}",
|
347
|
+
resource_uri=uri,
|
348
|
+
resource_type=resource_type,
|
349
|
+
description=description,
|
350
|
+
)
|
351
|
+
|
352
|
+
# Override process method if handler provided
|
353
|
+
if handler:
|
354
|
+
|
355
|
+
def custom_process(inputs):
|
356
|
+
try:
|
357
|
+
result = handler(inputs.get("resource_uri", uri))
|
358
|
+
return {"resource_content": result}
|
359
|
+
except Exception as e:
|
360
|
+
return {"resource_content": None, "error": str(e)}
|
361
|
+
|
362
|
+
resource_node.process = custom_process
|
363
|
+
|
364
|
+
self.resources[uri] = resource_node
|
365
|
+
|
366
|
+
# Emit middleware event
|
367
|
+
if self.event_stream:
|
368
|
+
await self._emit_mcp_event(
|
369
|
+
"resource_registered",
|
370
|
+
{"resource_uri": uri, "resource_type": resource_type},
|
371
|
+
)
|
372
|
+
|
373
|
+
logger.info(f"Registered MCP resource: {uri}")
|
374
|
+
return {"success": True, "resource_uri": uri}
|
375
|
+
|
376
|
+
async def execute_tool(
|
377
|
+
self, tool_name: str, arguments: Dict[str, Any], session_id: str = None
|
378
|
+
) -> Dict[str, Any]:
|
379
|
+
"""Execute MCP tool using Kailash workflow."""
|
380
|
+
|
381
|
+
if tool_name not in self.tools:
|
382
|
+
return {
|
383
|
+
"success": False,
|
384
|
+
"error": f"Tool {tool_name} not found",
|
385
|
+
"available_tools": list(self.tools.keys()),
|
386
|
+
}
|
387
|
+
|
388
|
+
# Execute using Kailash tool node
|
389
|
+
tool_node = self.tools[tool_name]
|
390
|
+
|
391
|
+
try:
|
392
|
+
result = tool_node.process({"tool_input": arguments})
|
393
|
+
|
394
|
+
# Emit middleware event
|
395
|
+
if self.event_stream:
|
396
|
+
await self._emit_mcp_event(
|
397
|
+
"tool_executed",
|
398
|
+
{
|
399
|
+
"tool_name": tool_name,
|
400
|
+
"arguments": arguments,
|
401
|
+
"session_id": session_id,
|
402
|
+
"success": True,
|
403
|
+
},
|
404
|
+
)
|
405
|
+
|
406
|
+
return {
|
407
|
+
"success": True,
|
408
|
+
"tool_name": tool_name,
|
409
|
+
"result": result,
|
410
|
+
"execution_count": tool_node.execution_count,
|
411
|
+
}
|
412
|
+
|
413
|
+
except Exception as e:
|
414
|
+
# Emit error event
|
415
|
+
if self.event_stream:
|
416
|
+
await self._emit_mcp_event(
|
417
|
+
"tool_execution_failed",
|
418
|
+
{"tool_name": tool_name, "error": str(e), "session_id": session_id},
|
419
|
+
)
|
420
|
+
|
421
|
+
return {"success": False, "error": str(e), "tool_name": tool_name}
|
422
|
+
|
423
|
+
async def get_resource(self, uri: str, session_id: str = None) -> Dict[str, Any]:
|
424
|
+
"""Get MCP resource using Kailash patterns."""
|
425
|
+
|
426
|
+
if uri not in self.resources:
|
427
|
+
return {
|
428
|
+
"success": False,
|
429
|
+
"error": f"Resource {uri} not found",
|
430
|
+
"available_resources": list(self.resources.keys()),
|
431
|
+
}
|
432
|
+
|
433
|
+
resource_node = self.resources[uri]
|
434
|
+
|
435
|
+
try:
|
436
|
+
result = resource_node.process({"resource_uri": uri})
|
437
|
+
|
438
|
+
# Emit middleware event
|
439
|
+
if self.event_stream:
|
440
|
+
await self._emit_mcp_event(
|
441
|
+
"resource_accessed",
|
442
|
+
{"resource_uri": uri, "session_id": session_id, "success": True},
|
443
|
+
)
|
444
|
+
|
445
|
+
return {
|
446
|
+
"success": True,
|
447
|
+
"resource_uri": uri,
|
448
|
+
"content": result,
|
449
|
+
"access_count": resource_node.access_count,
|
450
|
+
}
|
451
|
+
|
452
|
+
except Exception as e:
|
453
|
+
return {"success": False, "error": str(e), "resource_uri": uri}
|
454
|
+
|
455
|
+
async def list_capabilities(self) -> Dict[str, Any]:
|
456
|
+
"""List MCP server capabilities using Kailash patterns."""
|
457
|
+
|
458
|
+
return {
|
459
|
+
"server_info": {
|
460
|
+
"name": self.config.name,
|
461
|
+
"version": self.config.version,
|
462
|
+
"description": self.config.description,
|
463
|
+
"server_id": self.server_id,
|
464
|
+
"implementation": "Kailash SDK Middleware",
|
465
|
+
},
|
466
|
+
"tools": {
|
467
|
+
name: {
|
468
|
+
"description": tool.description,
|
469
|
+
"parameters_schema": tool.parameters_schema,
|
470
|
+
"execution_count": tool.execution_count,
|
471
|
+
"last_executed": (
|
472
|
+
tool.last_executed.isoformat() if tool.last_executed else None
|
473
|
+
),
|
474
|
+
}
|
475
|
+
for name, tool in self.tools.items()
|
476
|
+
},
|
477
|
+
"resources": {
|
478
|
+
uri: {
|
479
|
+
"resource_type": resource.resource_type,
|
480
|
+
"description": resource.description,
|
481
|
+
"access_count": resource.access_count,
|
482
|
+
}
|
483
|
+
for uri, resource in self.resources.items()
|
484
|
+
},
|
485
|
+
"features": {
|
486
|
+
"caching": self.config.enable_caching,
|
487
|
+
"metrics": self.config.enable_metrics,
|
488
|
+
"events": self.config.enable_events,
|
489
|
+
"streaming": self.config.enable_streaming,
|
490
|
+
"kailash_integration": True,
|
491
|
+
},
|
492
|
+
}
|
493
|
+
|
494
|
+
async def start(self):
|
495
|
+
"""Start MCP server with Kailash integration."""
|
496
|
+
self.started_at = datetime.now(timezone.utc)
|
497
|
+
|
498
|
+
# Start base server if available
|
499
|
+
if self.base_server:
|
500
|
+
# This would start the actual MCP protocol server
|
501
|
+
pass
|
502
|
+
|
503
|
+
# Emit startup event
|
504
|
+
if self.event_stream:
|
505
|
+
await self._emit_mcp_event(
|
506
|
+
"server_started",
|
507
|
+
{"server_id": self.server_id, "name": self.config.name},
|
508
|
+
)
|
509
|
+
|
510
|
+
logger.info(f"Started Kailash MCP Server: {self.config.name}")
|
511
|
+
|
512
|
+
async def stop(self):
|
513
|
+
"""Stop MCP server."""
|
514
|
+
# Emit shutdown event
|
515
|
+
if self.event_stream:
|
516
|
+
await self._emit_mcp_event(
|
517
|
+
"server_stopped",
|
518
|
+
{
|
519
|
+
"server_id": self.server_id,
|
520
|
+
"uptime_seconds": (
|
521
|
+
(datetime.now(timezone.utc) - self.started_at).total_seconds()
|
522
|
+
if self.started_at
|
523
|
+
else 0
|
524
|
+
),
|
525
|
+
},
|
526
|
+
)
|
527
|
+
|
528
|
+
logger.info(f"Stopped Kailash MCP Server: {self.config.name}")
|
529
|
+
|
530
|
+
async def _emit_mcp_event(self, event_type: str, data: Dict[str, Any]):
|
531
|
+
"""Emit MCP event to middleware event stream."""
|
532
|
+
|
533
|
+
from ..events import WorkflowEvent
|
534
|
+
|
535
|
+
event = WorkflowEvent(
|
536
|
+
type=EventType.SYSTEM_STATUS,
|
537
|
+
workflow_id="mcp_server",
|
538
|
+
data={
|
539
|
+
"mcp_event_type": event_type,
|
540
|
+
"server_id": self.server_id,
|
541
|
+
"server_name": self.config.name,
|
542
|
+
**data,
|
543
|
+
},
|
544
|
+
)
|
545
|
+
|
546
|
+
await self.event_stream.emit(event)
|
547
|
+
|
548
|
+
def get_stats(self) -> Dict[str, Any]:
|
549
|
+
"""Get MCP server statistics."""
|
550
|
+
uptime = (
|
551
|
+
(datetime.now(timezone.utc) - self.started_at).total_seconds()
|
552
|
+
if self.started_at
|
553
|
+
else 0
|
554
|
+
)
|
555
|
+
|
556
|
+
return {
|
557
|
+
"server_info": {
|
558
|
+
"server_id": self.server_id,
|
559
|
+
"name": self.config.name,
|
560
|
+
"uptime_seconds": uptime,
|
561
|
+
"started_at": self.started_at.isoformat() if self.started_at else None,
|
562
|
+
},
|
563
|
+
"tools": {
|
564
|
+
"total_tools": len(self.tools),
|
565
|
+
"total_executions": sum(
|
566
|
+
tool.execution_count for tool in self.tools.values()
|
567
|
+
),
|
568
|
+
},
|
569
|
+
"resources": {
|
570
|
+
"total_resources": len(self.resources),
|
571
|
+
"total_accesses": sum(
|
572
|
+
res.access_count for res in self.resources.values()
|
573
|
+
),
|
574
|
+
},
|
575
|
+
"implementation": "Kailash SDK Middleware MCP Server",
|
576
|
+
}
|
kailash/nodes/__init__.py
CHANGED
@@ -1,15 +1,31 @@
|
|
1
1
|
"""Node system for the Kailash SDK."""
|
2
2
|
|
3
3
|
# Import all node modules to ensure registration
|
4
|
-
from kailash.nodes import
|
4
|
+
from kailash.nodes import (
|
5
|
+
ai,
|
6
|
+
api,
|
7
|
+
auth,
|
8
|
+
code,
|
9
|
+
compliance,
|
10
|
+
data,
|
11
|
+
enterprise,
|
12
|
+
logic,
|
13
|
+
mixins,
|
14
|
+
monitoring,
|
15
|
+
security,
|
16
|
+
testing,
|
17
|
+
transform,
|
18
|
+
)
|
5
19
|
from kailash.nodes.base import Node, NodeParameter, NodeRegistry, register_node
|
6
|
-
from kailash.nodes.base_async import AsyncNode
|
7
20
|
from kailash.nodes.base_cycle_aware import CycleAwareNode
|
8
21
|
from kailash.nodes.code import PythonCodeNode
|
9
22
|
|
23
|
+
# Compatibility alias - AsyncNode is now just Node
|
24
|
+
AsyncNode = Node
|
25
|
+
|
10
26
|
__all__ = [
|
11
27
|
"Node",
|
12
|
-
"AsyncNode",
|
28
|
+
"AsyncNode", # Compatibility alias
|
13
29
|
"CycleAwareNode",
|
14
30
|
"NodeParameter",
|
15
31
|
"NodeRegistry",
|
@@ -18,9 +34,15 @@ __all__ = [
|
|
18
34
|
# Node modules
|
19
35
|
"ai",
|
20
36
|
"api",
|
37
|
+
"auth",
|
21
38
|
"code",
|
39
|
+
"compliance",
|
22
40
|
"data",
|
41
|
+
"enterprise",
|
23
42
|
"logic",
|
24
43
|
"mixins",
|
44
|
+
"monitoring",
|
45
|
+
"security",
|
46
|
+
"testing",
|
25
47
|
"transform",
|
26
48
|
]
|
@@ -0,0 +1,35 @@
|
|
1
|
+
"""Admin tool framework for enterprise user and permission management.
|
2
|
+
|
3
|
+
This module provides comprehensive admin functionality including user management,
|
4
|
+
role-based access control (RBAC), attribute-based access control (ABAC),
|
5
|
+
audit logging, and security event tracking.
|
6
|
+
|
7
|
+
Architecture:
|
8
|
+
- Built on Session 065's async database and ABAC infrastructure
|
9
|
+
- Django Admin-inspired features with SDK-native implementation
|
10
|
+
- Enterprise-grade scalability (500+ concurrent users)
|
11
|
+
- Multi-tenant support with data isolation
|
12
|
+
- Comprehensive audit trails for compliance
|
13
|
+
|
14
|
+
Core Components:
|
15
|
+
- UserManagementNode: Complete user lifecycle management
|
16
|
+
- RoleManagementNode: Role assignment and hierarchy management
|
17
|
+
- PermissionCheckNode: Real-time permission evaluation
|
18
|
+
- AuditLogNode: Comprehensive activity logging
|
19
|
+
- SecurityEventNode: Security incident tracking
|
20
|
+
"""
|
21
|
+
|
22
|
+
from .audit_log import AuditLogNode
|
23
|
+
from .permission_check import PermissionCheckNode
|
24
|
+
from .role_management import RoleManagementNode
|
25
|
+
from .security_event import SecurityEventNode
|
26
|
+
from .user_management import UserManagementNode
|
27
|
+
|
28
|
+
__all__ = [
|
29
|
+
# Core admin nodes
|
30
|
+
"UserManagementNode",
|
31
|
+
"RoleManagementNode",
|
32
|
+
"PermissionCheckNode",
|
33
|
+
"AuditLogNode",
|
34
|
+
"SecurityEventNode",
|
35
|
+
]
|