using Xunit; using System.Text.Json; namespace Svrnty.MCP.Core.Tests; /// /// Unit tests for MCP request/response models following TDD approach. /// Tests JSON-RPC 2.0 protocol message structures. /// public class McpModelsTests { [Fact] public void McpRequest_ShouldHaveJsonRpcVersion() { // Arrange & Act var request = new McpRequest { JsonRpc = "2.0", Method = "tools/call", Id = "1" }; // Assert Assert.Equal("2.0", request.JsonRpc); } [Fact] public void McpRequest_ShouldHaveMethod() { // Arrange & Act var request = new McpRequest { JsonRpc = "2.0", Method = "tools/list", Id = "1" }; // Assert Assert.Equal("tools/list", request.Method); } [Fact] public void McpRequest_ShouldHaveId() { // Arrange & Act var request = new McpRequest { JsonRpc = "2.0", Method = "tools/call", Id = "request-123" }; // Assert Assert.Equal("request-123", request.Id); } [Fact] public void McpRequest_ShouldHaveOptionalParams() { // Arrange var paramsJson = JsonDocument.Parse(""" { "name": "search_codex", "arguments": {"query": "test"} } """); // Act var request = new McpRequest { JsonRpc = "2.0", Method = "tools/call", Id = "1", Params = paramsJson }; // Assert Assert.NotNull(request.Params); Assert.Equal("search_codex", request.Params.RootElement.GetProperty("name").GetString()); } [Fact] public void McpRequest_ParamsCanBeNull() { // Arrange & Act var request = new McpRequest { JsonRpc = "2.0", Method = "tools/list", Id = "1", Params = null }; // Assert Assert.Null(request.Params); } [Fact] public void McpResponse_ShouldHaveJsonRpcVersion() { // Arrange & Act var response = new McpResponse { JsonRpc = "2.0", Id = "1" }; // Assert Assert.Equal("2.0", response.JsonRpc); } [Fact] public void McpResponse_ShouldHaveId() { // Arrange & Act var response = new McpResponse { JsonRpc = "2.0", Id = "request-456" }; // Assert Assert.Equal("request-456", response.Id); } [Fact] public void McpResponse_ShouldHaveOptionalResult() { // Arrange var resultJson = JsonDocument.Parse(""" { "tools": [ {"name": "search_codex", "description": "Search CODEX documents"} ] } """); // Act var response = new McpResponse { JsonRpc = "2.0", Id = "1", Result = resultJson }; // Assert Assert.NotNull(response.Result); Assert.True(response.Result.RootElement.TryGetProperty("tools", out _)); } [Fact] public void McpResponse_ShouldHaveOptionalError() { // Arrange var error = new McpError { Code = -32601, Message = "Method not found" }; // Act var response = new McpResponse { JsonRpc = "2.0", Id = "1", Error = error }; // Assert Assert.NotNull(response.Error); Assert.Equal(-32601, response.Error.Code); Assert.Equal("Method not found", response.Error.Message); } [Fact] public void McpResponse_ResultAndErrorMutuallyExclusive() { // Arrange var resultJson = JsonDocument.Parse("""{"status": "ok"}"""); var error = new McpError { Code = -32600, Message = "Invalid Request" }; // Act - Response should have either result OR error, not both var responseWithResult = new McpResponse { JsonRpc = "2.0", Id = "1", Result = resultJson, Error = null }; var responseWithError = new McpResponse { JsonRpc = "2.0", Id = "1", Result = null, Error = error }; // Assert Assert.NotNull(responseWithResult.Result); Assert.Null(responseWithResult.Error); Assert.Null(responseWithError.Result); Assert.NotNull(responseWithError.Error); } [Fact] public void McpError_ShouldHaveCode() { // Arrange & Act var error = new McpError { Code = -32700, Message = "Parse error" }; // Assert Assert.Equal(-32700, error.Code); } [Fact] public void McpError_ShouldHaveMessage() { // Arrange & Act var error = new McpError { Code = -32600, Message = "Invalid Request" }; // Assert Assert.Equal("Invalid Request", error.Message); } [Fact] public void McpError_ShouldHaveOptionalData() { // Arrange var dataJson = JsonDocument.Parse("""{"detail": "Missing required field"}"""); // Act var error = new McpError { Code = -32602, Message = "Invalid params", Data = dataJson }; // Assert Assert.NotNull(error.Data); Assert.Equal("Missing required field", error.Data.RootElement.GetProperty("detail").GetString()); } [Fact] public void McpRequest_ShouldSerializeToJson() { // Arrange var request = new McpRequest { JsonRpc = "2.0", Method = "tools/list", Id = "1" }; // Act var json = JsonSerializer.Serialize(request); // Assert Assert.Contains("\"jsonrpc\":\"2.0\"", json); Assert.Contains("\"method\":\"tools/list\"", json); Assert.Contains("\"id\":\"1\"", json); } [Fact] public void McpResponse_ShouldSerializeToJson() { // Arrange var resultJson = JsonDocument.Parse("""{"status": "success"}"""); var response = new McpResponse { JsonRpc = "2.0", Id = "1", Result = resultJson }; // Act var json = JsonSerializer.Serialize(response); // Assert Assert.Contains("\"jsonrpc\":\"2.0\"", json); Assert.Contains("\"id\":\"1\"", json); Assert.Contains("\"result\"", json); } }