From a502efb70369e7109dd5d78760aa595e29f350b8 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Tue, 17 Feb 2026 16:49:12 -0800 Subject: [PATCH] Update tests for @modelcontextprotocol/server-everything 2026.1.26 (#1273) Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com> --- package-lock.json | 15 +-- package.json | 2 +- .../Program.cs | 71 +++++++++------ .../ClientIntegrationTestFixture.cs | 2 +- .../ClientIntegrationTests.cs | 91 ++++++++++--------- .../DockerEverythingServerTests.cs | 4 +- 6 files changed, 107 insertions(+), 78 deletions(-) diff --git a/package-lock.json b/package-lock.json index aca8545..36b04d0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { - "name": "mcp", + "name": "csharp-sdk", "lockfileVersion": 3, "requires": true, "packages": { "": { "dependencies": { "@modelcontextprotocol/conformance": "0.1.13", - "@modelcontextprotocol/server-everything": "2025.12.18", + "@modelcontextprotocol/server-everything": "2026.1.26", "@modelcontextprotocol/server-memory": "2026.1.26" } }, @@ -82,12 +82,12 @@ } }, "node_modules/@modelcontextprotocol/server-everything": { - "version": "2025.12.18", - "resolved": "https://registry.npmjs.org/@modelcontextprotocol/server-everything/-/server-everything-2025.12.18.tgz", - "integrity": "sha512-S+MYITzTp02eLSxT+abAMDXf2vjubVKUbdjVj5HW9aEepa/lkcdcSZHeI8PpxpnZOQOW28FKGyFEG/QdawyAeA==", + "version": "2026.1.26", + "resolved": "https://registry.npmjs.org/@modelcontextprotocol/server-everything/-/server-everything-2026.1.26.tgz", + "integrity": "sha512-RIEXAQuKZeXZqFzJMqLDlzmMmG5sjq2uhS/VqzF4HIZ3w1V73YcWf+UXkxJueJuHMBO3Z8ceBrQ5wI6o/plZ+Q==", "license": "MIT", "dependencies": { - "@modelcontextprotocol/sdk": "^1.24.0", + "@modelcontextprotocol/sdk": "^1.25.2", "cors": "^2.8.5", "express": "^5.2.1", "jszip": "^3.10.1", @@ -430,6 +430,7 @@ "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", "license": "MIT", + "peer": true, "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.1", @@ -634,6 +635,7 @@ "resolved": "https://registry.npmjs.org/hono/-/hono-4.11.7.tgz", "integrity": "sha512-l7qMiNee7t82bH3SeyUCt9UF15EVmaBvsppY2zQtrbIhl/yzBTny+YUxsVjSjQ6gaqaeVtZmGocom8TzBlA4Yw==", "license": "MIT", + "peer": true, "engines": { "node": ">=16.9.0" } @@ -1294,6 +1296,7 @@ "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", "license": "MIT", + "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } diff --git a/package.json b/package.json index 4d007f0..b05f143 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "description": "Pinned npm dependencies for MCP C# SDK integration and conformance tests", "dependencies": { "@modelcontextprotocol/conformance": "0.1.13", - "@modelcontextprotocol/server-everything": "2025.12.18", + "@modelcontextprotocol/server-everything": "2026.1.26", "@modelcontextprotocol/server-memory": "2026.1.26" } } diff --git a/tests/ModelContextProtocol.TestServer/Program.cs b/tests/ModelContextProtocol.TestServer/Program.cs index fc70bdf..7ac6513 100644 --- a/tests/ModelContextProtocol.TestServer/Program.cs +++ b/tests/ModelContextProtocol.TestServer/Program.cs @@ -142,8 +142,8 @@ internal static class Program }, new Tool { - Name = "sampleLLM", - Description = "Samples from an LLM using MCP's sampling feature.", + Name = "trigger-sampling-request", + Description = "Trigger a Request from the Server for LLM Sampling", InputSchema = JsonElement.Parse(""" { "type": "object", @@ -205,7 +205,7 @@ internal static class Program Content = [new TextContentBlock { Text = request.Server.SessionId ?? string.Empty }] }; } - else if (request.Params?.Name == "sampleLLM") + else if (request.Params?.Name == "trigger-sampling-request") { if (request.Params?.Arguments is null || !request.Params.Arguments.TryGetValue("prompt", out var prompt) || @@ -213,7 +213,7 @@ internal static class Program { throw new McpProtocolException("Missing required arguments 'prompt' and 'maxTokens'", McpErrorCode.InvalidParams); } - var sampleResult = await request.Server.SampleAsync(CreateRequestSamplingParams(prompt.ToString(), "sampleLLM", Convert.ToInt32(maxTokens.GetRawText())), + var sampleResult = await request.Server.SampleAsync(CreateRequestSamplingParams(prompt.ToString(), "trigger-sampling-request", Convert.ToInt32(maxTokens.GetRawText())), cancellationToken: cancellationToken); return new CallToolResult @@ -257,28 +257,48 @@ internal static class Program Prompts = [ new Prompt { - Name = "simple_prompt", + Name = "simple-prompt", Description = "A prompt without arguments" }, new Prompt { - Name = "complex_prompt", + Name = "args-prompt", Description = "A prompt with arguments", Arguments = [ new PromptArgument { - Name = "temperature", - Description = "Temperature setting", + Name = "city", + Description = "Name of the city", Required = true }, new PromptArgument { - Name = "style", - Description = "Output style", + Name = "state", + Description = "Name of the state", Required = false } ] + }, + new Prompt + { + Name = "completable-prompt", + Description = "A prompt with completable arguments", + Arguments = + [ + new PromptArgument + { + Name = "department", + Description = "Choose the department", + Required = true + }, + new PromptArgument + { + Name = "name", + Description = "Choose a team member", + Required = true + } + ] } ] }; @@ -287,7 +307,7 @@ internal static class Program options.Handlers.GetPromptHandler = async (request, cancellationToken) => { List messages = []; - if (request.Params?.Name == "simple_prompt") + if (request.Params?.Name == "simple-prompt") { messages.Add(new PromptMessage { @@ -295,28 +315,25 @@ internal static class Program Content = new TextContentBlock { Text = "This is a simple prompt without arguments." }, }); } - else if (request.Params?.Name == "complex_prompt") + else if (request.Params?.Name == "args-prompt") { - string temperature = request.Params.Arguments?["temperature"].ToString() ?? "unknown"; - string style = request.Params.Arguments?["style"].ToString() ?? "unknown"; + string city = request.Params.Arguments?["city"].ToString() ?? "unknown"; + string state = request.Params.Arguments?["state"].ToString() ?? ""; + string location = !string.IsNullOrEmpty(state) ? $"{city}, {state}" : city; messages.Add(new PromptMessage { Role = Role.User, - Content = new TextContentBlock { Text = $"This is a complex prompt with arguments: temperature={temperature}, style={style}" }, - }); - messages.Add(new PromptMessage - { - Role = Role.Assistant, - Content = new TextContentBlock { Text = "I understand. You've provided a complex prompt with temperature and style arguments. How would you like me to proceed?" }, + Content = new TextContentBlock { Text = $"What's weather in {location}?" }, }); + } + else if (request.Params?.Name == "completable-prompt") + { + string department = request.Params.Arguments?["department"].ToString() ?? "unknown"; + string name = request.Params.Arguments?["name"].ToString() ?? "unknown"; messages.Add(new PromptMessage { Role = Role.User, - Content = new ImageContentBlock - { - Data = MCP_TINY_IMAGE, - MimeType = "image/png" - } + Content = new TextContentBlock { Text = $"Please promote {name} to the head of the {department} team." }, }); } else @@ -516,8 +533,8 @@ internal static class Program List sampleResourceIds = ["1", "2", "3", "4", "5"]; Dictionary> exampleCompletions = new() { - {"style", ["casual", "formal", "technical", "friendly"]}, - {"temperature", ["0", "0.5", "0.7", "1.0"]}, + {"department", ["Engineering", "Sales", "Marketing", "Support"]}, + {"name", ["Alice", "Bob", "Charlie"]}, }; options.Handlers.CompleteHandler = async (request, cancellationToken) => diff --git a/tests/ModelContextProtocol.Tests/ClientIntegrationTestFixture.cs b/tests/ModelContextProtocol.Tests/ClientIntegrationTestFixture.cs index 049d72d..6f0e8e4 100644 --- a/tests/ModelContextProtocol.Tests/ClientIntegrationTestFixture.cs +++ b/tests/ModelContextProtocol.Tests/ClientIntegrationTestFixture.cs @@ -15,7 +15,7 @@ public class ClientIntegrationTestFixture public ClientIntegrationTestFixture() { - const string ServerEverythingVersion = "2025.12.18"; + const string ServerEverythingVersion = "2026.1.26"; EverythingServerTransportOptions = new() { diff --git a/tests/ModelContextProtocol.Tests/ClientIntegrationTests.cs b/tests/ModelContextProtocol.Tests/ClientIntegrationTests.cs index 018e12d..3eba027 100644 --- a/tests/ModelContextProtocol.Tests/ClientIntegrationTests.cs +++ b/tests/ModelContextProtocol.Tests/ClientIntegrationTests.cs @@ -53,11 +53,7 @@ public partial class ClientIntegrationTests : LoggedTest, IClassFixture p.Name == "simple_prompt"); - Assert.Contains(prompts, p => p.Name == "complex_prompt"); + Assert.Contains(prompts, p => p.Name == "simple-prompt"); + Assert.Contains(prompts, p => p.Name == "args-prompt"); } [Theory] @@ -158,7 +154,7 @@ public partial class ClientIntegrationTests : LoggedTest, IClassFixture { - { "temperature", "0.7" }, - { "style", "formal" } + { "city", "Seattle" }, + { "state", "WA" } }; - var result = await client.GetPromptAsync("complex_prompt", arguments, cancellationToken: TestContext.Current.CancellationToken); + var result = await client.GetPromptAsync("args-prompt", arguments, cancellationToken: TestContext.Current.CancellationToken); // assert Assert.NotNull(result); @@ -208,8 +204,8 @@ public partial class ClientIntegrationTests : LoggedTest, IClassFixture allResourceTemplates = await client.ListResourceTemplatesAsync(cancellationToken: TestContext.Current.CancellationToken); - // The server provides a single test resource template - Assert.Single(allResourceTemplates); + // The server provides test resource templates + Assert.NotEmpty(allResourceTemplates); } [Theory] @@ -223,8 +219,8 @@ public partial class ClientIntegrationTests : LoggedTest, IClassFixture allResources = await client.ListResourcesAsync(cancellationToken: TestContext.Current.CancellationToken); - // The server provides 100 test resources - Assert.Equal(100, allResources.Count); + // The server provides test resources + Assert.NotEmpty(allResources); } [Theory] @@ -235,27 +231,29 @@ public partial class ClientIntegrationTests : LoggedTest, IClassFixture r.MimeType?.StartsWith("text/", StringComparison.Ordinal) is true); + var result = await client.ReadResourceAsync(textResource.Uri, null, TestContext.Current.CancellationToken); Assert.NotNull(result); Assert.Single(result.Contents); - TextResourceContents textResource = Assert.IsType(result.Contents[0]); - Assert.NotNull(textResource.Text); + TextResourceContents textContent = Assert.IsType(result.Contents[0]); + Assert.NotNull(textContent.Text); } - [Theory] - [MemberData(nameof(GetClients))] - public async Task ReadResource_Stdio_BinaryResource(string clientId) + // The latest "everything" server only exposes text-based file resources in its resource list; + // binary resources are available via resource templates but not in the listed resources. + [Fact] + public async Task ReadResource_Stdio_BinaryResource() { // arrange + var clientId = "test_server"; // act await using var client = await _fixture.CreateClientAsync(clientId); - // Even numbered resources are binary in the everything server (despite the docs saying otherwise) - // 2 is index 1, which is "odd" in the 0-based index + // Read a binary resource from the test server var result = await client.ReadResourceAsync("test://static/resource/2", null, TestContext.Current.CancellationToken); Assert.NotNull(result); @@ -336,9 +334,11 @@ public partial class ClientIntegrationTests : LoggedTest, IClassFixture { ["prompt"] = "Test prompt", @@ -536,7 +536,7 @@ public partial class ClientIntegrationTests : LoggedTest, IClassFixture() + var result = await client.CallToolAsync("trigger-sampling-request", new Dictionary() { ["prompt"] = "In just a few words, what is the most famous tower in Paris?", }, cancellationToken: TestContext.Current.CancellationToken); @@ -575,6 +575,12 @@ public partial class ClientIntegrationTests : LoggedTest, IClassFixture(), cancellationToken: TestContext.Current.CancellationToken); + } + // assert await receivedNotification.Task; } @@ -602,7 +608,7 @@ public partial class ClientIntegrationTests : LoggedTest, IClassFixture p.Name == "simple_prompt"); + Assert.Contains(result.Prompts, p => p.Name == "simple-prompt"); } [Theory] @@ -612,7 +618,7 @@ public partial class ClientIntegrationTests : LoggedTest, IClassFixture + // Call the server's trigger-sampling-request tool which should trigger our sampling handler + var result = await client.CallToolAsync("trigger-sampling-request", new Dictionary { ["prompt"] = "Test prompt", ["maxTokens"] = 100