using Microsoft.Extensions.DependencyInjection; using ModelContextProtocol.Client; using ModelContextProtocol.Protocol; using ModelContextProtocol.Server; namespace ModelContextProtocol.Tests.Server; /// /// Regression tests for issue #1721: the SDK-provided resultType, ttlMs, and /// cacheScope result decorations are exclusive to the 2026-07-28 protocol revision and /// must be absent from result objects on a session negotiated to an earlier revision /// (e.g. 2025-11-25). Emitting them breaks clients that strictly validate the 2025-11-25 /// schema. /// /// /// These drive the in-process client/server pair and inspect the /// raw JSON-RPC result wire shape (via ) /// so the assertions are about the actual serialized fields rather than deserialized objects. /// tools/list exercises the SetHandler decoration path (its result is both an /// and a ), while tools/call exercises the /// SetWithAlternateHandler path. /// public class ProtocolVersionResultDecorationTests : ClientServerTestBase { public ProtocolVersionResultDecorationTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { } protected override void ConfigureServices(ServiceCollection services, IMcpServerBuilder mcpServerBuilder) { mcpServerBuilder.WithTools([McpServerTool.Create(() => "ok", new() { Name = "echo" })]); } [Fact] public async Task ToolsList_On2025_11_25Session_OmitsResultTypeAndCacheHints() { await using var client = await CreateMcpClientForServer( new McpClientOptions { ProtocolVersion = McpProtocolVersions.November2025ProtocolVersion }); Assert.Equal(McpProtocolVersions.November2025ProtocolVersion, client.NegotiatedProtocolVersion); var response = await client.SendRequestAsync( new JsonRpcRequest { Method = RequestMethods.ToolsList }, TestContext.Current.CancellationToken); var result = response.Result!.AsObject(); Assert.False(result.ContainsKey("resultType"), "resultType must be absent on a 2025-11-25 tools/list result."); Assert.False(result.ContainsKey("ttlMs"), "ttlMs must be absent on a 2025-11-25 tools/list result."); Assert.False(result.ContainsKey("cacheScope"), "cacheScope must be absent on a 2025-11-25 tools/list result."); } [Fact] public async Task ToolsCall_On2025_11_25Session_OmitsResultType() { await using var client = await CreateMcpClientForServer( new McpClientOptions { ProtocolVersion = McpProtocolVersions.November2025ProtocolVersion }); Assert.Equal(McpProtocolVersions.November2025ProtocolVersion, client.NegotiatedProtocolVersion); var response = await client.SendRequestAsync( new JsonRpcRequest { Method = RequestMethods.ToolsCall, Params = System.Text.Json.JsonSerializer.SerializeToNode( new CallToolRequestParams { Name = "echo" }, McpJsonUtilities.DefaultOptions), }, TestContext.Current.CancellationToken); var result = response.Result!.AsObject(); Assert.False(result.ContainsKey("resultType"), "resultType must be absent on a 2025-11-25 tools/call result."); } [Fact] public async Task ToolsList_On2026_07_28Session_IncludesResultTypeAndCacheHints() { await using var client = await CreateMcpClientForServer( new McpClientOptions { ProtocolVersion = McpProtocolVersions.July2026ProtocolVersion }); Assert.Equal(McpProtocolVersions.July2026ProtocolVersion, client.NegotiatedProtocolVersion); var response = await client.SendRequestAsync( new JsonRpcRequest { Method = RequestMethods.ToolsList }, TestContext.Current.CancellationToken); var result = response.Result!.AsObject(); Assert.Equal("complete", result["resultType"]!.GetValue()); Assert.True(result.ContainsKey("ttlMs"), "ttlMs must be present on a 2026-07-28 tools/list result."); Assert.True(result.ContainsKey("cacheScope"), "cacheScope must be present on a 2026-07-28 tools/list result."); } [Fact] public async Task ToolsCall_On2026_07_28Session_IncludesResultType() { await using var client = await CreateMcpClientForServer( new McpClientOptions { ProtocolVersion = McpProtocolVersions.July2026ProtocolVersion }); Assert.Equal(McpProtocolVersions.July2026ProtocolVersion, client.NegotiatedProtocolVersion); var response = await client.SendRequestAsync( new JsonRpcRequest { Method = RequestMethods.ToolsCall, Params = System.Text.Json.JsonSerializer.SerializeToNode( new CallToolRequestParams { Name = "echo" }, McpJsonUtilities.DefaultOptions), }, TestContext.Current.CancellationToken); var result = response.Result!.AsObject(); Assert.Equal("complete", result["resultType"]!.GetValue()); } }