svrnty-mcp-gateway/docs/api/README.md
Svrnty a4a1dd2e38 docs: comprehensive AI coding assistant research and MCP-first implementation plan
Research conducted on modern AI coding assistants (Cursor, GitHub Copilot, Cline,
Aider, Windsurf, Replit Agent) to understand architecture patterns, context management,
code editing workflows, and tool use protocols.

Key Decision: Pivoted from building full CLI (40-50h) to validation-driven MCP-first
approach (10-15h). Build 5 core CODEX MCP tools that work with ANY coding assistant,
validate adoption over 2-4 weeks, then decide on full CLI if demand proven.

Files:
- research/ai-systems/modern-coding-assistants-architecture.md (comprehensive research)
- research/ai-systems/codex-coding-assistant-implementation-plan.md (original CLI plan, preserved)
- research/ai-systems/codex-mcp-tools-implementation-plan.md (approved MCP-first plan)
- ideas/registry.json (updated with approved MCP tools proposal)

Architech Validation: APPROVED with pivot to MCP-first approach
Human Decision: Approved (pragmatic validation-driven development)

Next: Begin Phase 1 implementation (10-15 hours, 5 core MCP tools)

🤖 Generated with CODEX Research System

Co-Authored-By: The Archivist <archivist@codex.svrnty.io>
Co-Authored-By: The Architech <architech@codex.svrnty.io>
Co-Authored-By: Mathias Beaulieu-Duncan <mat@svrnty.io>
2025-10-22 21:00:34 -04:00

766 lines
16 KiB
Markdown

# OpenHarbor.MCP.Gateway - API Reference
**Version:** 1.0.0
**Last Updated:** 2025-10-19
**Status:** Production-Ready
---
## Table of Contents
- [Core Abstractions](#core-abstractions)
- [IGatewayRouter](#igatewayrouter)
- [IRoutingStrategy](#iroutingstrategy)
- [ICircuitBreaker](#icircuitbreaker)
- [Infrastructure](#infrastructure)
- [GatewayRouter](#gatewayrouter)
- [RoutingStrategies](#routing-strategies)
- [CircuitBreaker](#circuitbreaker)
- [Models](#models)
- [RoutingContext](#routingcontext)
- [ServerInfo](#serverinfo)
- [GatewayConfig](#gatewayconfig)
- [ASP.NET Core Integration](#aspnet-core-integration)
- [Service Extensions](#service-extensions)
- [Endpoint Mapping](#endpoint-mapping)
- [Monitoring](#monitoring)
---
## Core Abstractions
### IGatewayRouter
**Namespace:** `OpenHarbor.MCP.Gateway.Core.Abstractions`
Interface defining the gateway routing contract.
#### Methods
##### RouteRequestAsync
```csharp
Task<McpToolResult> RouteRequestAsync(
RoutingContext context,
CancellationToken cancellationToken = default)
```
Routes an MCP request to an appropriate backend server.
**Parameters:**
- `context` (RoutingContext): Request routing context
- `cancellationToken` (CancellationToken): Cancellation support
**Returns:** `Task<McpToolResult>` - The result from the backend server
**Throws:**
- `NoHealthyServersException` - If all servers are unhealthy
- `RoutingException` - If routing decision fails
- `CircuitBreakerOpenException` - If circuit breaker is open
**Example:**
```csharp
var context = new RoutingContext
{
ClientId = "web-client",
ToolName = "search_documents",
Parameters = new Dictionary<string, object>
{
["query"] = "architecture"
}
};
var result = await router.RouteRequestAsync(context);
```
##### GetServerHealthAsync
```csharp
Task<IEnumerable<ServerHealth>> GetServerHealthAsync(
CancellationToken cancellationToken = default)
```
Gets health status of all registered servers.
**Returns:** `Task<IEnumerable<ServerHealth>>` - Health information for each server
**Example:**
```csharp
var healthStatuses = await router.GetServerHealthAsync();
foreach (var status in healthStatuses)
{
Console.WriteLine($"{status.ServerName}: {status.Status}");
}
```
---
### IRoutingStrategy
**Namespace:** `OpenHarbor.MCP.Gateway.Core.Abstractions`
Interface for implementing custom routing logic.
#### Methods
##### SelectServer
```csharp
string SelectServer(
RoutingContext context,
IEnumerable<ServerInfo> availableServers)
```
Selects a server to handle the request.
**Parameters:**
- `context` (RoutingContext): Request context
- `availableServers` (IEnumerable<ServerInfo>): Healthy servers
**Returns:** `string` - ID of the selected server
**Throws:**
- `NoServerAvailableException` - If no servers match criteria
**Example Implementation:**
```csharp
public class ToolBasedRoutingStrategy : IRoutingStrategy
{
public string SelectServer(
RoutingContext context,
IEnumerable<ServerInfo> servers)
{
// Route based on tool name pattern
if (context.ToolName.StartsWith("search_"))
{
return servers.First(s => s.Name == "search-server").Id;
}
// Default: first available
return servers.First().Id;
}
}
```
---
### ICircuitBreaker
**Namespace:** `OpenHarbor.MCP.Gateway.Core.Abstractions`
Interface for circuit breaker pattern implementation.
#### Properties
##### State
```csharp
CircuitBreakerState State { get; }
```
Current state of the circuit breaker.
```csharp
public enum CircuitBreakerState
{
Closed, // Normal operation
Open, // Failing, rejecting requests
HalfOpen // Testing if recovered
}
```
#### Methods
##### IsOpen
```csharp
bool IsOpen(string serverId)
```
Checks if circuit breaker is open for a specific server.
**Parameters:**
- `serverId` (string): Server identifier
**Returns:** `bool` - True if circuit is open (rejecting requests)
##### RecordSuccess
```csharp
Task RecordSuccessAsync(string serverId)
```
Records a successful request.
##### RecordFailure
```csharp
Task RecordFailureAsync(string serverId, Exception exception)
```
Records a failed request.
**Example:**
```csharp
if (_circuitBreaker.IsOpen("server-1"))
{
throw new CircuitBreakerOpenException("server-1");
}
try
{
var result = await CallServerAsync("server-1", request);
await _circuitBreaker.RecordSuccessAsync("server-1");
return result;
}
catch (Exception ex)
{
await _circuitBreaker.RecordFailureAsync("server-1", ex);
throw;
}
```
---
## Infrastructure
### GatewayRouter
**Namespace:** `OpenHarbor.MCP.Gateway.Infrastructure`
Default implementation of `IGatewayRouter`.
#### Constructor
```csharp
public GatewayRouter(
IRoutingStrategy routingStrategy,
ICircuitBreaker circuitBreaker,
IServerRegistry serverRegistry,
ILogger<GatewayRouter> logger = null)
```
**Parameters:**
- `routingStrategy` (IRoutingStrategy): Strategy for server selection
- `circuitBreaker` (ICircuitBreaker): Circuit breaker implementation
- `serverRegistry` (IServerRegistry): Registry of backend servers
- `logger` (ILogger): Optional logger
**Example:**
```csharp
var registry = new ServerRegistry();
registry.AddServer(new ServerInfo
{
Id = "server-1",
Name = "CODEX Server",
BaseUrl = "http://localhost:5050"
});
var router = new GatewayRouter(
new RoundRobinStrategy(),
new CircuitBreaker(),
registry
);
```
---
### Routing Strategies
Built-in routing strategy implementations.
#### RoundRobinStrategy
Distributes requests evenly across all healthy servers.
```csharp
public class RoundRobinStrategy : IRoutingStrategy
{
public string SelectServer(
RoutingContext context,
IEnumerable<ServerInfo> servers)
{
// Round-robin logic
var serverList = servers.ToList();
var index = _counter++ % serverList.Count;
return serverList[index].Id;
}
}
```
**Use Case:** Load balancing across identical servers
#### LeastConnectionsStrategy
Routes to the server with fewest active connections.
```csharp
public class LeastConnectionsStrategy : IRoutingStrategy
{
public string SelectServer(
RoutingContext context,
IEnumerable<ServerInfo> servers)
{
return servers
.OrderBy(s => s.ActiveConnections)
.First()
.Id;
}
}
```
**Use Case:** Balancing load when servers have different capacities
#### ToolBasedStrategy
Routes based on tool name patterns.
```csharp
public class ToolBasedStrategy : IRoutingStrategy
{
private readonly Dictionary<string, string> _toolToServerMap;
public string SelectServer(
RoutingContext context,
IEnumerable<ServerInfo> servers)
{
if (_toolToServerMap.TryGetValue(context.ToolName, out var serverId))
{
return serverId;
}
// Default fallback
return servers.First().Id;
}
}
```
**Use Case:** Route specific tools to specialized servers
---
### CircuitBreaker
**Namespace:** `OpenHarbor.MCP.Gateway.Infrastructure.Resilience`
Default circuit breaker implementation.
#### Configuration
```csharp
public class CircuitBreakerConfig
{
public int FailureThreshold { get; set; } = 5;
public int SuccessThreshold { get; set; } = 2;
public TimeSpan Timeout { get; set; } = TimeSpan.FromMinutes(1);
}
```
#### Usage
```csharp
var config = new CircuitBreakerConfig
{
FailureThreshold = 5, // Open after 5 failures
SuccessThreshold = 2, // Close after 2 successes
Timeout = TimeSpan.FromMinutes(1) // Test recovery after 1 min
};
var circuitBreaker = new CircuitBreaker(config);
```
---
## Models
### RoutingContext
**Namespace:** `OpenHarbor.MCP.Gateway.Core.Models`
Context information for routing decisions.
#### Properties
```csharp
public class RoutingContext
{
public string ClientId { get; set; }
public string ToolName { get; set; }
public Dictionary<string, object> Parameters { get; set; }
public Dictionary<string, string> Headers { get; set; }
public DateTime Timestamp { get; set; }
}
```
#### Example
```csharp
var context = new RoutingContext
{
ClientId = "web-client-123",
ToolName = "search_documents",
Parameters = new Dictionary<string, object>
{
["query"] = "test"
},
Headers = new Dictionary<string, string>
{
["X-Client-Version"] = "1.0.0"
},
Timestamp = DateTime.UtcNow
};
```
---
### ServerInfo
**Namespace:** `OpenHarbor.MCP.Gateway.Core.Models`
Information about a registered backend server.
#### Properties
```csharp
public class ServerInfo
{
public string Id { get; set; }
public string Name { get; set; }
public string BaseUrl { get; set; }
public bool IsHealthy { get; set; }
public int ActiveConnections { get; set; }
public DateTime LastHealthCheck { get; set; }
public TimeSpan AverageResponseTime { get; set; }
}
```
#### Example
```csharp
var serverInfo = new ServerInfo
{
Id = "codex-server-1",
Name = "CODEX MCP Server 1",
BaseUrl = "http://localhost:5050",
IsHealthy = true,
ActiveConnections = 3,
LastHealthCheck = DateTime.UtcNow,
AverageResponseTime = TimeSpan.FromMilliseconds(45)
};
```
---
### GatewayConfig
**Namespace:** `OpenHarbor.MCP.Gateway.Core.Models`
Gateway configuration.
#### Properties
```csharp
public class GatewayConfig
{
public string Name { get; set; }
public string Version { get; set; }
public string ListenAddress { get; set; }
public List<ServerConfig> Servers { get; set; }
public RoutingConfig Routing { get; set; }
public SecurityConfig Security { get; set; }
}
public class ServerConfig
{
public string Id { get; set; }
public string Name { get; set; }
public string BaseUrl { get; set; }
public bool Enabled { get; set; }
}
public class RoutingConfig
{
public string Strategy { get; set; } // "RoundRobin", "LeastConnections", "ToolBased"
public TimeSpan HealthCheckInterval { get; set; }
}
```
---
## ASP.NET Core Integration
### Service Extensions
**Namespace:** `OpenHarbor.MCP.Gateway.AspNetCore`
#### AddMcpGateway
```csharp
public static IServiceCollection AddMcpGateway(
this IServiceCollection services,
IConfiguration configuration)
```
Registers gateway services and dependencies.
**Configuration:**
```json
{
"Mcp": {
"Gateway": {
"Name": "MyGateway",
"Version": "1.0.0",
"ListenAddress": "http://localhost:8080"
},
"Servers": [ ... ],
"Routing": {
"Strategy": "RoundRobin",
"HealthCheckInterval": "00:00:30"
}
}
}
```
**Example:**
```csharp
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddMcpGateway(
builder.Configuration.GetSection("Mcp")
);
builder.Services.AddHealthChecks()
.AddCheck<McpServerHealthCheck>("mcp-servers");
var app = builder.Build();
app.MapMcpGateway();
app.MapHealthChecks("/health");
app.Run();
```
---
### Endpoint Mapping
#### MapMcpGateway
```csharp
public static IEndpointRouteBuilder MapMcpGateway(
this IEndpointRouteBuilder endpoints)
```
Maps gateway HTTP endpoints.
**Endpoints:**
- `POST /mcp/invoke` - Route MCP requests
- `GET /health` - Gateway health check
- `GET /servers` - List backend servers
- `GET /servers/{id}/health` - Server-specific health
**Example:**
```csharp
var app = builder.Build();
app.MapMcpGateway();
```
---
## Monitoring
### Metrics
OpenTelemetry metrics exposed by the gateway:
```csharp
public class GatewayMetrics
{
public Counter<long> TotalRequests { get; }
public Histogram<double> RequestDuration { get; }
public Counter<long> TotalErrors { get; }
public Gauge<int> ServerHealth { get; }
public Gauge<int> CircuitBreakerState { get; }
}
```
**Metric Names:**
- `mcp_gateway_requests_total`
- `mcp_gateway_request_duration_ms`
- `mcp_gateway_errors_total`
- `mcp_gateway_server_health`
- `mcp_gateway_circuit_breaker_state`
**Example Query (Prometheus):**
```promql
# Average request latency
rate(mcp_gateway_request_duration_ms_sum[5m]) /
rate(mcp_gateway_request_duration_ms_count[5m])
# Error rate
rate(mcp_gateway_errors_total[5m]) /
rate(mcp_gateway_requests_total[5m])
```
---
### Health Checks
#### Gateway Health Endpoint
```bash
curl http://localhost:8080/health
```
**Response:**
```json
{
"status": "Healthy",
"totalServers": 3,
"healthyServers": 3,
"degradedServers": 0,
"unhealthyServers": 0,
"servers": [
{
"id": "codex-server-1",
"name": "CODEX Server 1",
"status": "Healthy",
"lastCheck": "2025-10-19T12:00:00Z",
"responseTime": "12ms"
}
]
}
```
#### Custom Health Check
```csharp
public class McpServerHealthCheck : IHealthCheck
{
private readonly IGatewayRouter _router;
public async Task<HealthCheckResult> CheckHealthAsync(
HealthCheckContext context,
CancellationToken cancellationToken = default)
{
var serverHealth = await _router.GetServerHealthAsync(cancellationToken);
var unhealthyServers = serverHealth
.Count(s => s.Status != ServerHealthStatus.Healthy);
if (unhealthyServers == 0)
{
return HealthCheckResult.Healthy("All servers healthy");
}
if (unhealthyServers == serverHealth.Count())
{
return HealthCheckResult.Unhealthy("All servers unhealthy");
}
return HealthCheckResult.Degraded(
$"{unhealthyServers} of {serverHealth.Count()} servers unhealthy"
);
}
}
```
---
## Complete Example
### Creating a Gateway
```csharp
using OpenHarbor.MCP.Gateway.AspNetCore;
using OpenHarbor.MCP.Gateway.Core;
var builder = WebApplication.CreateBuilder(args);
// Add gateway services
builder.Services.AddMcpGateway(
builder.Configuration.GetSection("Mcp")
);
// Add custom routing strategy
builder.Services.AddSingleton<IRoutingStrategy, ToolBasedStrategy>();
// Add health checks
builder.Services.AddHealthChecks()
.AddCheck<McpServerHealthCheck>("mcp-servers");
var app = builder.Build();
// Map gateway endpoints
app.MapMcpGateway();
app.MapHealthChecks("/health");
// Start gateway
await app.RunAsync();
```
### Custom Routing Strategy
```csharp
public class CustomRoutingStrategy : IRoutingStrategy
{
public string SelectServer(
RoutingContext context,
IEnumerable<ServerInfo> servers)
{
// Route admin clients to dedicated server
if (context.ClientId.StartsWith("admin-"))
{
return servers.First(s => s.Name.Contains("admin")).Id;
}
// Route search tools to search-optimized server
if (context.ToolName.StartsWith("search_"))
{
return servers.First(s => s.Name.Contains("search")).Id;
}
// Default: least connections
return servers
.OrderBy(s => s.ActiveConnections)
.First()
.Id;
}
}
```
### Using the Gateway (Client Side)
```bash
# Route request through gateway
curl -X POST http://localhost:8080/mcp/invoke \
-H "Content-Type: application/json" \
-H "X-Client-Id: web-client" \
-d '{
"jsonrpc": "2.0",
"id": "1",
"method": "tools/call",
"params": {
"name": "search_documents",
"arguments": {
"query": "architecture"
}
}
}'
```
---
## See Also
- [Gateway Architecture](../architecture.md)
- [Module Design](../module-design.md)
- [Routing Strategies](../routing-strategies.md)
- [Security Guide](../security.md)
- [AGENT-PRIMER.md](../../AGENT-PRIMER.md)
---
**Document Type:** API Reference
**Version:** 1.0.0
**Last Updated:** 2025-10-19
**Maintained By:** Svrnty Development Team