.NET client for connecting to Model Context Protocol (MCP) servers
Go to file
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
docs docs: comprehensive AI coding assistant research and MCP-first implementation plan 2025-10-22 21:00:34 -04:00
samples/CodexMcpClient docs: comprehensive AI coding assistant research and MCP-first implementation plan 2025-10-22 21:00:34 -04:00
src docs: comprehensive AI coding assistant research and MCP-first implementation plan 2025-10-22 21:00:34 -04:00
tests/Svrnty.MCP.Client.Core.Tests docs: comprehensive AI coding assistant research and MCP-first implementation plan 2025-10-22 21:00:34 -04:00
.gitignore docs: comprehensive AI coding assistant research and MCP-first implementation plan 2025-10-22 21:00:34 -04:00
AGENT-PRIMER.md docs: comprehensive AI coding assistant research and MCP-first implementation plan 2025-10-22 21:00:34 -04:00
LICENSE docs: comprehensive AI coding assistant research and MCP-first implementation plan 2025-10-22 21:00:34 -04:00
README.md docs: comprehensive AI coding assistant research and MCP-first implementation plan 2025-10-22 21:00:34 -04:00
Svrnty.MCP.Client.sln docs: comprehensive AI coding assistant research and MCP-first implementation plan 2025-10-22 21:00:34 -04:00

OpenHarbor.MCP.Client

A modular, scalable, secure .NET library for consuming Model Context Protocol (MCP) servers

License: MIT .NET 8.0 Architecture: Clean


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)

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

# 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:

{
  "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

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

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

# 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):

{
  "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 for detailed design.


Examples

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:

# 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:

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

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:

{
  "Mcp": {
    "Connection": {
      "EnableConnectionPooling": true,
      "MaxConnectionsPerServer": 5,
      "ConnectionIdleTimeout": "00:05:00",
      "PoolEvictionInterval": "00:01:00"
    }
  }
}

Timeout Configuration

Configure timeouts per server:

{
  "Servers": [
    {
      "Name": "fast-server",
      "Timeout": "00:00:10"
    },
    {
      "Name": "slow-batch-server",
      "Timeout": "00:05:00"
    }
  ]
}

Health Checks

Monitor server connections:

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

# 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:

[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:

# 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 Complete API documentation (IMcpClient, Models, Configuration)
Module Design Architecture and design decisions
Implementation Plan Development roadmap
AGENT-PRIMER.md AI-assisted setup guide
HTTPS Setup Guide Production TLS/HTTPS configuration

OpenHarbor.MCP is a family of three complementary modules:

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 for:

  • Development setup
  • Code standards
  • Testing requirements
  • Pull request process

License

This project is licensed under the MIT License - see the LICENSE file for details.


Support


Built with love by Svrnty

Creating sovereign tools to democratize technology for humanity.