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());
}
}