# OpenHarbor.MCP.Client **A modular, scalable, secure .NET library for consuming Model Context Protocol (MCP) servers** [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE) [![.NET 8.0](https://img.shields.io/badge/.NET-8.0-512BD4)](https://dotnet.microsoft.com/download/dotnet/8.0) [![Architecture: Clean](https://img.shields.io/badge/Architecture-Clean-green)](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 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 { ["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 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 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 { ["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 _logger; public async Task CallWithRetryAsync( string serverName, string toolName, Dictionary 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> CheckServerHealthAsync() { var servers = await _mcpClient.GetConnectedServersAsync(); var health = new Dictionary(); 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 { ["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.