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.
- kailash/__init__.py +3 -3
- kailash/api/custom_nodes_secure.py +3 -3
- kailash/api/gateway.py +1 -1
- kailash/api/studio.py +2 -3
- kailash/api/workflow_api.py +3 -4
- kailash/core/resilience/bulkhead.py +460 -0
- kailash/core/resilience/circuit_breaker.py +92 -10
- kailash/edge/discovery.py +86 -0
- kailash/mcp_server/__init__.py +334 -0
- kailash/mcp_server/advanced_features.py +1022 -0
- kailash/{mcp → mcp_server}/ai_registry_server.py +29 -4
- kailash/mcp_server/auth.py +789 -0
- kailash/mcp_server/client.py +712 -0
- kailash/mcp_server/discovery.py +1593 -0
- kailash/mcp_server/errors.py +673 -0
- kailash/mcp_server/oauth.py +1727 -0
- kailash/mcp_server/protocol.py +1126 -0
- kailash/mcp_server/registry_integration.py +587 -0
- kailash/mcp_server/server.py +1747 -0
- kailash/{mcp → mcp_server}/servers/ai_registry.py +2 -2
- kailash/mcp_server/transports.py +1169 -0
- kailash/mcp_server/utils/cache.py +510 -0
- kailash/middleware/auth/auth_manager.py +3 -3
- kailash/middleware/communication/api_gateway.py +2 -9
- kailash/middleware/communication/realtime.py +1 -1
- kailash/middleware/mcp/client_integration.py +1 -1
- kailash/middleware/mcp/enhanced_server.py +2 -2
- kailash/nodes/__init__.py +2 -0
- kailash/nodes/admin/audit_log.py +6 -6
- kailash/nodes/admin/permission_check.py +8 -8
- kailash/nodes/admin/role_management.py +32 -28
- kailash/nodes/admin/schema.sql +6 -1
- kailash/nodes/admin/schema_manager.py +13 -13
- kailash/nodes/admin/security_event.py +16 -20
- kailash/nodes/admin/tenant_isolation.py +3 -3
- kailash/nodes/admin/transaction_utils.py +3 -3
- kailash/nodes/admin/user_management.py +21 -22
- kailash/nodes/ai/a2a.py +11 -11
- kailash/nodes/ai/ai_providers.py +9 -12
- kailash/nodes/ai/embedding_generator.py +13 -14
- kailash/nodes/ai/intelligent_agent_orchestrator.py +19 -19
- kailash/nodes/ai/iterative_llm_agent.py +3 -3
- kailash/nodes/ai/llm_agent.py +213 -36
- kailash/nodes/ai/self_organizing.py +2 -2
- kailash/nodes/alerts/discord.py +4 -4
- kailash/nodes/api/graphql.py +6 -6
- kailash/nodes/api/http.py +12 -17
- kailash/nodes/api/rate_limiting.py +4 -4
- kailash/nodes/api/rest.py +15 -15
- kailash/nodes/auth/mfa.py +3 -4
- kailash/nodes/auth/risk_assessment.py +2 -2
- kailash/nodes/auth/session_management.py +5 -5
- kailash/nodes/auth/sso.py +143 -0
- kailash/nodes/base.py +6 -2
- kailash/nodes/base_async.py +16 -2
- kailash/nodes/base_with_acl.py +2 -2
- kailash/nodes/cache/__init__.py +9 -0
- kailash/nodes/cache/cache.py +1172 -0
- kailash/nodes/cache/cache_invalidation.py +870 -0
- kailash/nodes/cache/redis_pool_manager.py +595 -0
- kailash/nodes/code/async_python.py +2 -1
- kailash/nodes/code/python.py +196 -35
- kailash/nodes/compliance/data_retention.py +6 -6
- kailash/nodes/compliance/gdpr.py +5 -5
- kailash/nodes/data/__init__.py +10 -0
- kailash/nodes/data/optimistic_locking.py +906 -0
- kailash/nodes/data/readers.py +8 -8
- kailash/nodes/data/redis.py +349 -0
- kailash/nodes/data/sql.py +314 -3
- kailash/nodes/data/streaming.py +21 -0
- kailash/nodes/enterprise/__init__.py +8 -0
- kailash/nodes/enterprise/audit_logger.py +285 -0
- kailash/nodes/enterprise/batch_processor.py +22 -3
- kailash/nodes/enterprise/data_lineage.py +1 -1
- kailash/nodes/enterprise/mcp_executor.py +205 -0
- kailash/nodes/enterprise/service_discovery.py +150 -0
- kailash/nodes/enterprise/tenant_assignment.py +108 -0
- kailash/nodes/logic/async_operations.py +2 -2
- kailash/nodes/logic/convergence.py +1 -1
- kailash/nodes/logic/operations.py +1 -1
- kailash/nodes/monitoring/__init__.py +11 -1
- kailash/nodes/monitoring/health_check.py +456 -0
- kailash/nodes/monitoring/log_processor.py +817 -0
- kailash/nodes/monitoring/metrics_collector.py +627 -0
- kailash/nodes/monitoring/performance_benchmark.py +137 -11
- kailash/nodes/rag/advanced.py +7 -7
- kailash/nodes/rag/agentic.py +49 -2
- kailash/nodes/rag/conversational.py +3 -3
- kailash/nodes/rag/evaluation.py +3 -3
- kailash/nodes/rag/federated.py +3 -3
- kailash/nodes/rag/graph.py +3 -3
- kailash/nodes/rag/multimodal.py +3 -3
- kailash/nodes/rag/optimized.py +5 -5
- kailash/nodes/rag/privacy.py +3 -3
- kailash/nodes/rag/query_processing.py +6 -6
- kailash/nodes/rag/realtime.py +1 -1
- kailash/nodes/rag/registry.py +2 -6
- kailash/nodes/rag/router.py +1 -1
- kailash/nodes/rag/similarity.py +7 -7
- kailash/nodes/rag/strategies.py +4 -4
- kailash/nodes/security/abac_evaluator.py +6 -6
- kailash/nodes/security/behavior_analysis.py +5 -6
- kailash/nodes/security/credential_manager.py +1 -1
- kailash/nodes/security/rotating_credentials.py +11 -11
- kailash/nodes/security/threat_detection.py +8 -8
- kailash/nodes/testing/credential_testing.py +2 -2
- kailash/nodes/transform/processors.py +5 -5
- kailash/runtime/local.py +162 -14
- kailash/runtime/parameter_injection.py +425 -0
- kailash/runtime/parameter_injector.py +657 -0
- kailash/runtime/testing.py +2 -2
- kailash/testing/fixtures.py +2 -2
- kailash/workflow/builder.py +99 -18
- kailash/workflow/builder_improvements.py +207 -0
- kailash/workflow/input_handling.py +170 -0
- {kailash-0.6.2.dist-info → kailash-0.6.4.dist-info}/METADATA +21 -8
- {kailash-0.6.2.dist-info → kailash-0.6.4.dist-info}/RECORD +126 -101
- kailash/mcp/__init__.py +0 -53
- kailash/mcp/client.py +0 -445
- kailash/mcp/server.py +0 -292
- kailash/mcp/server_enhanced.py +0 -449
- kailash/mcp/utils/cache.py +0 -267
- /kailash/{mcp → mcp_server}/client_new.py +0 -0
- /kailash/{mcp → mcp_server}/utils/__init__.py +0 -0
- /kailash/{mcp → mcp_server}/utils/config.py +0 -0
- /kailash/{mcp → mcp_server}/utils/formatters.py +0 -0
- /kailash/{mcp → mcp_server}/utils/metrics.py +0 -0
- {kailash-0.6.2.dist-info → kailash-0.6.4.dist-info}/WHEEL +0 -0
- {kailash-0.6.2.dist-info → kailash-0.6.4.dist-info}/entry_points.txt +0 -0
- {kailash-0.6.2.dist-info → kailash-0.6.4.dist-info}/licenses/LICENSE +0 -0
- {kailash-0.6.2.dist-info → kailash-0.6.4.dist-info}/top_level.txt +0 -0
@@ -23,6 +23,7 @@ Example:
|
|
23
23
|
|
24
24
|
import asyncio
|
25
25
|
import logging
|
26
|
+
import random
|
26
27
|
import time
|
27
28
|
from collections import deque
|
28
29
|
from dataclasses import dataclass, field
|
@@ -61,6 +62,15 @@ class CircuitBreakerConfig:
|
|
61
62
|
window_size: int = 100 # Rolling window for error rate
|
62
63
|
excluded_exceptions: List[type] = field(default_factory=list) # Don't count these
|
63
64
|
|
65
|
+
# Enhanced configurable thresholds
|
66
|
+
min_calls_before_evaluation: int = 10 # Min calls before evaluating error rate
|
67
|
+
slow_call_threshold: float = 5.0 # Seconds to consider a call slow
|
68
|
+
slow_call_rate_threshold: float = 0.8 # Rate of slow calls to trigger open
|
69
|
+
max_wait_duration_in_half_open: int = 60 # Max wait in half-open state
|
70
|
+
exponential_backoff_multiplier: float = 2.0 # Backoff multiplier for recovery
|
71
|
+
jitter_enabled: bool = True # Add jitter to recovery timeout
|
72
|
+
max_jitter_percentage: float = 0.1 # Maximum jitter as percentage of timeout
|
73
|
+
|
64
74
|
|
65
75
|
@dataclass
|
66
76
|
class CircuitBreakerMetrics:
|
@@ -70,36 +80,59 @@ class CircuitBreakerMetrics:
|
|
70
80
|
successful_calls: int = 0
|
71
81
|
failed_calls: int = 0
|
72
82
|
rejected_calls: int = 0
|
83
|
+
slow_calls: int = 0 # New: Track slow calls
|
73
84
|
state_transitions: List[Dict[str, Any]] = field(default_factory=list)
|
74
85
|
last_failure_time: Optional[float] = None
|
75
86
|
consecutive_failures: int = 0
|
76
87
|
consecutive_successes: int = 0
|
88
|
+
avg_call_duration: float = 0.0 # New: Average call duration
|
89
|
+
total_call_duration: float = 0.0 # New: Total duration for average calculation
|
77
90
|
|
78
|
-
def record_success(self):
|
91
|
+
def record_success(self, duration: float = 0.0):
|
79
92
|
"""Record successful call."""
|
80
93
|
self.total_calls += 1
|
81
94
|
self.successful_calls += 1
|
82
95
|
self.consecutive_successes += 1
|
83
96
|
self.consecutive_failures = 0
|
97
|
+
self._update_duration(duration)
|
84
98
|
|
85
|
-
def record_failure(self):
|
99
|
+
def record_failure(self, duration: float = 0.0):
|
86
100
|
"""Record failed call."""
|
87
101
|
self.total_calls += 1
|
88
102
|
self.failed_calls += 1
|
89
103
|
self.consecutive_failures += 1
|
90
104
|
self.consecutive_successes = 0
|
91
105
|
self.last_failure_time = time.time()
|
106
|
+
self._update_duration(duration)
|
92
107
|
|
93
108
|
def record_rejection(self):
|
94
109
|
"""Record rejected call (circuit open)."""
|
95
110
|
self.rejected_calls += 1
|
96
111
|
|
112
|
+
def record_slow_call(self):
|
113
|
+
"""Record slow call."""
|
114
|
+
self.slow_calls += 1
|
115
|
+
|
116
|
+
def _update_duration(self, duration: float):
|
117
|
+
"""Update duration metrics."""
|
118
|
+
if duration > 0:
|
119
|
+
self.total_call_duration += duration
|
120
|
+
# Update rolling average
|
121
|
+
if self.total_calls > 0:
|
122
|
+
self.avg_call_duration = self.total_call_duration / self.total_calls
|
123
|
+
|
97
124
|
def get_error_rate(self) -> float:
|
98
125
|
"""Calculate current error rate."""
|
99
126
|
if self.total_calls == 0:
|
100
127
|
return 0.0
|
101
128
|
return self.failed_calls / self.total_calls
|
102
129
|
|
130
|
+
def get_slow_call_rate(self) -> float:
|
131
|
+
"""Calculate current slow call rate."""
|
132
|
+
if self.total_calls == 0:
|
133
|
+
return 0.0
|
134
|
+
return self.slow_calls / self.total_calls
|
135
|
+
|
103
136
|
|
104
137
|
class ConnectionCircuitBreaker(Generic[T]):
|
105
138
|
"""Circuit breaker for database connections and operations.
|
@@ -159,14 +192,21 @@ class ConnectionCircuitBreaker(Generic[T]):
|
|
159
192
|
start_time = time.time()
|
160
193
|
try:
|
161
194
|
result = await func(*args, **kwargs)
|
162
|
-
|
195
|
+
execution_time = time.time() - start_time
|
196
|
+
|
197
|
+
# Check if this was a slow call
|
198
|
+
is_slow = execution_time > self.config.slow_call_threshold
|
199
|
+
|
200
|
+
await self._record_success(execution_time, is_slow)
|
163
201
|
return result
|
164
202
|
except Exception as e:
|
203
|
+
execution_time = time.time() - start_time
|
204
|
+
|
165
205
|
# Check if this exception should be counted
|
166
206
|
if not any(
|
167
207
|
isinstance(e, exc_type) for exc_type in self.config.excluded_exceptions
|
168
208
|
):
|
169
|
-
await self._record_failure(e)
|
209
|
+
await self._record_failure(e, execution_time)
|
170
210
|
raise
|
171
211
|
|
172
212
|
async def _check_state_transition(self):
|
@@ -191,6 +231,10 @@ class ConnectionCircuitBreaker(Generic[T]):
|
|
191
231
|
|
192
232
|
def _should_open(self) -> bool:
|
193
233
|
"""Determine if circuit should open based on failures."""
|
234
|
+
# Only evaluate if we have minimum number of calls
|
235
|
+
if self.metrics.total_calls < self.config.min_calls_before_evaluation:
|
236
|
+
return False
|
237
|
+
|
194
238
|
# Check consecutive failures
|
195
239
|
if self.metrics.consecutive_failures >= self.config.failure_threshold:
|
196
240
|
return True
|
@@ -202,22 +246,32 @@ class ConnectionCircuitBreaker(Generic[T]):
|
|
202
246
|
if error_rate >= self.config.error_rate_threshold:
|
203
247
|
return True
|
204
248
|
|
249
|
+
# Check slow call rate
|
250
|
+
slow_call_rate = self.metrics.get_slow_call_rate()
|
251
|
+
if slow_call_rate >= self.config.slow_call_rate_threshold:
|
252
|
+
return True
|
253
|
+
|
205
254
|
return False
|
206
255
|
|
207
|
-
async def _record_success(self):
|
256
|
+
async def _record_success(self, duration: float = 0.0, is_slow: bool = False):
|
208
257
|
"""Record successful execution."""
|
209
258
|
async with self._lock:
|
210
|
-
self.metrics.record_success()
|
259
|
+
self.metrics.record_success(duration)
|
260
|
+
if is_slow:
|
261
|
+
self.metrics.record_slow_call()
|
211
262
|
self._rolling_window.append(True)
|
212
263
|
|
213
264
|
if self.state == CircuitState.HALF_OPEN:
|
214
265
|
if self.metrics.consecutive_successes >= self.config.success_threshold:
|
215
266
|
await self._transition_to(CircuitState.CLOSED)
|
216
267
|
|
217
|
-
async def _record_failure(self, error: Exception):
|
268
|
+
async def _record_failure(self, error: Exception, duration: float = 0.0):
|
218
269
|
"""Record failed execution."""
|
219
270
|
async with self._lock:
|
220
|
-
self.metrics.record_failure()
|
271
|
+
self.metrics.record_failure(duration)
|
272
|
+
# Consider slow failures as additional burden
|
273
|
+
if duration > self.config.slow_call_threshold:
|
274
|
+
self.metrics.record_slow_call()
|
221
275
|
self._rolling_window.append(False)
|
222
276
|
|
223
277
|
if self.state == CircuitState.HALF_OPEN:
|
@@ -280,11 +334,31 @@ class ConnectionCircuitBreaker(Generic[T]):
|
|
280
334
|
return "Unknown reason"
|
281
335
|
|
282
336
|
def _time_until_recovery(self) -> float:
|
283
|
-
"""Calculate seconds until recovery attempt."""
|
337
|
+
"""Calculate seconds until recovery attempt with jitter and backoff."""
|
284
338
|
if self.state != CircuitState.OPEN:
|
285
339
|
return 0.0
|
340
|
+
|
286
341
|
elapsed = time.time() - self._last_state_change
|
287
|
-
|
342
|
+
|
343
|
+
# Apply exponential backoff based on number of state transitions to OPEN
|
344
|
+
open_transitions = sum(
|
345
|
+
1
|
346
|
+
for t in self.metrics.state_transitions
|
347
|
+
if t.get("to") == CircuitState.OPEN.value
|
348
|
+
)
|
349
|
+
backoff_multiplier = self.config.exponential_backoff_multiplier ** max(
|
350
|
+
0, open_transitions - 1
|
351
|
+
)
|
352
|
+
|
353
|
+
base_timeout = self.config.recovery_timeout * backoff_multiplier
|
354
|
+
|
355
|
+
# Add jitter if enabled
|
356
|
+
if self.config.jitter_enabled:
|
357
|
+
jitter_range = base_timeout * self.config.max_jitter_percentage
|
358
|
+
jitter = random.uniform(-jitter_range, jitter_range)
|
359
|
+
base_timeout += jitter
|
360
|
+
|
361
|
+
remaining = base_timeout - elapsed
|
288
362
|
return max(0.0, remaining)
|
289
363
|
|
290
364
|
async def force_open(self, reason: str = "Manual override"):
|
@@ -331,7 +405,10 @@ class ConnectionCircuitBreaker(Generic[T]):
|
|
331
405
|
"successful_calls": self.metrics.successful_calls,
|
332
406
|
"failed_calls": self.metrics.failed_calls,
|
333
407
|
"rejected_calls": self.metrics.rejected_calls,
|
408
|
+
"slow_calls": self.metrics.slow_calls,
|
334
409
|
"error_rate": self.metrics.get_error_rate(),
|
410
|
+
"slow_call_rate": self.metrics.get_slow_call_rate(),
|
411
|
+
"avg_call_duration": self.metrics.avg_call_duration,
|
335
412
|
"consecutive_failures": self.metrics.consecutive_failures,
|
336
413
|
"consecutive_successes": self.metrics.consecutive_successes,
|
337
414
|
},
|
@@ -340,6 +417,11 @@ class ConnectionCircuitBreaker(Generic[T]):
|
|
340
417
|
"success_threshold": self.config.success_threshold,
|
341
418
|
"recovery_timeout": self.config.recovery_timeout,
|
342
419
|
"error_rate_threshold": self.config.error_rate_threshold,
|
420
|
+
"slow_call_threshold": self.config.slow_call_threshold,
|
421
|
+
"slow_call_rate_threshold": self.config.slow_call_rate_threshold,
|
422
|
+
"min_calls_before_evaluation": self.config.min_calls_before_evaluation,
|
423
|
+
"exponential_backoff_multiplier": self.config.exponential_backoff_multiplier,
|
424
|
+
"jitter_enabled": self.config.jitter_enabled,
|
343
425
|
},
|
344
426
|
"time_until_recovery": (
|
345
427
|
self._time_until_recovery() if self.state == CircuitState.OPEN else None
|
kailash/edge/discovery.py
CHANGED
@@ -199,6 +199,92 @@ class EdgeDiscovery:
|
|
199
199
|
self._last_health_check[location.location_id] = datetime.now(UTC)
|
200
200
|
logger.info(f"Added edge location: {location.name}")
|
201
201
|
|
202
|
+
async def register_edge(self, edge_config: Dict[str, Any]):
|
203
|
+
"""Register an edge location from configuration dictionary.
|
204
|
+
|
205
|
+
Args:
|
206
|
+
edge_config: Dictionary containing edge location configuration
|
207
|
+
"""
|
208
|
+
from .location import (
|
209
|
+
ComplianceZone,
|
210
|
+
EdgeCapabilities,
|
211
|
+
EdgeLocation,
|
212
|
+
EdgeRegion,
|
213
|
+
GeographicCoordinates,
|
214
|
+
)
|
215
|
+
|
216
|
+
# Extract basic info
|
217
|
+
location_id = edge_config["id"]
|
218
|
+
region_str = edge_config.get("region", "us-east")
|
219
|
+
|
220
|
+
# Map region string to enum
|
221
|
+
region_map = {
|
222
|
+
"us-east-1": EdgeRegion.US_EAST,
|
223
|
+
"us-west-1": EdgeRegion.US_WEST,
|
224
|
+
"eu-west-1": EdgeRegion.EU_WEST,
|
225
|
+
"eu-central-1": EdgeRegion.EU_CENTRAL,
|
226
|
+
"asia-southeast-1": EdgeRegion.ASIA_SOUTHEAST,
|
227
|
+
}
|
228
|
+
region = region_map.get(region_str, EdgeRegion.US_EAST)
|
229
|
+
|
230
|
+
# Default coordinates based on region
|
231
|
+
coord_map = {
|
232
|
+
EdgeRegion.US_EAST: GeographicCoordinates(39.0458, -76.6413), # Virginia
|
233
|
+
EdgeRegion.US_WEST: GeographicCoordinates(37.7749, -122.4194), # California
|
234
|
+
EdgeRegion.EU_WEST: GeographicCoordinates(53.3498, -6.2603), # Ireland
|
235
|
+
EdgeRegion.EU_CENTRAL: GeographicCoordinates(50.1109, 8.6821), # Frankfurt
|
236
|
+
EdgeRegion.ASIA_SOUTHEAST: GeographicCoordinates(
|
237
|
+
1.3521, 103.8198
|
238
|
+
), # Singapore
|
239
|
+
}
|
240
|
+
coordinates = coord_map.get(region, GeographicCoordinates(39.0458, -76.6413))
|
241
|
+
|
242
|
+
# Create capabilities
|
243
|
+
capabilities = EdgeCapabilities(
|
244
|
+
cpu_cores=edge_config.get("capacity", 1000) // 100, # Rough mapping
|
245
|
+
memory_gb=edge_config.get("capacity", 1000) // 50,
|
246
|
+
storage_gb=edge_config.get("capacity", 1000) * 2,
|
247
|
+
bandwidth_gbps=10.0,
|
248
|
+
database_support=["postgresql", "redis"],
|
249
|
+
ai_models_available=["llama", "claude"],
|
250
|
+
)
|
251
|
+
|
252
|
+
# Create edge location
|
253
|
+
location = EdgeLocation(
|
254
|
+
location_id=location_id,
|
255
|
+
name=f"Edge {region_str.title()}",
|
256
|
+
region=region,
|
257
|
+
coordinates=coordinates,
|
258
|
+
capabilities=capabilities,
|
259
|
+
endpoint_url=edge_config.get(
|
260
|
+
"endpoint", f"http://{location_id}.edge.local:8080"
|
261
|
+
),
|
262
|
+
)
|
263
|
+
|
264
|
+
# Set health status
|
265
|
+
from .location import EdgeStatus
|
266
|
+
|
267
|
+
if edge_config.get("healthy", True):
|
268
|
+
location.status = EdgeStatus.ACTIVE
|
269
|
+
self._health_results[location_id] = HealthCheckResult.HEALTHY
|
270
|
+
else:
|
271
|
+
location.status = EdgeStatus.OFFLINE
|
272
|
+
self._health_results[location_id] = HealthCheckResult.UNHEALTHY
|
273
|
+
|
274
|
+
# Update metrics
|
275
|
+
location.metrics.latency_p50_ms = edge_config.get("latency_ms", 10)
|
276
|
+
location.metrics.cpu_utilization = edge_config.get(
|
277
|
+
"current_load", 0
|
278
|
+
) / edge_config.get("capacity", 1000)
|
279
|
+
|
280
|
+
# Add to locations
|
281
|
+
self.locations[location_id] = location
|
282
|
+
self._last_health_check[location_id] = datetime.now(UTC)
|
283
|
+
|
284
|
+
logger.info(f"Registered edge location: {location_id} in {region_str}")
|
285
|
+
|
286
|
+
return location
|
287
|
+
|
202
288
|
def remove_location(self, location_id: str):
|
203
289
|
"""Remove an edge location from the discovery pool."""
|
204
290
|
if location_id in self.locations:
|
@@ -0,0 +1,334 @@
|
|
1
|
+
"""Enhanced Model Context Protocol (MCP) Service Layer with Service Discovery.
|
2
|
+
|
3
|
+
This module provides production-ready MCP client and server functionality with
|
4
|
+
comprehensive service discovery, authentication, monitoring, and resilience
|
5
|
+
features. Built on top of the official Anthropic MCP Python SDK.
|
6
|
+
|
7
|
+
Enhanced Features:
|
8
|
+
- Service Discovery: Automatic server registration and discovery
|
9
|
+
- Authentication: Multiple auth providers (API Key, JWT, OAuth)
|
10
|
+
- Load Balancing: Intelligent server selection and failover
|
11
|
+
- Health Monitoring: Automatic health checking and status tracking
|
12
|
+
- Circuit Breaker: Failure detection and recovery patterns
|
13
|
+
- Metrics Collection: Comprehensive performance monitoring
|
14
|
+
- Network Discovery: UDP broadcast/multicast server discovery
|
15
|
+
- Error Handling: Structured error codes and retry strategies
|
16
|
+
|
17
|
+
Design Philosophy:
|
18
|
+
Provides production-ready distributed systems infrastructure for MCP
|
19
|
+
while maintaining compatibility with the official SDK. Enhances the
|
20
|
+
basic protocol implementation with enterprise-grade features.
|
21
|
+
|
22
|
+
Key Components:
|
23
|
+
- MCPClient: Enhanced client with auth, retry, and multi-transport support
|
24
|
+
- MCPServer: Production-ready server with all enterprise features
|
25
|
+
- ServiceRegistry: Central registry for server discovery and management
|
26
|
+
- ServiceMesh: Intelligent routing and load balancing
|
27
|
+
- ServerRegistrar: Automatic server registration and lifecycle management
|
28
|
+
|
29
|
+
Service Discovery Features:
|
30
|
+
- File-based registry with JSON storage
|
31
|
+
- Network discovery via UDP broadcast/multicast
|
32
|
+
- Health checking and automatic status updates
|
33
|
+
- Capability-based server filtering
|
34
|
+
- Load balancing with priority scoring
|
35
|
+
- Automatic failover and circuit breaker patterns
|
36
|
+
|
37
|
+
Examples:
|
38
|
+
Enhanced MCP client with discovery:
|
39
|
+
|
40
|
+
>>> from kailash.mcp_server import get_mcp_client, discover_mcp_servers
|
41
|
+
>>> # Discover servers with specific capability
|
42
|
+
>>> servers = await discover_mcp_servers(capability="search")
|
43
|
+
>>> # Get best client for capability
|
44
|
+
>>> client = await get_mcp_client("search")
|
45
|
+
>>> result = await client.call_tool(server_config, "search", {"query": "AI"})
|
46
|
+
|
47
|
+
Production MCP server with auto-discovery:
|
48
|
+
|
49
|
+
>>> from kailash.mcp_server import MCPServer, enable_auto_discovery
|
50
|
+
>>> from kailash.mcp_server.auth import APIKeyAuth
|
51
|
+
>>>
|
52
|
+
>>> # Create server with authentication
|
53
|
+
>>> auth = APIKeyAuth({"user1": "secret-key"})
|
54
|
+
>>> server = MCPServer(
|
55
|
+
... "my-tools",
|
56
|
+
... auth_provider=auth,
|
57
|
+
... enable_metrics=True,
|
58
|
+
... circuit_breaker_config={"failure_threshold": 5}
|
59
|
+
... )
|
60
|
+
>>>
|
61
|
+
>>> @server.tool(required_permission="tools.calculate")
|
62
|
+
... def calculate(a: int, b: int) -> int:
|
63
|
+
... return a + b
|
64
|
+
>>>
|
65
|
+
>>> # Enable auto-discovery and start
|
66
|
+
>>> registrar = enable_auto_discovery(server, enable_network_discovery=True)
|
67
|
+
>>> registrar.start_with_registration()
|
68
|
+
|
69
|
+
Service mesh with failover:
|
70
|
+
|
71
|
+
>>> from kailash.mcp_server import ServiceRegistry, ServiceMesh
|
72
|
+
>>> registry = ServiceRegistry()
|
73
|
+
>>> mesh = ServiceMesh(registry)
|
74
|
+
>>>
|
75
|
+
>>> # Call with automatic failover
|
76
|
+
>>> result = await mesh.call_with_failover(
|
77
|
+
... "search", "web_search", {"query": "Python"}, max_retries=3
|
78
|
+
... )
|
79
|
+
"""
|
80
|
+
|
81
|
+
# Advanced Features
|
82
|
+
from .advanced_features import (
|
83
|
+
BinaryResourceHandler,
|
84
|
+
CancellationContext,
|
85
|
+
ChangeType,
|
86
|
+
Content,
|
87
|
+
ContentType,
|
88
|
+
ElicitationSystem,
|
89
|
+
MultiModalContent,
|
90
|
+
ProgressReporter,
|
91
|
+
ResourceChange,
|
92
|
+
)
|
93
|
+
from .advanced_features import ResourceTemplate as AdvancedResourceTemplate
|
94
|
+
from .advanced_features import (
|
95
|
+
SchemaValidator,
|
96
|
+
StreamingHandler,
|
97
|
+
StructuredTool,
|
98
|
+
ToolAnnotation,
|
99
|
+
create_cancellation_context,
|
100
|
+
create_progress_reporter,
|
101
|
+
structured_tool,
|
102
|
+
)
|
103
|
+
|
104
|
+
# Authentication framework
|
105
|
+
from .auth import (
|
106
|
+
APIKeyAuth,
|
107
|
+
AuthManager,
|
108
|
+
AuthProvider,
|
109
|
+
BasicAuth,
|
110
|
+
BearerTokenAuth,
|
111
|
+
JWTAuth,
|
112
|
+
PermissionManager,
|
113
|
+
RateLimiter,
|
114
|
+
)
|
115
|
+
from .client import MCPClient
|
116
|
+
|
117
|
+
# Service Discovery System
|
118
|
+
from .discovery import (
|
119
|
+
DiscoveryBackend,
|
120
|
+
FileBasedDiscovery,
|
121
|
+
HealthChecker,
|
122
|
+
LoadBalancer,
|
123
|
+
NetworkDiscovery,
|
124
|
+
ServerInfo,
|
125
|
+
ServiceMesh,
|
126
|
+
ServiceRegistry,
|
127
|
+
create_default_registry,
|
128
|
+
discover_mcp_servers,
|
129
|
+
get_mcp_client,
|
130
|
+
)
|
131
|
+
|
132
|
+
# Enhanced error handling
|
133
|
+
from .errors import (
|
134
|
+
AuthenticationError,
|
135
|
+
AuthorizationError,
|
136
|
+
CircuitBreakerRetry,
|
137
|
+
ErrorAggregator,
|
138
|
+
ExponentialBackoffRetry,
|
139
|
+
MCPError,
|
140
|
+
MCPErrorCode,
|
141
|
+
RateLimitError,
|
142
|
+
ResourceError,
|
143
|
+
RetryableOperation,
|
144
|
+
RetryStrategy,
|
145
|
+
ServiceDiscoveryError,
|
146
|
+
ToolError,
|
147
|
+
TransportError,
|
148
|
+
ValidationError,
|
149
|
+
)
|
150
|
+
|
151
|
+
# OAuth 2.1 Authentication
|
152
|
+
from .oauth import (
|
153
|
+
AccessToken,
|
154
|
+
AuthorizationCode,
|
155
|
+
AuthorizationServer,
|
156
|
+
ClientStore,
|
157
|
+
ClientType,
|
158
|
+
GrantType,
|
159
|
+
InMemoryClientStore,
|
160
|
+
InMemoryTokenStore,
|
161
|
+
JWTManager,
|
162
|
+
OAuth2Client,
|
163
|
+
OAuthClient,
|
164
|
+
RefreshToken,
|
165
|
+
ResourceServer,
|
166
|
+
TokenStore,
|
167
|
+
TokenType,
|
168
|
+
)
|
169
|
+
|
170
|
+
# Complete Protocol Implementation
|
171
|
+
from .protocol import (
|
172
|
+
CancellationManager,
|
173
|
+
CancelledNotification,
|
174
|
+
CompletionManager,
|
175
|
+
CompletionRequest,
|
176
|
+
CompletionResult,
|
177
|
+
MessageType,
|
178
|
+
MetaData,
|
179
|
+
ProgressManager,
|
180
|
+
ProgressNotification,
|
181
|
+
ProgressToken,
|
182
|
+
ProtocolManager,
|
183
|
+
ResourceTemplate,
|
184
|
+
RootsManager,
|
185
|
+
SamplingManager,
|
186
|
+
SamplingRequest,
|
187
|
+
ToolResult,
|
188
|
+
cancel_request,
|
189
|
+
complete_progress,
|
190
|
+
get_protocol_manager,
|
191
|
+
is_cancelled,
|
192
|
+
start_progress,
|
193
|
+
update_progress,
|
194
|
+
)
|
195
|
+
|
196
|
+
# Registry Integration
|
197
|
+
from .registry_integration import (
|
198
|
+
NetworkAnnouncer,
|
199
|
+
ServerRegistrar,
|
200
|
+
enable_auto_discovery,
|
201
|
+
register_server_manually,
|
202
|
+
)
|
203
|
+
|
204
|
+
# Enhanced server with production features
|
205
|
+
from .server import MCPServer, MCPServerBase, SimpleMCPServer
|
206
|
+
|
207
|
+
# Enhanced Transport Layer
|
208
|
+
from .transports import (
|
209
|
+
BaseTransport,
|
210
|
+
EnhancedStdioTransport,
|
211
|
+
SSETransport,
|
212
|
+
StreamableHTTPTransport,
|
213
|
+
TransportManager,
|
214
|
+
TransportSecurity,
|
215
|
+
WebSocketTransport,
|
216
|
+
get_transport_manager,
|
217
|
+
)
|
218
|
+
|
219
|
+
__all__ = [
|
220
|
+
# Core MCP Components
|
221
|
+
"MCPClient",
|
222
|
+
"MCPServer",
|
223
|
+
"MCPServerBase",
|
224
|
+
# Prototyping server
|
225
|
+
"SimpleMCPServer",
|
226
|
+
# Service Discovery System
|
227
|
+
"ServiceRegistry",
|
228
|
+
"ServerInfo",
|
229
|
+
"DiscoveryBackend",
|
230
|
+
"FileBasedDiscovery",
|
231
|
+
"NetworkDiscovery",
|
232
|
+
"HealthChecker",
|
233
|
+
"LoadBalancer",
|
234
|
+
"ServiceMesh",
|
235
|
+
"create_default_registry",
|
236
|
+
"discover_mcp_servers",
|
237
|
+
"get_mcp_client",
|
238
|
+
# Registry Integration
|
239
|
+
"ServerRegistrar",
|
240
|
+
"NetworkAnnouncer",
|
241
|
+
"enable_auto_discovery",
|
242
|
+
"register_server_manually",
|
243
|
+
# Authentication
|
244
|
+
"AuthProvider",
|
245
|
+
"APIKeyAuth",
|
246
|
+
"BearerTokenAuth",
|
247
|
+
"JWTAuth",
|
248
|
+
"BasicAuth",
|
249
|
+
"AuthManager",
|
250
|
+
"PermissionManager",
|
251
|
+
"RateLimiter",
|
252
|
+
# Enhanced Error Handling
|
253
|
+
"MCPError",
|
254
|
+
"MCPErrorCode",
|
255
|
+
"AuthenticationError",
|
256
|
+
"AuthorizationError",
|
257
|
+
"RateLimitError",
|
258
|
+
"ToolError",
|
259
|
+
"ResourceError",
|
260
|
+
"TransportError",
|
261
|
+
"ServiceDiscoveryError",
|
262
|
+
"ValidationError",
|
263
|
+
"RetryStrategy",
|
264
|
+
"RetryableOperation",
|
265
|
+
"ExponentialBackoffRetry",
|
266
|
+
"CircuitBreakerRetry",
|
267
|
+
"ErrorAggregator",
|
268
|
+
# Complete Protocol Implementation
|
269
|
+
"MessageType",
|
270
|
+
"ProgressToken",
|
271
|
+
"MetaData",
|
272
|
+
"ProgressNotification",
|
273
|
+
"CancelledNotification",
|
274
|
+
"CompletionRequest",
|
275
|
+
"CompletionResult",
|
276
|
+
"SamplingRequest",
|
277
|
+
"ResourceTemplate",
|
278
|
+
"ToolResult",
|
279
|
+
"ProgressManager",
|
280
|
+
"CancellationManager",
|
281
|
+
"CompletionManager",
|
282
|
+
"SamplingManager",
|
283
|
+
"RootsManager",
|
284
|
+
"ProtocolManager",
|
285
|
+
"get_protocol_manager",
|
286
|
+
"start_progress",
|
287
|
+
"update_progress",
|
288
|
+
"complete_progress",
|
289
|
+
"is_cancelled",
|
290
|
+
"cancel_request",
|
291
|
+
# Enhanced Transport Layer
|
292
|
+
"BaseTransport",
|
293
|
+
"EnhancedStdioTransport",
|
294
|
+
"SSETransport",
|
295
|
+
"StreamableHTTPTransport",
|
296
|
+
"WebSocketTransport",
|
297
|
+
"TransportSecurity",
|
298
|
+
"TransportManager",
|
299
|
+
"get_transport_manager",
|
300
|
+
# OAuth 2.1 Authentication
|
301
|
+
"GrantType",
|
302
|
+
"TokenType",
|
303
|
+
"ClientType",
|
304
|
+
"OAuthClient",
|
305
|
+
"AccessToken",
|
306
|
+
"RefreshToken",
|
307
|
+
"AuthorizationCode",
|
308
|
+
"ClientStore",
|
309
|
+
"InMemoryClientStore",
|
310
|
+
"TokenStore",
|
311
|
+
"InMemoryTokenStore",
|
312
|
+
"JWTManager",
|
313
|
+
"AuthorizationServer",
|
314
|
+
"ResourceServer",
|
315
|
+
"OAuth2Client",
|
316
|
+
# Advanced Features
|
317
|
+
"ContentType",
|
318
|
+
"ChangeType",
|
319
|
+
"Content",
|
320
|
+
"ResourceChange",
|
321
|
+
"ToolAnnotation",
|
322
|
+
"MultiModalContent",
|
323
|
+
"SchemaValidator",
|
324
|
+
"StructuredTool",
|
325
|
+
"AdvancedResourceTemplate",
|
326
|
+
"BinaryResourceHandler",
|
327
|
+
"StreamingHandler",
|
328
|
+
"ElicitationSystem",
|
329
|
+
"ProgressReporter",
|
330
|
+
"CancellationContext",
|
331
|
+
"structured_tool",
|
332
|
+
"create_progress_reporter",
|
333
|
+
"create_cancellation_context",
|
334
|
+
]
|