svrnty-mcp-gateway/docs/api/README.md
Svrnty 19ef79362e refactor: rename OpenHarbor.MCP to Svrnty.MCP across all libraries
- Renamed all directories: OpenHarbor.MCP.* → Svrnty.MCP.*
- Updated all namespaces in 179 C# files
- Renamed 20 .csproj files and 3 .sln files
- Updated 193 documentation references
- Updated 33 references in main CODEX codebase
- Updated Codex.sln with new paths
- Build verified: 0 errors

Preparing for extraction to standalone repositories.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-22 21:04:17 -04:00

16 KiB

Svrnty.MCP.Gateway - API Reference

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


Table of Contents


Core Abstractions

IGatewayRouter

Namespace: Svrnty.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: Svrnty.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: Svrnty.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: Svrnty.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: Svrnty.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: Svrnty.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: Svrnty.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: Svrnty.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: Svrnty.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 Svrnty.MCP.Gateway.AspNetCore;
using Svrnty.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