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