| docs | ||
| samples/CodexMcpClient | ||
| src | ||
| tests/Svrnty.MCP.Client.Core.Tests | ||
| .gitignore | ||
| AGENT-PRIMER.md | ||
| LICENSE | ||
| README.md | ||
| Svrnty.MCP.Client.sln | ||
Svrnty.MCP.Client
A modular, scalable, secure .NET library for consuming Model Context Protocol (MCP) servers
What is Svrnty.MCP.Client?
Svrnty.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 Svrnty.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: Svrnty.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:
- Copy this entire folder to your project directory
- Open your AI assistant and say: "Read AGENT-PRIMER.md and set up Svrnty.MCP.Client for my project"
- 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/Svrnty.MCP.Client/src/Svrnty.MCP.Client.AspNetCore/Svrnty.MCP.Client.AspNetCore.csproj
# OR via NuGet (when published)
# dotnet add package Svrnty.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 Svrnty.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 Svrnty.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
Svrnty.MCP.Client follows Clean Architecture principles:
┌─────────────────────────────────────────────────┐
│ Svrnty.MCP.Client.Cli (Executable) │
│ ┌───────────────────────────────────────────┐ │
│ │ Svrnty.MCP.Client.AspNetCore (DI) │ │
│ │ ┌─────────────────────────────────────┐ │ │
│ │ │ Svrnty.MCP.Client.Infrastructure│ │ │
│ │ │ ┌───────────────────────────────┐ │ │ │
│ │ │ │ Svrnty.MCP.Client.Core │ │ │ │
│ │ │ │ - IMcpClient │ │ │ │
│ │ │ │ - IMcpServerConnection │ │ │ │
│ │ │ │ - IConnectionPool │ │ │ │
│ │ │ │ - Models (no dependencies) │ │ │ │
│ │ │ └───────────────────────────────┘ │ │ │
│ │ └─────────────────────────────────────┘ │ │
│ └───────────────────────────────────────────┘ │
└─────────────────────────────────────────────────┘
Projects
| Project | Purpose | Dependencies |
|---|---|---|
| Svrnty.MCP.Client.Core | Abstractions, interfaces, models | None |
| Svrnty.MCP.Client.Infrastructure | MCP client implementation, transports, connection management | Core, System.Text.Json |
| Svrnty.MCP.Client.AspNetCore | ASP.NET Core integration, DI extensions | Core, Infrastructure, ASP.NET Core |
| Svrnty.MCP.Client.Cli | Standalone CLI executable | All above |
See Architecture Documentation 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:
# Terminal 1: Start CODEX MCP Server
cd /path/to/Svrnty.MCP.Server/samples/CodexMcpServer
dotnet run
# Server listens on http://localhost:5050
# Terminal 2: Run client commands
cd /path/to/Svrnty.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
Svrnty.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/Svrnty.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
Svrnty.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
- Svrnty.MCP.Client.Core.Tests: 60 tests
- HTTP client connection tests: 20 tests
- Configuration validation tests
- Error handling and retry logic
- Svrnty.MCP.Client.Core.Tests: 60 tests
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 |
Related Modules
Svrnty.MCP is a family of three complementary modules:
- Svrnty.MCP.Server - Server library (expose tools TO AI agents)
- Svrnty.MCP.Client - Client library (call tools FROM servers) ← You are here
- Svrnty.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 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
- Issues: GitHub Issues
- Email: info@svrnty.io
- Documentation: docs/
Built with love by Svrnty
Creating sovereign tools to democratize technology for humanity.