Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion mods/OniMcp/Server/McpHttpServerModernProtocol.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,15 @@ private bool TryHandleModernPost(HttpListenerRequest httpRequest, HttpListenerRe
? (string)meta["io.modelcontextprotocol/protocolVersion"]
: null;

bool modernSignal = string.Equals(protocolVersion, ModernProtocolVersion, StringComparison.Ordinal)
bool explicitModern = string.Equals(protocolVersion, ModernProtocolVersion, StringComparison.Ordinal);
if (IsSupportedProtocolVersion(protocolVersion))
return false;

string sessionId = httpRequest.Headers["Mcp-Session-Id"];
if (!explicitModern && IsSessionActive(sessionId))
return false;

bool modernSignal = explicitModern
|| string.Equals(metaVersion, ModernProtocolVersion, StringComparison.Ordinal);
if (!modernSignal)
return false;
Expand Down
76 changes: 70 additions & 6 deletions tests/OniMcp.ModernProtocol.Tests/Program.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Sockets;
Expand Down Expand Up @@ -38,7 +39,7 @@ private static void Main()
const string missingUri = "oni://missing-resource";
const string modernMeta = "\"_meta\":{\"io.modelcontextprotocol/protocolVersion\":\"2026-07-28\",\"io.modelcontextprotocol/clientCapabilities\":{},\"io.modelcontextprotocol/clientInfo\":{\"name\":\"sep-2164-regression\",\"version\":\"1.0\"}}";
string body = "{\"jsonrpc\":\"2.0\",\"method\":\"resources/read\",\"id\":2164,\"params\":{\"uri\":\"" + missingUri + "\"," + modernMeta + "}}";
using (var response = PostModern(client, body, missingUri))
using (var response = Post(client, body, null, "2026-07-28", "resources/read", missingUri))
{
Assert(response.StatusCode == HttpStatusCode.OK, "Resource application error changed HTTP status");
JObject json = JObject.Parse(response.Content.ReadAsStringAsync().GetAwaiter().GetResult());
Expand All @@ -52,24 +53,87 @@ private static void Main()
}
Assert(server.GetSessionSummaries().Count == 0,
"Modern resource error allocated legacy session state");

const string initialize = "{\"jsonrpc\":\"2.0\",\"method\":\"initialize\",\"id\":1,\"params\":{\"protocolVersion\":\"2025-11-25\"}}";
string sessionId;
using (var response = Post(client, initialize, null, "2025-11-25"))
{
Assert(response.StatusCode == HttpStatusCode.OK, "Legacy initialize failed");
Assert(JObject.Parse(response.Content.ReadAsStringAsync().GetAwaiter().GetResult())["result"] != null,
"Legacy initialize returned no result");
sessionId = response.Headers.GetValues("Mcp-Session-Id").Single();
}

const string futureMeta = "\"_meta\":{\"io.modelcontextprotocol/protocolVersion\":\"2026-07-28\",\"io.modelcontextprotocol/clientCapabilities\":{\"sampling\":{}},\"io.modelcontextprotocol/clientInfo\":{\"name\":\"mixed-era-regression\",\"version\":\"1.0\"}}";
string legacyToolsList = "{\"jsonrpc\":\"2.0\",\"method\":\"tools/list\",\"id\":2,\"params\":{" + futureMeta + "}}";

using (var response = Post(client, legacyToolsList, sessionId, "2025-11-25"))
{
Assert(response.StatusCode == HttpStatusCode.OK,
"Explicit legacy transport was diverted by future metadata");
Assert(JObject.Parse(response.Content.ReadAsStringAsync().GetAwaiter().GetResult())["result"] != null,
"Explicit legacy transport did not reach legacy tools/list");
Assert(response.Headers.GetValues("Mcp-Session-Id").Single() == sessionId,
"Explicit legacy transport lost its session identity");
}

using (var response = Post(client, legacyToolsList, sessionId))
{
Assert(response.StatusCode == HttpStatusCode.OK,
"Established legacy session was diverted by future metadata");
Assert(JObject.Parse(response.Content.ReadAsStringAsync().GetAwaiter().GetResult())["result"] != null,
"Established legacy session did not reach legacy tools/list");
Assert(response.Headers.GetValues("Mcp-Protocol-Version").Single() == "2025-11-25",
"Established legacy session changed protocol era");
}

using (var response = Post(client, legacyToolsList, sessionId, "2026-07-28", "tools/list"))
{
Assert(response.StatusCode == HttpStatusCode.NotFound,
"Explicit modern transport was downgraded by a legacy session id");
JObject json = JObject.Parse(response.Content.ReadAsStringAsync().GetAwaiter().GetResult());
Assert((int)json["error"]["code"] == McpErrorCode.MethodNotFound,
"Explicit modern transport did not stay on the modern path");
Assert(!response.Headers.Contains("Mcp-Session-Id"),
"Modern response reused a legacy session header");
}

string discover = "{\"jsonrpc\":\"2.0\",\"method\":\"server/discover\",\"id\":3,\"params\":{" + modernMeta + "}}";
using (var response = Post(client, discover, null, null, "server/discover"))
{
Assert(response.StatusCode == HttpStatusCode.BadRequest,
"Headerless modern metadata did not reach modern validation");
JObject json = JObject.Parse(response.Content.ReadAsStringAsync().GetAwaiter().GetResult());
Assert((int)json["error"]["code"] == -32020,
"Headerless modern metadata fell back to legacy session validation");
}

Assert(server.GetSessionSummaries().Count == 1,
"Mixed-era regression changed legacy session ownership");
}
}
finally
{
server.StopServer();
Invoke(_bridge, "OnDestroy");
}
Console.WriteLine("PASS SEP-2164 modern resource-not-found wire regression");
Console.WriteLine("PASS modern resource and mixed-era routing wire regressions");
}

private static HttpResponseMessage PostModern(HttpClient client, string json, string name)
private static HttpResponseMessage Post(HttpClient client, string json, string sessionId = null,
string protocolVersion = null, string method = null, string name = null)
{
using (var request = new HttpRequestMessage(HttpMethod.Post, ""))
{
request.Content = new StringContent(json, Encoding.UTF8, "application/json");
request.Headers.Add("Mcp-Protocol-Version", "2026-07-28");
request.Headers.Add("Mcp-Method", "resources/read");
request.Headers.Add("Mcp-Name", name);
if (sessionId != null)
request.Headers.Add("Mcp-Session-Id", sessionId);
if (protocolVersion != null)
request.Headers.Add("Mcp-Protocol-Version", protocolVersion);
if (method != null)
request.Headers.Add("Mcp-Method", method);
if (name != null)
request.Headers.Add("Mcp-Name", name);
Task<HttpResponseMessage> work = client.SendAsync(request);
PumpUntil(work);
return work.GetAwaiter().GetResult();
Expand Down
Loading