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

341 lines
8.9 KiB
Markdown

# OpenHarbor.MCP.Client - Module Design
**Document Type:** Architecture Design Document
**Status:** Planned
**Version:** 1.0.0
**Last Updated:** 2025-10-19
---
## Overview
OpenHarbor.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
```
┌─────────────────────────────────────────────────┐
│ OpenHarbor.MCP.Client.Cli (Executable) │
│ ┌───────────────────────────────────────────┐ │
│ │ OpenHarbor.MCP.Client.AspNetCore (DI) │ │
│ │ ┌─────────────────────────────────────┐ │ │
│ │ │ OpenHarbor.MCP.Client.Infrastructure│ │ │
│ │ │ ┌───────────────────────────────┐ │ │ │
│ │ │ │ OpenHarbor.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