svrnty-mcp-gateway/docs/api
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
..
README.md docs: comprehensive AI coding assistant research and MCP-first implementation plan 2025-10-22 21:00:34 -04:00

OpenHarbor.MCP.Gateway - API Reference

Version: 1.0.0 Last Updated: 2025-10-19 Status: Production-Ready


Table of Contents


Core Abstractions

IGatewayRouter

Namespace: OpenHarbor.MCP.Gateway.Core.Abstractions

Interface defining the gateway routing contract.

Methods

RouteRequestAsync
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:

var context = new RoutingContext
{
    ClientId = "web-client",
    ToolName = "search_documents",
    Parameters = new Dictionary<string, object>
    {
        ["query"] = "architecture"
    }
};

var result = await router.RouteRequestAsync(context);
GetServerHealthAsync
Task<IEnumerable<ServerHealth>> GetServerHealthAsync(
    CancellationToken cancellationToken = default)

Gets health status of all registered servers.

Returns: Task<IEnumerable<ServerHealth>> - Health information for each server

Example:

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
string SelectServer(
    RoutingContext context,
    IEnumerable<ServerInfo> availableServers)

Selects a server to handle the request.

Parameters:

  • context (RoutingContext): Request context
  • availableServers (IEnumerable): Healthy servers

Returns: string - ID of the selected server

Throws:

  • NoServerAvailableException - If no servers match criteria

Example Implementation:

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
CircuitBreakerState State { get; }

Current state of the circuit breaker.

public enum CircuitBreakerState
{
    Closed,   // Normal operation
    Open,     // Failing, rejecting requests
    HalfOpen  // Testing if recovered
}

Methods

IsOpen
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
Task RecordSuccessAsync(string serverId)

Records a successful request.

RecordFailure
Task RecordFailureAsync(string serverId, Exception exception)

Records a failed request.

Example:

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

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:

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.

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.

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.

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

public class CircuitBreakerConfig
{
    public int FailureThreshold { get; set; } = 5;
    public int SuccessThreshold { get; set; } = 2;
    public TimeSpan Timeout { get; set; } = TimeSpan.FromMinutes(1);
}

Usage

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

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

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

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

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

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

public static IServiceCollection AddMcpGateway(
    this IServiceCollection services,
    IConfiguration configuration)

Registers gateway services and dependencies.

Configuration:

{
  "Mcp": {
    "Gateway": {
      "Name": "MyGateway",
      "Version": "1.0.0",
      "ListenAddress": "http://localhost:8080"
    },
    "Servers": [ ... ],
    "Routing": {
      "Strategy": "RoundRobin",
      "HealthCheckInterval": "00:00:30"
    }
  }
}

Example:

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

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:

var app = builder.Build();
app.MapMcpGateway();

Monitoring

Metrics

OpenTelemetry metrics exposed by the gateway:

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):

# 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

curl http://localhost:8080/health

Response:

{
  "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

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

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

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)

# 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


Document Type: API Reference Version: 1.0.0 Last Updated: 2025-10-19 Maintained By: Svrnty Development Team