svrnty-mcp-client/docs/api/README.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

736 lines
15 KiB
Markdown

# OpenHarbor.MCP.Client - API Reference
**Version:** 1.0.0
**Last Updated:** 2025-10-19
**Status:** Production-Ready
---
## Table of Contents
- [Core Abstractions](#core-abstractions)
- [IMcpClient](#imcpclient)
- [IMcpServerConnection](#imcpserverconnection)
- [Infrastructure](#infrastructure)
- [McpClient](#mcpclient)
- [HttpServerConnection](#httpserverconnection)
- [Models](#models)
- [ServerConnectionConfig](#serverconnectionconfig)
- [McpToolInfo](#mcptoolinfo)
- [McpToolResult](#mcptoolresult)
- [ASP.NET Core Integration](#aspnet-core-integration)
- [Service Extensions](#service-extensions)
- [Configuration](#configuration)
---
## Core Abstractions
### IMcpClient
**Namespace:** `OpenHarbor.MCP.Client.Core.Abstractions`
Interface defining the MCP client contract for consuming MCP servers.
#### Methods
##### ConnectToServerAsync
```csharp
Task ConnectToServerAsync(
string serverName,
ServerConnectionConfig config,
CancellationToken cancellationToken = default)
```
Establishes a connection to an MCP server.
**Parameters:**
- `serverName` (string): Unique identifier for this server
- `config` (ServerConnectionConfig): Connection configuration
- `cancellationToken` (CancellationToken): Optional cancellation token
**Throws:**
- `ConnectionException` - If connection fails
- `ArgumentException` - If server name already exists
**Example:**
```csharp
await client.ConnectToServerAsync(
"codex-server",
new ServerConnectionConfig
{
Transport = TransportType.Http,
BaseUrl = "http://localhost:5050",
Timeout = TimeSpan.FromSeconds(30)
}
);
```
##### ListToolsAsync
```csharp
Task<IEnumerable<McpToolInfo>> ListToolsAsync(
string serverName,
CancellationToken cancellationToken = default)
```
Lists all tools available on a connected server.
**Parameters:**
- `serverName` (string): Name of the server to query
- `cancellationToken` (CancellationToken): Optional cancellation token
**Returns:** `Task<IEnumerable<McpToolInfo>>` - Collection of available tools
**Throws:**
- `ServerNotFoundException` - If server not connected
- `ConnectionException` - If connection lost
**Example:**
```csharp
var tools = await client.ListToolsAsync("codex-server");
foreach (var tool in tools)
{
Console.WriteLine($"{tool.Name}: {tool.Description}");
}
```
##### CallToolAsync
```csharp
Task<McpToolResult> CallToolAsync(
string serverName,
string toolName,
Dictionary<string, object> arguments,
CancellationToken cancellationToken = default)
```
Calls a tool on a connected server.
**Parameters:**
- `serverName` (string): Name of the server hosting the tool
- `toolName` (string): Name of the tool to execute
- `arguments` (Dictionary<string, object>): Tool input parameters
- `cancellationToken` (CancellationToken): Optional cancellation token
**Returns:** `Task<McpToolResult>` - The result of the tool execution
**Throws:**
- `ServerNotFoundException` - If server not connected
- `ToolNotFoundException` - If tool doesn't exist
- `InvalidArgumentsException` - If arguments don't match schema
- `ConnectionException` - If connection lost
**Example:**
```csharp
var result = await client.CallToolAsync(
serverName: "codex-server",
toolName: "search_documents",
arguments: new Dictionary<string, object>
{
["query"] = "architecture patterns",
["maxResults"] = 10
}
);
if (result.IsSuccess)
{
Console.WriteLine(result.Content);
}
```
##### GetConnectedServersAsync
```csharp
Task<IEnumerable<ServerInfo>> GetConnectedServersAsync(
CancellationToken cancellationToken = default)
```
Gets a list of all connected servers.
**Returns:** `Task<IEnumerable<ServerInfo>>` - Connected servers with status
**Example:**
```csharp
var servers = await client.GetConnectedServersAsync();
foreach (var server in servers)
{
Console.WriteLine($"{server.Name}: {(server.IsHealthy ? "Healthy" : "Unhealthy")}");
}
```
##### DisconnectFromServerAsync
```csharp
Task DisconnectFromServerAsync(
string serverName,
CancellationToken cancellationToken = default)
```
Disconnects from a specific server.
**Parameters:**
- `serverName` (string): Name of the server to disconnect from
- `cancellationToken` (CancellationToken): Optional cancellation token
**Example:**
```csharp
await client.DisconnectFromServerAsync("codex-server");
```
---
### IMcpServerConnection
**Namespace:** `OpenHarbor.MCP.Client.Core.Abstractions`
Interface representing a connection to a single MCP server.
#### Properties
##### ServerName
```csharp
string ServerName { get; }
```
Unique identifier for this server connection.
##### IsConnected
```csharp
bool IsConnected { get; }
```
Indicates whether the connection is active.
##### Config
```csharp
ServerConnectionConfig Config { get; }
```
Configuration used for this connection.
#### Methods
##### SendRequestAsync
```csharp
Task<JsonRpcResponse> SendRequestAsync(
JsonRpcRequest request,
CancellationToken cancellationToken = default)
```
Sends a JSON-RPC request to the server.
**Parameters:**
- `request` (JsonRpcRequest): The request to send
- `cancellationToken` (CancellationToken): Cancellation support
**Returns:** `Task<JsonRpcResponse>` - The server response
**Example:**
```csharp
var request = new JsonRpcRequest
{
JsonRpc = "2.0",
Id = "1",
Method = "tools/list"
};
var response = await connection.SendRequestAsync(request);
```
---
## Infrastructure
### McpClient
**Namespace:** `OpenHarbor.MCP.Client.Infrastructure`
Default implementation of `IMcpClient`.
#### Constructor
```csharp
public McpClient(ILogger<McpClient> logger = null)
```
**Parameters:**
- `logger` (ILogger<McpClient>): Optional logger instance
**Example:**
```csharp
var client = new McpClient();
// With logging
var loggerFactory = LoggerFactory.Create(builder =>
{
builder.AddConsole();
});
var logger = loggerFactory.CreateLogger<McpClient>();
var clientWithLogging = new McpClient(logger);
```
#### Configuration
**Connection Pooling:**
```csharp
var client = new McpClient();
client.EnableConnectionPooling = true;
client.MaxConnectionsPerServer = 5;
client.ConnectionIdleTimeout = TimeSpan.FromMinutes(5);
```
**Retry Policy:**
```csharp
client.MaxRetries = 3;
client.RetryDelay = TimeSpan.FromSeconds(1);
client.RetryBackoff = RetryBackoffStrategy.Exponential;
```
---
### HttpServerConnection
**Namespace:** `OpenHarbor.MCP.Client.Infrastructure.Transports`
HTTP-based implementation of `IMcpServerConnection`.
#### Constructor
```csharp
public HttpServerConnection(
string serverName,
HttpServerConnectionConfig config,
HttpClient httpClient = null)
```
**Parameters:**
- `serverName` (string): Server identifier
- `config` (HttpServerConnectionConfig): HTTP-specific configuration
- `httpClient` (HttpClient): Optional HttpClient (for DI)
**Example:**
```csharp
var config = new HttpServerConnectionConfig
{
ServerUrl = "http://localhost:5050",
Timeout = TimeSpan.FromSeconds(30),
ApiKey = Environment.GetEnvironmentVariable("MCP_API_KEY")
};
var connection = new HttpServerConnection("codex-server", config);
await connection.ConnectAsync();
```
#### Configuration Options
```csharp
public class HttpServerConnectionConfig : ServerConnectionConfig
{
public string ServerUrl { get; set; }
public string ApiKey { get; set; }
public Dictionary<string, string> Headers { get; set; }
public TimeSpan Timeout { get; set; }
public bool ValidateSslCertificate { get; set; }
}
```
---
## Models
### ServerConnectionConfig
**Namespace:** `OpenHarbor.MCP.Client.Core.Models`
Base configuration for server connections.
#### Properties
```csharp
public class ServerConnectionConfig
{
public TransportType Transport { get; set; }
public TimeSpan Timeout { get; set; }
public bool Enabled { get; set; }
}
public enum TransportType
{
Http,
Stdio
}
```
#### Example
```csharp
var config = new ServerConnectionConfig
{
Transport = TransportType.Http,
Timeout = TimeSpan.FromSeconds(30),
Enabled = true
};
```
---
### McpToolInfo
**Namespace:** `OpenHarbor.MCP.Client.Core.Models`
Metadata about an available tool.
#### Properties
```csharp
public class McpToolInfo
{
public string Name { get; set; }
public string Description { get; set; }
public McpToolSchema InputSchema { get; set; }
}
```
#### Example
```csharp
var toolInfo = new McpToolInfo
{
Name = "search_documents",
Description = "Search documents by query",
InputSchema = new McpToolSchema { ... }
};
```
---
### McpToolResult
**Namespace:** `OpenHarbor.MCP.Client.Core.Models`
Result of a tool execution.
#### Properties
```csharp
public class McpToolResult
{
public bool IsSuccess { get; set; }
public string Content { get; set; }
public string ErrorMessage { get; set; }
public int? ErrorCode { get; set; }
}
```
#### Usage
```csharp
var result = await client.CallToolAsync(...);
if (result.IsSuccess)
{
Console.WriteLine($"Success: {result.Content}");
}
else
{
Console.WriteLine($"Error {result.ErrorCode}: {result.ErrorMessage}");
}
```
---
## ASP.NET Core Integration
### Service Extensions
**Namespace:** `OpenHarbor.MCP.Client.AspNetCore`
#### AddMcpClient
```csharp
public static IServiceCollection AddMcpClient(
this IServiceCollection services,
IConfiguration configuration)
```
Registers MCP client and dependencies from configuration.
**Configuration Format:**
```json
{
"Mcp": {
"Client": {
"Name": "MyAppClient",
"Version": "1.0.0"
},
"Servers": [
{
"Name": "codex-server",
"Transport": {
"Type": "Http",
"BaseUrl": "http://localhost:5050"
},
"Timeout": "00:00:30",
"Enabled": true
}
]
}
}
```
**Example:**
```csharp
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddMcpClient(
builder.Configuration.GetSection("Mcp")
);
var app = builder.Build();
```
#### Dependency Injection
```csharp
public class MyService
{
private readonly IMcpClient _mcpClient;
public MyService(IMcpClient mcpClient)
{
_mcpClient = mcpClient;
}
public async Task<string> SearchAsync(string query)
{
var result = await _mcpClient.CallToolAsync(
"codex-server",
"search_documents",
new Dictionary<string, object> { ["query"] = query }
);
return result.Content;
}
}
```
---
## Configuration
### appsettings.json Structure
```json
{
"Mcp": {
"Client": {
"Name": "MyApplication",
"Version": "1.0.0",
"Description": "My MCP client application"
},
"Servers": [
{
"Name": "codex-server",
"Transport": {
"Type": "Http",
"BaseUrl": "http://localhost:5050"
},
"Timeout": "00:00:30",
"Enabled": true
}
],
"Connection": {
"MaxRetries": 3,
"RetryDelayMs": 1000,
"EnableConnectionPooling": true,
"MaxConnectionsPerServer": 5,
"ConnectionIdleTimeout": "00:05:00"
}
}
}
```
### Environment Variables
Override configuration with environment variables:
```bash
export MCP__SERVERS__0__TRANSPORT__BASEURL="https://production.example.com"
export MCP__CONNECTION__MAXRETRIES="5"
```
---
## Error Handling
### Exception Hierarchy
```
McpException (base)
├── ConnectionException
│ ├── ServerNotFoundException
│ ├── ConnectionTimeoutException
│ └── ServerUnavailableException
├── ToolException
│ ├── ToolNotFoundException
│ └── InvalidArgumentsException
└── TransportException
├── HttpTransportException
└── StdioTransportException
```
### Example Error Handling
```csharp
try
{
var result = await client.CallToolAsync(...);
}
catch (ServerNotFoundException ex)
{
_logger.LogError($"Server not found: {ex.ServerName}");
}
catch (ToolNotFoundException ex)
{
_logger.LogError($"Tool not found: {ex.ToolName}");
}
catch (ConnectionTimeoutException ex)
{
_logger.LogWarning($"Timeout connecting to {ex.ServerName}");
// Retry logic
}
catch (McpException ex)
{
_logger.LogError($"MCP error: {ex.Message}");
}
```
---
## Complete Example
### Console Application
```csharp
using OpenHarbor.MCP.Client.Core;
using OpenHarbor.MCP.Client.Infrastructure;
class Program
{
static async Task Main(string[] args)
{
// 1. Create client
var client = new McpClient();
// 2. Connect to server
await client.ConnectToServerAsync(
"codex-server",
new ServerConnectionConfig
{
Transport = TransportType.Http,
BaseUrl = "http://localhost:5050",
Timeout = TimeSpan.FromSeconds(30)
}
);
// 3. List available tools
var tools = await client.ListToolsAsync("codex-server");
Console.WriteLine($"Found {tools.Count()} tools:");
foreach (var tool in tools)
{
Console.WriteLine($" - {tool.Name}: {tool.Description}");
}
// 4. Call a tool
var result = await client.CallToolAsync(
serverName: "codex-server",
toolName: "search_documents",
arguments: new Dictionary<string, object>
{
["query"] = "architecture",
["maxResults"] = 5
}
);
// 5. Handle result
if (result.IsSuccess)
{
Console.WriteLine($"Results: {result.Content}");
}
else
{
Console.WriteLine($"Error: {result.ErrorMessage}");
}
// 6. Disconnect
await client.DisconnectFromServerAsync("codex-server");
}
}
```
### ASP.NET Core Web API
```csharp
[ApiController]
[Route("api/[controller]")]
public class SearchController : ControllerBase
{
private readonly IMcpClient _mcpClient;
public SearchController(IMcpClient mcpClient)
{
_mcpClient = mcpClient;
}
[HttpGet]
public async Task<IActionResult> Search([FromQuery] string query)
{
try
{
var result = await _mcpClient.CallToolAsync(
"codex-server",
"search_documents",
new Dictionary<string, object> { ["query"] = query }
);
if (result.IsSuccess)
{
return Ok(result.Content);
}
return StatusCode(500, result.ErrorMessage);
}
catch (ServerNotFoundException ex)
{
return NotFound($"Server not found: {ex.ServerName}");
}
catch (Exception ex)
{
return StatusCode(500, ex.Message);
}
}
}
```
---
## See Also
- [Client Architecture](../architecture.md)
- [Module Design](../module-design.md)
- [Implementation Plan](../implementation-plan.md)
- [AGENT-PRIMER.md](../../AGENT-PRIMER.md)
---
**Document Type:** API Reference
**Version:** 1.0.0
**Last Updated:** 2025-10-19
**Maintained By:** Svrnty Development Team