Reliability
Reliability patterns added and hardened in ISA MCP.
Key Improvements (2026-04-08)
- Health/readiness semantics with healthy vs degraded states
- Graceful semantic-to-lexical search fallback
- Vector ID overflow detection for Qdrant point IDs
- Exponential-backoff retry for transient Qdrant failures
- Cache key versioning for safe schema evolution
- Atomic delete patterns to avoid count/delete race conditions
- Transaction-wrapped migrations with rollback-ready structure
Health and Degraded Modes
GET /health distinguishes ready, degraded, and unready states instead of collapsing all dependency issues into a single healthy response.
| HTTP | status | Meaning |
|---|---|---|
200 | healthy | Critical dependencies are healthy and the server is ready |
200 | degraded | Traffic is still served, but some capability has degraded |
503 | degraded | The server is not ready because a critical dependency failed or a circuit breaker is open |
503 | initializing / draining | Startup or shutdown transition state |
The health payload includes a dedicated search block:
{
"search": {
"status": "ok",
"mode": "semantic"
}
}When the model dependency is unavailable, search degrades instead of hard-failing:
{
"search": {
"status": "degraded",
"mode": "lexical",
"reason": "ISA Model health check failed: ReadTimeout"
}
}Operationally:
- treat
search.mode = semanticas the normal steady state - treat
search.mode = lexicalas serviceable but degraded - treat
search.status = erroras unready and page on it
Standard Retry and Rate-Limit Headers
Structured resilience errors are translated into standard HTTP headers so clients can back off automatically.
HTTP 429 responses may include:
Retry-AfterX-RateLimit-LimitX-RateLimit-RemainingX-RateLimit-Reset
HTTP 502 responses raised from an open circuit breaker include:
Retry-After
Vector Store Safety
Overflow Detection
Vector IDs use type offsets. Capacity is bounded per type to avoid collisions.
- max items per type:
1,000,000 - warning threshold:
900,000
When limits are exceeded, writes fail early with explicit errors.
Retry Strategy
Qdrant writes/deletes are retried on transient failures:
- max retries:
3 - base delay:
0.5s - exponential backoff progression
Cache Versioning
Cache keys include an explicit schema version prefix:
mcp:cache:v{CACHE_VERSION}:...When schema changes, bumping CACHE_VERSION safely invalidates stale payload shapes.
Database Consistency
Atomic Deletes
COUNT + DELETE race windows were removed via CTE-style atomic delete-and-count queries.
Migration Safety
Migrations use:
BEGIN/COMMITtransactional boundaries- backup-first patterns for destructive changes
- idempotent DDL guards where possible
Health Failure Persistence
The aggregator persists health failure counts and error timestamps in the server registry so that failure state survives process restarts. Each server record carries two fields:
| Field | Type | Description |
|---|---|---|
health_failures | int | Consecutive failed health checks (resets to 0 on success) |
last_error_at | datetime | UTC timestamp of the most recent failure |
How it works
A background health monitor runs on a 30-second interval. For each connected server:
- A session-level health check is issued.
- On success,
health_failuresis reset to0in both in-memory state and the registry. - On failure,
health_failuresis incremented andlast_error_atis updated. - Once
health_failuresreaches the threshold (default3), the server status transitions toDEGRADED.
Because failures are written to the registry (PostgreSQL or in-memory store), a restarted aggregator can pick up where it left off instead of assuming all servers are healthy.
Health check response
The single-server health check returns:
{
"server_id": "uuid",
"server_name": "my-server",
"status": "connected",
"is_healthy": true,
"consecutive_failures": 0,
"last_check": "2026-03-12T10:00:00Z",
"health_check_url": "http://localhost:8080/health"
}Automatic recovery
The reconnect_unhealthy method iterates over all servers in DEGRADED or ERROR status and attempts reconnection. On a successful reconnect, health_failures is reset to 0.
Connection Event Tracking
Every connection lifecycle transition is recorded as a ConnectionEvent in a per-server ring buffer (default capacity: 100 events per server). Events are stored newest-first and are available through MCP tools for diagnostics.
Event types
| Event type | Emitted when |
|---|---|
connect | Session established successfully |
disconnect | Session closed (explicit or cleanup) |
reconnect | A reconnect cycle begins |
error | Connection fails after all retry attempts |
resume | SSE/streamable-HTTP session resumption attempted |
Event structure
Each event contains:
{
"event_type": "connect",
"timestamp": "2026-03-12T10:00:00Z",
"server_id": "uuid",
"details": "Connected successfully"
}Aggregator Observability Tools
The following MCP tools expose health and connection state at runtime. They are registered under AggregatorTools and available to any connected client.
aggregator_health
Run a health check across all connected servers or a single server.
| Parameter | Type | Description |
|---|---|---|
server_name | string | Filter to a specific server (optional) |
server_id | string | Filter by UUID (optional) |
Returns a list of health status objects (see health check response above).
get_aggregator_state
Dashboard-style snapshot of the entire aggregation layer.
Returns:
{
"total_servers": 5,
"connected_servers": 3,
"disconnected_servers": 1,
"error_servers": 1,
"total_tools": 42,
"servers": [
{ "id": "uuid", "name": "my-server", "status": "connected", "tool_count": 12 }
]
}get_server_connection_info
Detailed connection metadata for a single server including transport type, uptime, session ID, last event ID, and the 10 most recent events.
| Parameter | Type | Description |
|---|---|---|
server_name | string | Server name (optional) |
server_id | string | Server UUID (optional) |
Returns:
{
"server_id": "uuid",
"transport_type": "stdio",
"connected_at": "2026-03-12T09:00:00Z",
"uptime_seconds": 3600,
"session_id": "abc123",
"last_event_id": "evt-99",
"recent_events": [
{ "event_type": "connect", "timestamp": "2026-03-12T09:00:00Z", "details": "Connected successfully" }
]
}get_connection_history
Full connection event history for a server, useful for post-incident analysis.
| Parameter | Type | Default | Description |
|---|---|---|---|
server_name | string | Server name (optional) | |
server_id | string | Server UUID (optional) | |
limit | integer | 50 | Max events to return (1-100) |
Returns an array of event objects, newest first.
reconnect_server
Force-disconnect and reconnect a specific server, rediscovering its tools. Use this when a server is misbehaving or after its configuration changes.
| Parameter | Type | Description |
|---|---|---|
server_name | string | Server name (optional) |
server_id | string | Server UUID (optional) |
Returns:
{
"success": true,
"server_id": "uuid",
"status": "connected",
"tools_discovered": 12
}On reconnect, health failures are reset to 0 and a reconnect event is recorded in the connection history.