Tighten draft protocol negotiation boundaries (#1692)

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Tarek Mahmoud Sayed <tarekms@ntdev.microsoft.com>
This commit is contained in:
Stephen Halter 2026-07-12 14:30:49 -07:00 • committed by GitHub
commit fd38f51e27
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -147,7 +147,7 @@ public class MrtrProtocolTests(ITestOutputHelper outputHelper) : KestrelInMemory
// headers. No initialize handshake and no Mcp-Session-Id.
HttpClient.DefaultRequestHeaders.Accept.Add(new("application/json"));
HttpClient.DefaultRequestHeaders.Accept.Add(new("text/event-stream"));
HttpClient.DefaultRequestHeaders.Add("MCP-Protocol-Version", McpHttpHeaders.July2026ProtocolVersion);
HttpClient.DefaultRequestHeaders.Add("MCP-Protocol-Version", McpProtocolVersions.July2026ProtocolVersion);
}
public async ValueTask DisposeAsync()
@ -261,7 +261,7 @@ public class MrtrProtocolTests(ITestOutputHelper outputHelper) : KestrelInMemory
public async Task BackcompatResolver_SendsServerRequestOverPostStream_WithoutGetStream()
{
// Configure a server that does NOT pin 2026-07-28 so it can negotiate the current
// protocol with a legacy client. The backcompat resolver path only runs when the
// initialize-handshake protocol. The backcompat resolver path only runs when the
// negotiated version is not 2026-07-28.
Builder.Services.AddMcpServer(options =>
{
@ -302,7 +302,7 @@ public class MrtrProtocolTests(ITestOutputHelper outputHelper) : KestrelInMemory
HttpClient.DefaultRequestHeaders.Accept.Add(new("application/json"));
HttpClient.DefaultRequestHeaders.Accept.Add(new("text/event-stream"));
// Initialize with the current legacy protocol so the server's backcompat resolver runs.
// Initialize with the current initialize-handshake protocol so the server's backcompat resolver runs.
var initJson = """
{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-11-25","capabilities":{"roots":{}},"clientInfo":{"name":"BackcompatTestClient","version":"1.0.0"}}}
""";
@ -337,7 +337,7 @@ public class MrtrProtocolTests(ITestOutputHelper outputHelper) : KestrelInMemory
// the response headers arrive instead of waiting for the SSE stream to close.
var callRequest = new HttpRequestMessage(HttpMethod.Post, (string?)null)
{
Content = JsonContent(CallTool("backcompat-roots-tool")),
Content = JsonContent(CallTool("backcompat-roots-tool", includePerRequestMetadata: false)),
};
callRequest.Content.Headers.Add("Mcp-Method", "tools/call");
callRequest.Content.Headers.Add("Mcp-Name", "backcompat-roots-tool");
@ -456,16 +456,49 @@ public class MrtrProtocolTests(ITestOutputHelper outputHelper) : KestrelInMemory
private long _lastRequestId = 1;
private string Request(string method, string parameters = "{}")
private string Request(string method, string parameters = "{}", bool includePerRequestMetadata = true)
{
var id = Interlocked.Increment(ref _lastRequestId);
return $$"""
{"jsonrpc":"2.0","id":{{id}},"method":"{{method}}","params":{{parameters}}}
""";
var paramsObj = JsonNode.Parse(parameters) as JsonObject ?? new JsonObject();
if (includePerRequestMetadata)
{
AddJuly2026ProtocolMeta(paramsObj);
}
var request = new JsonObject
{
["jsonrpc"] = "2.0",
["id"] = id,
["method"] = method,
["params"] = paramsObj,
};
return request.ToJsonString();
}
private string CallTool(string toolName, string arguments = "{}") =>
private static void AddJuly2026ProtocolMeta(JsonObject paramsObj)
{
if (paramsObj["_meta"] is not JsonObject meta)
{
meta = [];
paramsObj["_meta"] = meta;
}
meta[MetaKeys.ProtocolVersion] = McpProtocolVersions.July2026ProtocolVersion;
meta[MetaKeys.ClientInfo] = new JsonObject
{
["name"] = "MrtrTestClient",
["version"] = "1.0",
};
if (meta[MetaKeys.ClientCapabilities] is not JsonObject)
{
meta[MetaKeys.ClientCapabilities] = new JsonObject();
}
}
private string CallTool(string toolName, string arguments = "{}", bool includePerRequestMetadata = true) =>
Request("tools/call", $$"""
{"name":"{{toolName}}","arguments":{{arguments}}}
""");
""", includePerRequestMetadata);
}