svrnty-mcp-client/docs/module-design.md
Svrnty 97880406dc 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

341 lines
8.9 KiB
Markdown

# Svrnty.MCP.Client - Module Design
**Document Type:** Architecture Design Document
**Status:** Planned
**Version:** 1.0.0
**Last Updated:** 2025-10-19
---
## Overview
Svrnty.MCP.Client is a .NET 8 library that enables applications to act as MCP clients, consuming tools exposed by remote MCP servers. This document defines the architecture, components, and design decisions.
### Purpose
- **What**: Client library for connecting to and calling tools from MCP servers
- **Why**: Enable .NET applications to consume MCP server capabilities
- **How**: Clean Architecture with transport abstractions, connection pooling, and error handling
---
## Architecture
### Clean Architecture Layers
```
┌─────────────────────────────────────────────────┐
│ Svrnty.MCP.Client.Cli (Executable) │
│ ┌───────────────────────────────────────────┐ │
│ │ Svrnty.MCP.Client.AspNetCore (DI) │ │
│ │ ┌─────────────────────────────────────┐ │ │
│ │ │ Svrnty.MCP.Client.Infrastructure│ │ │
│ │ │ ┌───────────────────────────────┐ │ │ │
│ │ │ │ Svrnty.MCP.Client.Core │ │ │ │
│ │ │ │ - IMcpClient │ │ │ │
│ │ │ │ - IMcpServerConnection │ │ │ │
│ │ │ │ - IConnectionPool │ │ │ │
│ │ │ │ - Models (no dependencies) │ │ │ │
│ │ │ └───────────────────────────────┘ │ │ │
│ │ └─────────────────────────────────────┘ │ │
│ └───────────────────────────────────────────┘ │
└─────────────────────────────────────────────────┘
```
### Layer Responsibilities
| Layer | Purpose | Dependencies |
|-------|---------|--------------|
| **Core** | Abstractions and models | None |
| **Infrastructure** | Transport implementations | Core, System.Text.Json |
| **AspNetCore** | DI and configuration | Core, Infrastructure, ASP.NET Core |
| **Cli** | Command-line interface | All layers |
---
## Core Components
### IMcpClient Interface
Primary interface for client operations:
```csharp
public interface IMcpClient
{
// Connection Management
Task ConnectToServerAsync(string serverName, CancellationToken ct = default);
Task DisconnectFromServerAsync(string serverName, CancellationToken ct = default);
Task<IEnumerable<McpServerInfo>> GetConnectedServersAsync();
// Tool Discovery
Task<IEnumerable<McpToolInfo>> ListToolsAsync(string serverName, CancellationToken ct = default);
// Tool Execution
Task<McpToolResult> CallToolAsync(
string serverName,
string toolName,
Dictionary<string, object> arguments,
CancellationToken ct = default
);
// Health Monitoring
Task PingAsync(string serverName, CancellationToken ct = default);
}
```
### IMcpServerConnection Interface
Represents connection to a single MCP server:
```csharp
public interface IMcpServerConnection : IDisposable
{
string ServerName { get; }
bool IsConnected { get; }
DateTime LastActivity { get; }
Task<JsonRpcResponse> SendRequestAsync(
JsonRpcRequest request,
CancellationToken ct = default
);
Task ConnectAsync(CancellationToken ct = default);
Task DisconnectAsync(CancellationToken ct = default);
}
```
### IConnectionPool Interface
Manages connection pooling:
```csharp
public interface IConnectionPool
{
Task<IMcpServerConnection> AcquireConnectionAsync(
string serverName,
CancellationToken ct = default
);
void ReleaseConnection(IMcpServerConnection connection);
Task EvictIdleConnectionsAsync(CancellationToken ct = default);
}
```
---
## Transport Layer
### Supported Transports
#### Stdio Transport
Communication via standard input/output with spawned process:
```csharp
public class StdioTransport : IMcpTransport
{
private readonly string _command;
private readonly string[] _args;
private Process? _process;
public async Task<JsonRpcResponse> SendAsync(
JsonRpcRequest request,
CancellationToken ct)
{
// Write JSON to stdin
// Read JSON from stdout
// Handle stderr logging
}
}
```
#### HTTP Transport
Communication via HTTP API:
```csharp
public class HttpTransport : IMcpTransport
{
private readonly HttpClient _httpClient;
private readonly string _baseUrl;
public async Task<JsonRpcResponse> SendAsync(
JsonRpcRequest request,
CancellationToken ct)
{
// POST JSON to HTTP endpoint
// Deserialize response
}
}
```
---
## Configuration
### Server Configuration Model
```csharp
public class McpServerConfig
{
public string Name { get; set; }
public string? Description { get; set; }
public TransportConfig Transport { get; set; }
public TimeSpan Timeout { get; set; } = TimeSpan.FromSeconds(30);
public bool Enabled { get; set; } = true;
}
public class TransportConfig
{
public string Type { get; set; } // "Stdio" or "Http"
public string? Command { get; set; } // For Stdio
public string[]? Args { get; set; } // For Stdio
public string? BaseUrl { get; set; } // For HTTP
public Dictionary<string, string>? Headers { get; set; } // For HTTP
}
```
### Connection Configuration
```csharp
public class ConnectionConfig
{
public int MaxRetries { get; set; } = 3;
public int RetryDelayMs { get; set; } = 1000;
public double RetryBackoffMultiplier { get; set; } = 2.0;
public bool EnableConnectionPooling { get; set; } = true;
public int MaxConnectionsPerServer { get; set; } = 5;
public TimeSpan ConnectionIdleTimeout { get; set; } = TimeSpan.FromMinutes(5);
public TimeSpan PoolEvictionInterval { get; set; } = TimeSpan.FromMinutes(1);
}
```
---
## Error Handling
### Exception Hierarchy
```csharp
public class McpClientException : Exception { }
public class McpConnectionException : McpClientException { }
public class McpToolNotFoundException : McpClientException { }
public class McpToolExecutionException : McpClientException
{
public string ServerName { get; }
public string ToolName { get; }
public Dictionary<string, object> Arguments { get; }
}
public class McpTimeoutException : McpClientException { }
```
### Retry Strategy
```csharp
public class RetryPolicy
{
public async Task<T> ExecuteAsync<T>(
Func<Task<T>> operation,
int maxRetries,
int delayMs,
double backoffMultiplier)
{
for (int attempt = 0; attempt < maxRetries; attempt++)
{
try
{
return await operation();
}
catch (McpConnectionException) when (attempt < maxRetries - 1)
{
var delay = delayMs * Math.Pow(backoffMultiplier, attempt);
await Task.Delay((int)delay);
}
}
throw new McpConnectionException("Max retries exceeded");
}
}
```
---
## Testing Strategy
### Unit Tests
- Test Core abstractions with mocks
- Test Infrastructure implementations with mock transports
- Test retry logic and connection pooling
### Integration Tests
- Test actual connections to mock MCP servers
- Test tool discovery and execution
- Test error scenarios (timeouts, connection failures)
### Test Coverage Goals
- Core: >90%
- Infrastructure: >80%
- AspNetCore: >70%
---
## Performance Considerations
### Connection Pooling
- Reuse connections to avoid process spawn overhead
- Configurable pool size per server
- Idle connection eviction
### Request Pipelining
- Support concurrent requests to same server
- Queue requests when connection limit reached
### Timeout Management
- Per-server configurable timeouts
- Cancellation token support throughout
---
## Security
### Input Validation
- Validate server configuration
- Sanitize arguments before sending
- Validate JSON responses
### Connection Security
- HTTPS for HTTP transport
- Environment variable expansion for secrets
- No hardcoded credentials
---
## Future Enhancements
- [ ] WebSocket transport support
- [ ] Request/response compression
- [ ] Metrics and observability (OpenTelemetry)
- [ ] Connection health monitoring
- [ ] Circuit breaker pattern
- [ ] Server discovery mechanism
---
**Document Version:** 1.0.0
**Status:** Planned
**Next Review:** After Phase 1 implementation