svrnty-mcp-client/tests/Svrnty.MCP.Client.Core.Tests/Infrastructure/McpClientTests.cs
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

177 lines
4.7 KiB
C#

using Moq;
using OpenHarbor.MCP.Client.Core.Abstractions;
using OpenHarbor.MCP.Client.Core.Exceptions;
using OpenHarbor.MCP.Client.Core.Models;
using OpenHarbor.MCP.Client.Infrastructure;
using Xunit;
namespace OpenHarbor.MCP.Client.Core.Tests.Infrastructure;
/// <summary>
/// Unit tests for McpClient following TDD approach.
/// Tests client initialization, server management, and tool operations.
/// </summary>
public class McpClientTests
{
[Fact]
public void Constructor_WithServerConfigs_CreatesClient()
{
// Arrange
var configs = new List<McpServerConfig>
{
CreateTestConfig("server1"),
CreateTestConfig("server2")
};
// Act
var client = new McpClient(configs);
// Assert
Assert.NotNull(client);
}
[Fact]
public async Task ConnectAllAsync_WithMultipleServers_ConnectsAll()
{
// Arrange
var configs = new List<McpServerConfig>
{
CreateTestConfig("server1"),
CreateTestConfig("server2")
};
var client = new McpClient(configs);
// Act
await client.ConnectAllAsync();
// Assert
var servers = await client.GetConnectedServersAsync();
Assert.Equal(2, servers.Count());
}
[Fact]
public async Task DisconnectAllAsync_AfterConnect_DisconnectsAll()
{
// Arrange
var configs = new List<McpServerConfig> { CreateTestConfig("server1") };
var client = new McpClient(configs);
await client.ConnectAllAsync();
// Act
await client.DisconnectAllAsync();
// Assert
var servers = await client.GetConnectedServersAsync();
Assert.Empty(servers);
}
[Fact]
public async Task GetConnectedServersAsync_WithNoServers_ReturnsEmpty()
{
// Arrange
var client = new McpClient(new List<McpServerConfig>());
// Act
var servers = await client.GetConnectedServersAsync();
// Assert
Assert.Empty(servers);
}
[Fact]
public async Task ListToolsAsync_WithNonExistentServer_ThrowsServerNotFoundException()
{
// Arrange
var client = new McpClient(new List<McpServerConfig>());
// Act & Assert
await Assert.ThrowsAsync<ServerNotFoundException>(
async () => await client.ListToolsAsync("non-existent-server")
);
}
[Fact]
public async Task CallToolAsync_WithNonExistentServer_ThrowsServerNotFoundException()
{
// Arrange
var client = new McpClient(new List<McpServerConfig>());
// Act & Assert
await Assert.ThrowsAsync<ServerNotFoundException>(
async () => await client.CallToolAsync("non-existent-server", "test_tool")
);
}
[Fact]
public async Task PingAsync_WithNonExistentServer_ThrowsServerNotFoundException()
{
// Arrange
var client = new McpClient(new List<McpServerConfig>());
// Act & Assert
await Assert.ThrowsAsync<ServerNotFoundException>(
async () => await client.PingAsync("non-existent-server")
);
}
[Fact]
public async Task DisposeAsync_AfterConnect_DisposesCleanly()
{
// Arrange
var configs = new List<McpServerConfig> { CreateTestConfig("server1") };
var client = new McpClient(configs);
await client.ConnectAllAsync();
// Act
await client.DisposeAsync();
// Assert
var servers = await client.GetConnectedServersAsync();
Assert.Empty(servers);
}
[Fact]
public async Task ListToolsAsync_WithConnectedServer_ReturnsTools()
{
// Arrange
var configs = new List<McpServerConfig> { CreateTestConfig("server1") };
var client = new McpClient(configs);
await client.ConnectAllAsync();
// Act
var tools = await client.ListToolsAsync("server1");
// Assert
Assert.NotNull(tools);
}
[Fact]
public async Task CallToolAsync_WithConnectedServer_ReturnsResult()
{
// Arrange
var configs = new List<McpServerConfig> { CreateTestConfig("server1") };
var client = new McpClient(configs);
await client.ConnectAllAsync();
// Act
var result = await client.CallToolAsync("server1", "test_tool");
// Assert
Assert.NotNull(result);
}
private static McpServerConfig CreateTestConfig(string name)
{
return new McpServerConfig
{
Name = name,
Transport = new StdioTransportConfig
{
Type = "Stdio",
Command = "echo",
Args = new[] { "test" }
}
};
}
}