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>
549 lines
16 KiB
Markdown
549 lines
16 KiB
Markdown
# OpenHarbor.MCP.Client
|
|
|
|
**A modular, scalable, secure .NET library for consuming Model Context Protocol (MCP) servers**
|
|
|
|
[](LICENSE)
|
|
[](https://dotnet.microsoft.com/download/dotnet/8.0)
|
|
[](docs/architecture.md)
|
|
|
|
---
|
|
|
|
## What is OpenHarbor.MCP.Client?
|
|
|
|
OpenHarbor.MCP.Client is a **standalone, reusable .NET library** that enables any .NET application to act as an MCP client, allowing your application to discover and call tools exposed by MCP servers.
|
|
|
|
**Model Context Protocol (MCP)** is an industry-standard protocol backed by Anthropic that defines how AI agents communicate with external tools and data sources. Think of it as a universal adapter that lets your application safely access capabilities from remote MCP servers.
|
|
|
|
### Key Features
|
|
|
|
- **Modular & Reusable**: Copy to any .NET project, configure, and go
|
|
- **Clean Architecture**: Core abstractions, infrastructure implementation, ASP.NET Core integration
|
|
- **Security-First**: Connection validation, timeout handling, error recovery
|
|
- **Transport Flexibility**: HTTP (primary for production) and stdio (legacy for local tools)
|
|
- **AI-Automated Setup**: AGENT-PRIMER.md guides AI assistants to configure your integration automatically
|
|
- **TDD Foundation**: Built with test-driven development, comprehensive test coverage
|
|
- **Production-Ready**: Observability, error handling, connection pooling, retry logic
|
|
|
|
---
|
|
|
|
## Why OpenHarbor.MCP.Client?
|
|
|
|
**Problem**: Your .NET application needs to access tools and capabilities exposed by remote MCP servers (search, data processing, API access) but has no standardized way to connect.
|
|
|
|
**Solution**: OpenHarbor.MCP.Client transforms your application into an MCP client, allowing you to discover, validate, and call tools from any MCP server with proper error handling and connection management.
|
|
|
|
**Use Cases**:
|
|
- Connect your app to Claude Desktop's exposed tools
|
|
- Call tools from remote knowledge bases or search engines
|
|
- Integrate with third-party MCP servers for document processing
|
|
- Build AI-powered workflows that consume multiple MCP services
|
|
- Access enterprise MCP servers for data analysis and reporting
|
|
|
|
---
|
|
|
|
## Quick Start
|
|
|
|
### Prerequisites
|
|
|
|
- .NET 8.0 SDK or higher
|
|
- Your existing .NET application (Web API, Console, Worker Service, etc.)
|
|
- Access to one or more MCP servers (local or remote)
|
|
|
|
### Option 1: AI-Automated Setup (Recommended)
|
|
|
|
If you have access to Claude or another AI assistant:
|
|
|
|
1. Copy this entire folder to your project directory
|
|
2. Open your AI assistant and say: "Read AGENT-PRIMER.md and set up OpenHarbor.MCP.Client for my project"
|
|
3. The AI will analyze your system, generate configuration, and create sample client code automatically
|
|
|
|
### Option 2: Manual Setup
|
|
|
|
#### Step 1: Add Package Reference
|
|
|
|
```bash
|
|
# Via project reference (development)
|
|
dotnet add reference /path/to/OpenHarbor.MCP.Client/src/OpenHarbor.MCP.Client.AspNetCore/OpenHarbor.MCP.Client.AspNetCore.csproj
|
|
|
|
# OR via NuGet (when published)
|
|
# dotnet add package OpenHarbor.MCP.Client.AspNetCore
|
|
```
|
|
|
|
#### Step 2: Configure appsettings.json
|
|
|
|
Add MCP client configuration:
|
|
|
|
```json
|
|
{
|
|
"Mcp": {
|
|
"Client": {
|
|
"Name": "MyAppMcpClient",
|
|
"Version": "1.0.0",
|
|
"Description": "MCP client for MyApp"
|
|
},
|
|
"Servers": [
|
|
{
|
|
"Name": "codex-server",
|
|
"Transport": {
|
|
"Type": "Http",
|
|
"BaseUrl": "http://localhost:5050"
|
|
},
|
|
"Timeout": "00:00:30",
|
|
"Enabled": true
|
|
},
|
|
{
|
|
"Name": "remote-mcp-server",
|
|
"Transport": {
|
|
"Type": "Http",
|
|
"BaseUrl": "https://api.example.com/mcp"
|
|
},
|
|
"Timeout": "00:00:60",
|
|
"Enabled": true
|
|
}
|
|
],
|
|
"Connection": {
|
|
"MaxRetries": 3,
|
|
"RetryDelayMs": 1000,
|
|
"EnableConnectionPooling": true
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
#### Step 3: Update Program.cs
|
|
|
|
```csharp
|
|
using OpenHarbor.MCP.Client.AspNetCore;
|
|
|
|
var builder = WebApplication.CreateBuilder(args);
|
|
|
|
// Add MCP client
|
|
builder.Services.AddMcpClient(builder.Configuration.GetSection("Mcp"));
|
|
|
|
var app = builder.Build();
|
|
|
|
app.Run();
|
|
```
|
|
|
|
#### Step 4: Use the Client to Call Tools
|
|
|
|
```csharp
|
|
using OpenHarbor.MCP.Client.Core.Abstractions;
|
|
|
|
public class MyService
|
|
{
|
|
private readonly IMcpClient _mcpClient;
|
|
|
|
public MyService(IMcpClient mcpClient)
|
|
{
|
|
_mcpClient = mcpClient;
|
|
}
|
|
|
|
public async Task<string> SearchCodexAsync(string query)
|
|
{
|
|
// List available tools from the codex-server
|
|
var tools = await _mcpClient.ListToolsAsync("codex-server");
|
|
|
|
// Call the search_codex tool
|
|
var result = await _mcpClient.CallToolAsync(
|
|
serverName: "codex-server",
|
|
toolName: "search_codex",
|
|
arguments: new Dictionary<string, object>
|
|
{
|
|
["query"] = query,
|
|
["maxResults"] = 10
|
|
}
|
|
);
|
|
|
|
return result.Content;
|
|
}
|
|
}
|
|
```
|
|
|
|
#### Step 5: Run and Test
|
|
|
|
```bash
|
|
# Ensure MCP servers are running
|
|
# Terminal 1: Start CODEX MCP Server
|
|
dotnet run --project /path/to/CodexMcpServer
|
|
# Server listens on http://localhost:5050
|
|
|
|
# Terminal 2: Run your client application
|
|
dotnet run
|
|
|
|
# The client will automatically connect to configured MCP servers via HTTP
|
|
# and be ready to call their tools
|
|
```
|
|
|
|
**Legacy Stdio Transport** (for local process-based tools):
|
|
```json
|
|
{
|
|
"Servers": [
|
|
{
|
|
"Name": "local-tool",
|
|
"Transport": {
|
|
"Type": "Stdio",
|
|
"Command": "dotnet",
|
|
"Args": ["run", "--project", "/path/to/tool", "--", "--stdio"]
|
|
},
|
|
"Enabled": true
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
Note: HTTP transport is recommended for production with remote servers, load balancing, and monitoring.
|
|
|
|
---
|
|
|
|
## Architecture
|
|
|
|
OpenHarbor.MCP.Client follows **Clean Architecture** principles:
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────┐
|
|
│ OpenHarbor.MCP.Client.Cli (Executable) │
|
|
│ ┌───────────────────────────────────────────┐ │
|
|
│ │ OpenHarbor.MCP.Client.AspNetCore (DI) │ │
|
|
│ │ ┌─────────────────────────────────────┐ │ │
|
|
│ │ │ OpenHarbor.MCP.Client.Infrastructure│ │ │
|
|
│ │ │ ┌───────────────────────────────┐ │ │ │
|
|
│ │ │ │ OpenHarbor.MCP.Client.Core │ │ │ │
|
|
│ │ │ │ - IMcpClient │ │ │ │
|
|
│ │ │ │ - IMcpServerConnection │ │ │ │
|
|
│ │ │ │ - IConnectionPool │ │ │ │
|
|
│ │ │ │ - Models (no dependencies) │ │ │ │
|
|
│ │ │ └───────────────────────────────┘ │ │ │
|
|
│ │ └─────────────────────────────────────┘ │ │
|
|
│ └───────────────────────────────────────────┘ │
|
|
└─────────────────────────────────────────────────┘
|
|
```
|
|
|
|
### Projects
|
|
|
|
| Project | Purpose | Dependencies |
|
|
|---------|---------|--------------|
|
|
| **OpenHarbor.MCP.Client.Core** | Abstractions, interfaces, models | None |
|
|
| **OpenHarbor.MCP.Client.Infrastructure** | MCP client implementation, transports, connection management | Core, System.Text.Json |
|
|
| **OpenHarbor.MCP.Client.AspNetCore** | ASP.NET Core integration, DI extensions | Core, Infrastructure, ASP.NET Core |
|
|
| **OpenHarbor.MCP.Client.Cli** | Standalone CLI executable | All above |
|
|
|
|
See [Architecture Documentation](docs/architecture.md) for detailed design.
|
|
|
|
---
|
|
|
|
## Examples
|
|
|
|
### 1. CodexMcpClient (Knowledge Search)
|
|
|
|
Sample client application that connects to CODEX MCP Server:
|
|
|
|
```
|
|
samples/CodexMcpClient/
|
|
├── Services/
|
|
│ ├── CodexSearchService.cs # Search documents
|
|
│ ├── DocumentService.cs # Retrieve documents
|
|
│ └── TagService.cs # List and filter tags
|
|
├── Program.cs
|
|
└── appsettings.json
|
|
```
|
|
|
|
**Running the sample**:
|
|
```bash
|
|
# Terminal 1: Start CODEX MCP Server
|
|
cd /path/to/OpenHarbor.MCP.Server/samples/CodexMcpServer
|
|
dotnet run
|
|
# Server listens on http://localhost:5050
|
|
|
|
# Terminal 2: Run client commands
|
|
cd /path/to/OpenHarbor.MCP.Client/samples/CodexMcpClient
|
|
dotnet run -- search "architecture patterns"
|
|
dotnet run -- get-document <id>
|
|
dotnet run -- list-tags
|
|
|
|
# Client connects to server via HTTP (configured in appsettings.json)
|
|
```
|
|
|
|
### 2. Multi-Server Client
|
|
|
|
Connect to multiple MCP servers simultaneously:
|
|
|
|
```csharp
|
|
public class MultiServerService
|
|
{
|
|
private readonly IMcpClient _mcpClient;
|
|
|
|
public async Task<CombinedResults> SearchAllServersAsync(string query)
|
|
{
|
|
// Get list of connected servers
|
|
var servers = await _mcpClient.GetConnectedServersAsync();
|
|
|
|
var results = new CombinedResults();
|
|
|
|
foreach (var server in servers)
|
|
{
|
|
// List tools available on this server
|
|
var tools = await _mcpClient.ListToolsAsync(server.Name);
|
|
|
|
// Find search tool (if exists)
|
|
var searchTool = tools.FirstOrDefault(t => t.Name.Contains("search"));
|
|
|
|
if (searchTool != null)
|
|
{
|
|
var result = await _mcpClient.CallToolAsync(
|
|
server.Name,
|
|
searchTool.Name,
|
|
new Dictionary<string, object> { ["query"] = query }
|
|
);
|
|
|
|
results.Add(server.Name, result);
|
|
}
|
|
}
|
|
|
|
return results;
|
|
}
|
|
}
|
|
```
|
|
|
|
### 3. Error Handling and Retry
|
|
|
|
```csharp
|
|
public class ResilientMcpService
|
|
{
|
|
private readonly IMcpClient _mcpClient;
|
|
private readonly ILogger<ResilientMcpService> _logger;
|
|
|
|
public async Task<McpToolResult> CallWithRetryAsync(
|
|
string serverName,
|
|
string toolName,
|
|
Dictionary<string, object> arguments,
|
|
int maxRetries = 3)
|
|
{
|
|
for (int attempt = 0; attempt < maxRetries; attempt++)
|
|
{
|
|
try
|
|
{
|
|
return await _mcpClient.CallToolAsync(serverName, toolName, arguments);
|
|
}
|
|
catch (McpConnectionException ex) when (attempt < maxRetries - 1)
|
|
{
|
|
_logger.LogWarning(
|
|
"MCP call failed (attempt {Attempt}/{MaxRetries}): {Error}",
|
|
attempt + 1, maxRetries, ex.Message
|
|
);
|
|
|
|
await Task.Delay(TimeSpan.FromSeconds(Math.Pow(2, attempt)));
|
|
}
|
|
}
|
|
|
|
throw new Exception($"Failed after {maxRetries} attempts");
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Connection Management
|
|
|
|
### Connection Pooling
|
|
|
|
OpenHarbor.MCP.Client includes connection pooling for efficient resource usage:
|
|
|
|
```json
|
|
{
|
|
"Mcp": {
|
|
"Connection": {
|
|
"EnableConnectionPooling": true,
|
|
"MaxConnectionsPerServer": 5,
|
|
"ConnectionIdleTimeout": "00:05:00",
|
|
"PoolEvictionInterval": "00:01:00"
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
### Timeout Configuration
|
|
|
|
Configure timeouts per server:
|
|
|
|
```json
|
|
{
|
|
"Servers": [
|
|
{
|
|
"Name": "fast-server",
|
|
"Timeout": "00:00:10"
|
|
},
|
|
{
|
|
"Name": "slow-batch-server",
|
|
"Timeout": "00:05:00"
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
### Health Checks
|
|
|
|
Monitor server connections:
|
|
|
|
```csharp
|
|
public class ServerHealthService
|
|
{
|
|
private readonly IMcpClient _mcpClient;
|
|
|
|
public async Task<Dictionary<string, bool>> CheckServerHealthAsync()
|
|
{
|
|
var servers = await _mcpClient.GetConnectedServersAsync();
|
|
var health = new Dictionary<string, bool>();
|
|
|
|
foreach (var server in servers)
|
|
{
|
|
try
|
|
{
|
|
await _mcpClient.PingAsync(server.Name);
|
|
health[server.Name] = true;
|
|
}
|
|
catch
|
|
{
|
|
health[server.Name] = false;
|
|
}
|
|
}
|
|
|
|
return health;
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Testing
|
|
|
|
### Integration Tests
|
|
|
|
```bash
|
|
# Run all tests
|
|
dotnet test
|
|
|
|
# Run specific test project
|
|
dotnet test tests/OpenHarbor.MCP.Client.Tests/
|
|
|
|
# Run with coverage
|
|
dotnet test /p:CollectCoverage=true
|
|
```
|
|
|
|
### Mock MCP Server
|
|
|
|
The library includes a mock server for testing:
|
|
|
|
```csharp
|
|
[Fact]
|
|
public async Task Client_CanCallMockServerTool()
|
|
{
|
|
// Arrange
|
|
var mockServer = new MockMcpServer()
|
|
.WithTool("test_tool", async (args) =>
|
|
McpToolResult.Success($"Received: {args["input"]}"));
|
|
|
|
var client = new McpClient();
|
|
await client.ConnectToServerAsync(mockServer);
|
|
|
|
// Act
|
|
var result = await client.CallToolAsync(
|
|
"mock-server",
|
|
"test_tool",
|
|
new Dictionary<string, object> { ["input"] = "test" }
|
|
);
|
|
|
|
// Assert
|
|
Assert.True(result.IsSuccess);
|
|
Assert.Equal("Received: test", result.Content);
|
|
}
|
|
```
|
|
|
|
### Test Coverage
|
|
|
|
OpenHarbor.MCP.Client maintains **88.52% line coverage** and **75.58% branch coverage** with **60 tests** passing (100%).
|
|
|
|
**Coverage Breakdown:**
|
|
- **Lines**: 88.52% (excellent)
|
|
- **Branches**: 75.58% (excellent)
|
|
- **Test Projects**: 1
|
|
- OpenHarbor.MCP.Client.Core.Tests: 60 tests
|
|
- HTTP client connection tests: 20 tests
|
|
- Configuration validation tests
|
|
- Error handling and retry logic
|
|
|
|
**Analysis:**
|
|
- **Excellent coverage** - exceeds 85% industry threshold
|
|
- All critical paths tested
|
|
- Error handling well-covered
|
|
- Configuration scenarios comprehensive
|
|
|
|
**Coverage Reports:**
|
|
```bash
|
|
# Generate coverage report
|
|
dotnet test --collect:"XPlat Code Coverage" --results-directory ./TestResults
|
|
|
|
# View detailed coverage
|
|
# See: /home/svrnty/codex/COVERAGE-SUMMARY.md for complete analysis
|
|
```
|
|
|
|
**Status**: ✅ Excellent - Production-ready coverage meets all industry standards
|
|
|
|
---
|
|
|
|
## Documentation
|
|
|
|
| Document | Description |
|
|
|----------|-------------|
|
|
| [**API Reference**](docs/api/) | **Complete API documentation (IMcpClient, Models, Configuration)** |
|
|
| [Module Design](docs/module-design.md) | Architecture and design decisions |
|
|
| [Implementation Plan](docs/implementation-plan.md) | Development roadmap |
|
|
| [AGENT-PRIMER.md](AGENT-PRIMER.md) | AI-assisted setup guide |
|
|
| [HTTPS Setup Guide](docs/deployment/https-setup.md) | Production TLS/HTTPS configuration |
|
|
|
|
---
|
|
|
|
## Related Modules
|
|
|
|
OpenHarbor.MCP is a family of three complementary modules:
|
|
|
|
- **[OpenHarbor.MCP.Server](../OpenHarbor.MCP.Server/)** - Server library (expose tools TO AI agents)
|
|
- **[OpenHarbor.MCP.Client](../OpenHarbor.MCP.Client/)** - Client library (call tools FROM servers) ← You are here
|
|
- **[OpenHarbor.MCP.Gateway](../OpenHarbor.MCP.Gateway/)** - Gateway/proxy (route between clients and servers)
|
|
|
|
All three modules share:
|
|
- Same Clean Architecture pattern
|
|
- Same documentation structure
|
|
- Same security principles
|
|
- Compatible .NET 8 SDKs
|
|
|
|
---
|
|
|
|
## Contributing
|
|
|
|
We welcome contributions! See [CONTRIBUTING.md](CONTRIBUTING.md) for:
|
|
- Development setup
|
|
- Code standards
|
|
- Testing requirements
|
|
- Pull request process
|
|
|
|
---
|
|
|
|
## License
|
|
|
|
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
|
|
---
|
|
|
|
## Support
|
|
|
|
- **Issues**: [GitHub Issues](https://github.com/svrnty/openharbor-mcp/issues)
|
|
- **Email**: info@svrnty.io
|
|
- **Documentation**: [docs/](docs/)
|
|
|
|
---
|
|
|
|
**Built with love by Svrnty**
|
|
|
|
Creating sovereign tools to democratize technology for humanity.
|