svrnty-mcp-server/tests/Svrnty.MCP.Core.Tests/McpServerTests.cs
Svrnty 0c27de4162 refactor: rename OpenHarbor.MCP to Svrnty.MCP across all libraries
- Renamed all directories: OpenHarbor.MCP.* → Svrnty.MCP.*
- Updated all namespaces in 179 C# files
- Renamed 20 .csproj files and 3 .sln files
- Updated 193 documentation references
- Updated 33 references in main CODEX codebase
- Updated Codex.sln with new paths
- Build verified: 0 errors

Preparing for extraction to standalone repositories.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-22 21:04:17 -04:00

278 lines
8.4 KiB
C#

using Xunit;
using Moq;
using System.Text.Json;
using System.Threading.Tasks;
namespace Svrnty.MCP.Core.Tests;
/// <summary>
/// Unit tests for McpServer following TDD approach.
/// Tests MCP protocol method routing and execution.
/// </summary>
public class McpServerTests
{
[Fact]
public void McpServer_ShouldInitializeWithToolRegistry()
{
// Arrange
var registry = new ToolRegistry();
// Act
var server = new McpServer(registry);
// Assert
Assert.NotNull(server);
}
[Fact]
public void McpServer_ShouldThrowOnNullRegistry()
{
// Act & Assert
Assert.Throws<ArgumentNullException>(() =>
new McpServer(null!)
);
}
[Fact]
public async Task McpServer_HandleRequest_WithToolsList_ShouldReturnToolDescriptions()
{
// Arrange
var registry = new ToolRegistry();
var mockTool = CreateMockTool("test_tool", "Test tool description");
registry.AddTool(mockTool.Object);
var server = new McpServer(registry);
var request = new McpRequest
{
Id = "1",
Method = "tools/list"
};
// Act
var response = await server.HandleRequestAsync(request);
// Assert
Assert.NotNull(response);
Assert.Equal("1", response.Id);
Assert.Null(response.Error);
Assert.NotNull(response.Result);
var result = response.Result.RootElement;
Assert.True(result.TryGetProperty("tools", out var tools));
Assert.Equal(JsonValueKind.Array, tools.ValueKind);
Assert.Equal(1, tools.GetArrayLength());
var tool = tools[0];
Assert.True(tool.TryGetProperty("name", out var name));
Assert.Equal("test_tool", name.GetString());
Assert.True(tool.TryGetProperty("description", out var desc));
Assert.Equal("Test tool description", desc.GetString());
}
[Fact]
public async Task McpServer_HandleRequest_WithToolsList_EmptyRegistry_ShouldReturnEmptyArray()
{
// Arrange
var registry = new ToolRegistry();
var server = new McpServer(registry);
var request = new McpRequest
{
Id = "1",
Method = "tools/list"
};
// Act
var response = await server.HandleRequestAsync(request);
// Assert
Assert.NotNull(response);
Assert.Null(response.Error);
Assert.NotNull(response.Result);
var result = response.Result.RootElement;
Assert.True(result.TryGetProperty("tools", out var tools));
Assert.Equal(0, tools.GetArrayLength());
}
[Fact]
public async Task McpServer_HandleRequest_WithToolsCall_ShouldExecuteTool()
{
// Arrange
var registry = new ToolRegistry();
var mockTool = CreateMockTool("search_codex", "Search tool");
mockTool.Setup(t => t.ExecuteAsync(It.IsAny<JsonDocument>()))
.ReturnsAsync(JsonDocument.Parse("""{"results": ["doc1", "doc2"]}"""));
registry.AddTool(mockTool.Object);
var server = new McpServer(registry);
var request = new McpRequest
{
Id = "2",
Method = "tools/call",
Params = JsonDocument.Parse("""{"name":"search_codex","arguments":{"query":"test"}}""")
};
// Act
var response = await server.HandleRequestAsync(request);
// Assert
Assert.NotNull(response);
Assert.Equal("2", response.Id);
Assert.Null(response.Error);
Assert.NotNull(response.Result);
var result = response.Result.RootElement;
Assert.True(result.TryGetProperty("results", out var results));
mockTool.Verify(t => t.ExecuteAsync(It.IsAny<JsonDocument>()), Times.Once);
}
[Fact]
public async Task McpServer_HandleRequest_WithToolsCall_NonexistentTool_ShouldReturnError()
{
// Arrange
var registry = new ToolRegistry();
var server = new McpServer(registry);
var request = new McpRequest
{
Id = "3",
Method = "tools/call",
Params = JsonDocument.Parse("""{"name":"nonexistent_tool","arguments":{}}""")
};
// Act
var response = await server.HandleRequestAsync(request);
// Assert
Assert.NotNull(response);
Assert.Equal("3", response.Id);
Assert.Null(response.Result);
Assert.NotNull(response.Error);
Assert.Equal(-32601, response.Error.Code); // Method not found
Assert.Contains("nonexistent_tool", response.Error.Message);
}
[Fact]
public async Task McpServer_HandleRequest_WithUnknownMethod_ShouldReturnError()
{
// Arrange
var registry = new ToolRegistry();
var server = new McpServer(registry);
var request = new McpRequest
{
Id = "4",
Method = "unknown/method"
};
// Act
var response = await server.HandleRequestAsync(request);
// Assert
Assert.NotNull(response);
Assert.Equal("4", response.Id);
Assert.Null(response.Result);
Assert.NotNull(response.Error);
Assert.Equal(-32601, response.Error.Code); // Method not found
Assert.Contains("unknown/method", response.Error.Message);
}
[Fact]
public async Task McpServer_HandleRequest_WithToolsCall_MissingParams_ShouldReturnError()
{
// Arrange
var registry = new ToolRegistry();
var server = new McpServer(registry);
var request = new McpRequest
{
Id = "5",
Method = "tools/call"
// No Params
};
// Act
var response = await server.HandleRequestAsync(request);
// Assert
Assert.NotNull(response);
Assert.Equal("5", response.Id);
Assert.Null(response.Result);
Assert.NotNull(response.Error);
Assert.Equal(-32602, response.Error.Code); // Invalid params
}
[Fact]
public async Task McpServer_HandleRequest_WithToolsCall_MissingToolName_ShouldReturnError()
{
// Arrange
var registry = new ToolRegistry();
var server = new McpServer(registry);
var request = new McpRequest
{
Id = "6",
Method = "tools/call",
Params = JsonDocument.Parse("""{"arguments":{}}""") // Missing "name"
};
// Act
var response = await server.HandleRequestAsync(request);
// Assert
Assert.NotNull(response);
Assert.Equal("6", response.Id);
Assert.Null(response.Result);
Assert.NotNull(response.Error);
Assert.Equal(-32602, response.Error.Code); // Invalid params
}
[Fact]
public async Task McpServer_HandleRequest_WithNullRequest_ShouldThrow()
{
// Arrange
var registry = new ToolRegistry();
var server = new McpServer(registry);
// Act & Assert
await Assert.ThrowsAsync<ArgumentNullException>(async () =>
await server.HandleRequestAsync(null!)
);
}
[Fact]
public async Task McpServer_HandleRequest_WithToolsList_MultipleTools_ShouldReturnAll()
{
// Arrange
var registry = new ToolRegistry();
registry.AddTool(CreateMockTool("tool1", "First tool").Object);
registry.AddTool(CreateMockTool("tool2", "Second tool").Object);
registry.AddTool(CreateMockTool("tool3", "Third tool").Object);
var server = new McpServer(registry);
var request = new McpRequest
{
Id = "7",
Method = "tools/list"
};
// Act
var response = await server.HandleRequestAsync(request);
// Assert
Assert.NotNull(response);
Assert.NotNull(response.Result);
var result = response.Result.RootElement;
Assert.True(result.TryGetProperty("tools", out var tools));
Assert.Equal(3, tools.GetArrayLength());
}
// Helper method to create mock tools
private Mock<IMcpTool> CreateMockTool(string name, string description)
{
var mockTool = new Mock<IMcpTool>();
mockTool.Setup(t => t.Name).Returns(name);
mockTool.Setup(t => t.Description).Returns(description);
mockTool.Setup(t => t.Schema).Returns(JsonDocument.Parse("""{"type": "object"}"""));
mockTool.Setup(t => t.ExecuteAsync(It.IsAny<JsonDocument>()))
.ReturnsAsync(JsonDocument.Parse("""{"status": "ok"}"""));
return mockTool;
}
}