# AGENT-PRIMER: OpenHarbor.MCP.Client Automated Setup **Purpose**: This document guides AI agents to automatically analyze a target system and configure OpenHarbor.MCP.Client integration with minimal human intervention. **Target Audience**: AI assistants (Claude, ChatGPT, etc.) helping developers integrate MCP client capabilities into .NET applications. --- ## Overview OpenHarbor.MCP.Client is a **standalone, reusable .NET library** that adds Model Context Protocol (MCP) client capabilities to any .NET application, allowing it to discover and call tools exposed by remote MCP servers. This primer enables AI-automated configuration by walking through system analysis, configuration generation, and validation. **What you'll automate:** 1. System analysis (detect .NET version, project type, dependencies) 2. Configuration file generation (appsettings.json, client-config.json, Program.cs) 3. Sample MCP client usage code based on detected features 4. Environment setup and validation --- ## Step 1: System Analysis **Goal**: Understand the target system to generate appropriate configuration. ### Tasks for AI Agent: #### 1.1 Detect .NET Environment ```bash # Check .NET SDK version dotnet --version # List installed SDKs dotnet --list-sdks # List installed runtimes dotnet --list-runtimes ``` **Required**: .NET 8.0 SDK or higher **Action if missing**: Provide installation instructions for user's OS #### 1.2 Analyze Project Structure ```bash # Find .csproj files find . -name "*.csproj" -type f # Examine project type grep -E "" *.csproj ``` **Detect**: - Project type (Web API, Console, Worker Service, etc.) - Target framework (net8.0, net9.0) - Existing dependencies #### 1.3 Identify Integration Points ```bash # Check for existing HTTP clients grep -r "HttpClient\|IHttpClientFactory" --include="*.cs" # Check for dependency injection setup grep -r "AddScoped\|AddSingleton\|AddTransient" --include="*.cs" # Check for background services grep -r "IHostedService\|BackgroundService" --include="*.cs" ``` **Output**: JSON summary of detected features ```json { "dotnetVersion": "8.0.100", "projectType": "AspNetCore.WebApi", "targetFramework": "net8.0", "features": { "hasHttpClient": true, "hasBackgroundWorkers": true, "hasAuthentication": true, "hasLogging": true, "hasDependencyInjection": true }, "dependencies": [ "Microsoft.Extensions.Http", "Microsoft.Extensions.Logging", "Microsoft.Extensions.DependencyInjection" ] } ``` --- ## Step 2: Generate Configuration **Goal**: Create configuration files tailored to the detected system. ### 2.1 NuGet Package References **Add to project's .csproj**: ```xml ``` **Note**: When OpenHarbor.MCP.Client is published to NuGet, replace with: ```xml ``` ### 2.2 appsettings.json Configuration **Generate based on detected project**: ```json { "Mcp": { "Client": { "Name": "MyAppMcpClient", "Version": "1.0.0", "Description": "MCP client for MyApp - connects to remote MCP servers" }, "Servers": [ { "Name": "local-codex-server", "Description": "CODEX knowledge base MCP server", "Transport": { "Type": "Http", "Command": "dotnet", "Args": ["run", "--project", "/path/to/CodexMcpServer/CodexMcpServer.csproj"] }, "Timeout": "00:00:30", "Enabled": true }, { "Name": "remote-api-server", "Description": "Remote HTTP-based MCP server", "Transport": { "Type": "Http", "BaseUrl": "https://api.example.com/mcp", "Headers": { "Authorization": "Bearer ${MCP_API_KEY}" } }, "Timeout": "00:01:00", "Enabled": false } ], "Connection": { "MaxRetries": 3, "RetryDelayMs": 1000, "RetryBackoffMultiplier": 2.0, "EnableConnectionPooling": true, "MaxConnectionsPerServer": 5, "ConnectionIdleTimeout": "00:05:00", "PoolEvictionInterval": "00:01:00" }, "Logging": { "LogToolCalls": true, "LogConnectionEvents": true, "LogLevel": "Information" } } } ``` **Configuration explanation**: - `Client.Name`: Identifier for this MCP client - `Servers`: List of MCP servers to connect to - `Transport.Type`: "Stdio" (process) or "Http" (API) - `Timeout`: How long to wait for responses - `Enabled`: Whether to auto-connect on startup - `Connection.MaxRetries`: Retry failed calls automatically - `Connection.EnableConnectionPooling`: Reuse connections for efficiency ### 2.3 Program.cs Integration **For ASP.NET Core projects**: ```csharp using OpenHarbor.MCP.Client.AspNetCore; var builder = WebApplication.CreateBuilder(args); // Add MCP Client builder.Services.AddMcpClient(builder.Configuration.GetSection("Mcp")); // Register services that use MCP client builder.Services.AddScoped(); var app = builder.Build(); // Optional: Connect to all enabled servers on startup var mcpClient = app.Services.GetRequiredService(); await mcpClient.ConnectToEnabledServersAsync(); app.Run(); ``` **For Console applications**: ```csharp using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Configuration; using OpenHarbor.MCP.Client.Infrastructure; var config = new ConfigurationBuilder() .AddJsonFile("appsettings.json") .Build(); var services = new ServiceCollection(); // Add MCP Client services.AddMcpClient(config.GetSection("Mcp")); var provider = services.BuildServiceProvider(); // Use MCP Client var mcpClient = provider.GetRequiredService(); await mcpClient.ConnectToServerAsync("local-codex-server"); var tools = await mcpClient.ListToolsAsync("local-codex-server"); Console.WriteLine($"Available tools: {string.Join(", ", tools.Select(t => t.Name))}"); ``` --- ## Step 3: Generate Sample Client Usage **Goal**: Create service classes that demonstrate MCP client usage based on detected project features. ### 3.1 Basic Search Service **If project has search/query capabilities**: ```csharp using OpenHarbor.MCP.Client.Core.Abstractions; using OpenHarbor.MCP.Client.Core.Models; namespace MyApp.Services; public interface ICodexSearchService { Task> SearchAsync(string query, int maxResults = 10); } public class CodexSearchService : ICodexSearchService { private readonly IMcpClient _mcpClient; private readonly ILogger _logger; private const string ServerName = "local-codex-server"; public CodexSearchService( IMcpClient mcpClient, ILogger logger) { _mcpClient = mcpClient; _logger = logger; } public async Task> SearchAsync( string query, int maxResults = 10) { try { var result = await _mcpClient.CallToolAsync( serverName: ServerName, toolName: "search_codex", arguments: new Dictionary { ["query"] = query, ["maxResults"] = maxResults } ); if (!result.IsSuccess) { _logger.LogWarning( "MCP tool call failed: {Error}", result.ErrorMessage ); return Enumerable.Empty(); } return ParseSearchResults(result.Content); } catch (McpConnectionException ex) { _logger.LogError(ex, "Failed to connect to MCP server"); return Enumerable.Empty(); } } private IEnumerable ParseSearchResults(string jsonContent) { // Parse JSON response and convert to SearchResult models return JsonSerializer.Deserialize>(jsonContent) ?? Enumerable.Empty(); } } ``` ### 3.2 Document Retrieval Service **If project works with documents**: ```csharp using OpenHarbor.MCP.Client.Core.Abstractions; namespace MyApp.Services; public interface IDocumentService { Task GetDocumentAsync(string documentId); Task> ListDocumentsAsync(int skip = 0, int take = 20); } public class DocumentService : IDocumentService { private readonly IMcpClient _mcpClient; private const string ServerName = "local-codex-server"; public DocumentService(IMcpClient mcpClient) { _mcpClient = mcpClient; } public async Task GetDocumentAsync(string documentId) { var result = await _mcpClient.CallToolAsync( ServerName, "get_document", new Dictionary { ["documentId"] = documentId } ); if (!result.IsSuccess) return null; return JsonSerializer.Deserialize(result.Content); } public async Task> ListDocumentsAsync( int skip = 0, int take = 20) { var result = await _mcpClient.CallToolAsync( ServerName, "list_documents", new Dictionary { ["skip"] = skip, ["take"] = take } ); if (!result.IsSuccess) return Enumerable.Empty(); return JsonSerializer.Deserialize>(result.Content) ?? Enumerable.Empty(); } } ``` ### 3.3 Multi-Server Aggregation Service **For advanced scenarios (multiple MCP servers)**: ```csharp using OpenHarbor.MCP.Client.Core.Abstractions; namespace MyApp.Services; public interface IAggregationService { Task SearchAllServersAsync(string query); } public class AggregationService : IAggregationService { private readonly IMcpClient _mcpClient; private readonly ILogger _logger; public AggregationService( IMcpClient mcpClient, ILogger logger) { _mcpClient = mcpClient; _logger = logger; } public async Task SearchAllServersAsync(string query) { var servers = await _mcpClient.GetConnectedServersAsync(); var results = new AggregatedResults(); var tasks = servers.Select(server => SearchServerAsync(server.Name, query) ); var serverResults = await Task.WhenAll(tasks); foreach (var (serverName, items) in serverResults) { if (items.Any()) { results.Add(serverName, items); } } return results; } private async Task<(string ServerName, IEnumerable Results)> SearchServerAsync(string serverName, string query) { try { var tools = await _mcpClient.ListToolsAsync(serverName); var searchTool = tools.FirstOrDefault(t => t.Name.Contains("search", StringComparison.OrdinalIgnoreCase)); if (searchTool == null) return (serverName, Enumerable.Empty()); var result = await _mcpClient.CallToolAsync( serverName, searchTool.Name, new Dictionary { ["query"] = query } ); if (!result.IsSuccess) return (serverName, Enumerable.Empty()); var items = JsonSerializer.Deserialize>(result.Content) ?? Enumerable.Empty(); return (serverName, items); } catch (Exception ex) { _logger.LogWarning( ex, "Failed to search server {ServerName}", serverName ); return (serverName, Enumerable.Empty()); } } } ``` --- ## Step 4: Connection Health Monitoring **Generate health check service**: ```csharp using Microsoft.Extensions.Diagnostics.HealthChecks; using OpenHarbor.MCP.Client.Core.Abstractions; namespace MyApp.HealthChecks; public class McpServerHealthCheck : IHealthCheck { private readonly IMcpClient _mcpClient; private readonly ILogger _logger; public McpServerHealthCheck( IMcpClient mcpClient, ILogger logger) { _mcpClient = mcpClient; _logger = logger; } public async Task CheckHealthAsync( HealthCheckContext context, CancellationToken cancellationToken = default) { var servers = await _mcpClient.GetConnectedServersAsync(); var healthData = new Dictionary(); var allHealthy = true; foreach (var server in servers) { try { await _mcpClient.PingAsync(server.Name, cancellationToken); healthData[server.Name] = "Healthy"; } catch (Exception ex) { _logger.LogWarning( ex, "Health check failed for MCP server {ServerName}", server.Name ); healthData[server.Name] = $"Unhealthy: {ex.Message}"; allHealthy = false; } } return allHealthy ? HealthCheckResult.Healthy("All MCP servers are responsive", healthData) : HealthCheckResult.Degraded("Some MCP servers are not responsive", data: healthData); } } ``` **Register in Program.cs**: ```csharp builder.Services.AddHealthChecks() .AddCheck("mcp-servers"); app.MapHealthChecks("/health"); ``` --- ## Step 5: Validation & Testing **Goal**: Verify configuration and provide feedback. ### 5.1 Configuration Validation ```bash # Validate appsettings.json syntax cat appsettings.json | jq . # Test connection to configured server (if Stdio) dotnet run --project /path/to/CodexMcpServer -- tools/list ``` ### 5.2 Sample Test Execution **Create integration test**: ```csharp using Xunit; using Microsoft.Extensions.DependencyInjection; using OpenHarbor.MCP.Client.Core.Abstractions; public class McpClientIntegrationTests { [Fact] public async Task Client_CanConnectToServer() { // Arrange var services = new ServiceCollection(); services.AddMcpClient(/* config */); var provider = services.BuildServiceProvider(); var client = provider.GetRequiredService(); // Act await client.ConnectToServerAsync("local-codex-server"); var tools = await client.ListToolsAsync("local-codex-server"); // Assert Assert.NotEmpty(tools); } [Fact] public async Task Client_CanCallTool() { // Arrange var services = new ServiceCollection(); services.AddMcpClient(/* config */); var provider = services.BuildServiceProvider(); var client = provider.GetRequiredService(); await client.ConnectToServerAsync("local-codex-server"); // Act var result = await client.CallToolAsync( "local-codex-server", "search_codex", new Dictionary { ["query"] = "test", ["maxResults"] = 5 } ); // Assert Assert.True(result.IsSuccess); Assert.NotNull(result.Content); } } ``` ### 5.3 Provide Feedback to User **Generate summary report**: ```markdown ## OpenHarbor.MCP.Client Setup Complete ### Configuration Summary - **Project Type**: ASP.NET Core Web API - **Target Framework**: .NET 8.0 - **.NET SDK Version**: 8.0.100 ### MCP Servers Configured 1. **local-codex-server** (Stdio) - Command: `dotnet run --project /path/to/CodexMcpServer` - Status: Enabled - Timeout: 30 seconds 2. **remote-api-server** (HTTP) - URL: https://api.example.com/mcp - Status: Disabled (requires configuration) - Timeout: 60 seconds ### Generated Files - ✅ appsettings.json (MCP client configuration) - ✅ Program.cs (client registration) - ✅ Services/CodexSearchService.cs (search integration) - ✅ Services/DocumentService.cs (document retrieval) - ✅ HealthChecks/McpServerHealthCheck.cs (monitoring) ### Next Steps 1. Update server paths in appsettings.json 2. Configure authentication (if using HTTP transport) 3. Run tests: `dotnet test` 4. Start application: `dotnet run` 5. Check health: `curl http://localhost:5000/health` ### Testing the Integration ```bash # List available tools dotnet run -- mcp list-tools --server local-codex-server # Call a tool dotnet run -- mcp call-tool --server local-codex-server --tool search_codex --args '{"query":"test"}' ``` ### Troubleshooting - Ensure MCP servers are running before connecting - Check logs in `logs/mcp-client.log` for connection errors - Verify timeout values are appropriate for your servers - Test network connectivity for HTTP-based servers ``` --- ## Step 6: AI Agent Workflow **Recommended automation sequence**: 1. **Analyze** → Run Step 1 (system detection) 2. **Confirm** → Show detected features, ask user approval 3. **Generate** → Create files from Step 2-4 4. **Validate** → Run Step 5 tests 5. **Report** → Provide Step 5.3 summary 6. **Handoff** → "Configuration complete. Ready to start using MCP client?" **Example AI interaction**: ``` AI: I've analyzed your project. Here's what I found: - .NET 8.0 Web API - Existing HTTP client setup - Logging configured I can set up OpenHarbor.MCP.Client to connect to: 1. Local CODEX server (Stdio) 2. Remote API server (HTTP) Should I proceed with configuration? (yes/no) User: yes AI: Generating configuration files... ✅ appsettings.json created ✅ Program.cs updated ✅ Sample services created ✅ Health checks configured Running validation tests... ✅ All tests passed Setup complete! Your app can now connect to MCP servers. Next step: Run `dotnet run` to start. ``` --- ## Appendix: Common Scenarios ### A. Console Application Setup - Use `IHostBuilder` pattern - Register MCP client in service collection - Call tools from `Main` method ### B. Background Worker Setup - Implement `IHostedService` - Connect to servers on startup - Poll tools periodically ### C. Web API Integration - Register client in DI container - Inject into controllers/services - Call tools in request handlers ### D. Multiple Server Scenarios - Configure multiple servers in array - Use `GetConnectedServersAsync()` to discover - Aggregate results from multiple sources --- **Document Version**: 1.0.0 **Last Updated**: 2025-10-19 **Target**: OpenHarbor.MCP.Client