using Microsoft.Extensions.DependencyInjection; using ModelContextProtocol.Client; using ModelContextProtocol.Protocol; using ModelContextProtocol.Server; using System.Text.Json; using System.Text.Json.Nodes; namespace ModelContextProtocol.Tests.Client; /// /// Connection-flow tests for the 2026-07-28 protocol revision (SEP-2575 + SEP-2567) /// on . A client that requests /// calls server/discover rather than /// initialize. /// public class July2026ProtocolConnectionTests : ClientServerTestBase { private const string LatestStableVersion = McpProtocolVersions.November2025ProtocolVersion; public July2026ProtocolConnectionTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper, startServer: false) { } protected override void ConfigureServices(ServiceCollection services, IMcpServerBuilder mcpServerBuilder) { services.Configure(options => { options.ServerInfo = new Implementation { Name = nameof(July2026ProtocolConnectionTests), Version = "1.0" }; }); } [Fact] public async Task Client_RequestingJuly2026Protocol_NegotiatesIt() { StartServer(); var options = new McpClientOptions { ProtocolVersion = McpProtocolVersions.July2026ProtocolVersion }; await using var client = await CreateMcpClientForServer(options); Assert.Equal(McpProtocolVersions.July2026ProtocolVersion, client.NegotiatedProtocolVersion); Assert.NotNull(client.ServerCapabilities); Assert.Equal(nameof(July2026ProtocolConnectionTests), client.ServerInfo.Name); } [Fact] public async Task Client_RequestingInitializeHandshakeVersion_NegotiatesIt() { StartServer(); await using var client = await CreateMcpClientForServer(new McpClientOptions { ProtocolVersion = LatestStableVersion }); Assert.NotEqual(McpProtocolVersions.July2026ProtocolVersion, client.NegotiatedProtocolVersion); } [Fact] public async Task Client_AllowsDiscoverResultWithoutServerInfo() { ConfigureDiscoverServerInfo(meta => meta.Remove(MetaKeys.ServerInfo)); StartServer(); var options = new McpClientOptions { ProtocolVersion = McpProtocolVersions.July2026ProtocolVersion }; await using var client = await CreateMcpClientForServer(options); Assert.Equal(McpProtocolVersions.July2026ProtocolVersion, client.NegotiatedProtocolVersion); Assert.Throws(() => _ = client.ServerInfo); } [Fact] public async Task Client_RejectsMalformedDiscoverServerInfo() { ConfigureDiscoverServerInfo(meta => meta[MetaKeys.ServerInfo] = "invalid"); StartServer(); var options = new McpClientOptions { ProtocolVersion = McpProtocolVersions.July2026ProtocolVersion }; await Assert.ThrowsAsync(() => CreateMcpClientForServer(options)); } [Fact] public async Task Client_RejectsNullDiscoverServerInfo() { ConfigureDiscoverServerInfo(meta => meta[MetaKeys.ServerInfo] = null); StartServer(); var options = new McpClientOptions { ProtocolVersion = McpProtocolVersions.July2026ProtocolVersion }; await Assert.ThrowsAsync(() => CreateMcpClientForServer(options)); } [Fact] public async Task InitializeHandshakeClient_CannotCallServerDiscover() { // server/discover is registered unconditionally so the protocol boundary filter can return a structured // error, but initialize-handshake clients cannot use it after negotiating an older protocol version. StartServer(); await using var client = await CreateMcpClientForServer(new McpClientOptions { ProtocolVersion = LatestStableVersion }); var exception = await Assert.ThrowsAsync(async () => await client.SendRequestAsync( new JsonRpcRequest { Method = RequestMethods.ServerDiscover }, TestContext.Current.CancellationToken)); Assert.Equal(McpErrorCode.MethodNotFound, exception.ErrorCode); Assert.Contains(RequestMethods.ServerDiscover, exception.Message, StringComparison.Ordinal); } [Fact] public async Task ServerDiscover_IncludesJuly2026ProtocolVersion() { StartServer(); await using var client = await CreateMcpClientForServer(); var response = await client.SendRequestAsync( new JsonRpcRequest { Method = RequestMethods.ServerDiscover }, TestContext.Current.CancellationToken); var discoverResult = JsonSerializer.Deserialize(response.Result, McpJsonUtilities.DefaultOptions); Assert.NotNull(discoverResult); Assert.Equal("complete", discoverResult.ResultType); Assert.Equal([McpProtocolVersions.July2026ProtocolVersion], discoverResult.SupportedVersions); } private void ConfigureDiscoverServerInfo(Action configure) { McpServerBuilder.WithMessageFilters(filters => filters.AddOutgoingFilter(next => async (context, cancellationToken) => { if (context.JsonRpcMessage is JsonRpcResponse { Result: JsonObject result } && result["supportedVersions"] is not null && result["_meta"] is JsonObject meta) { configure(meta); } await next(context, cancellationToken); })); } }