diff --git a/src/ModelContextProtocol.Core/Client/McpClient.cs b/src/ModelContextProtocol.Core/Client/McpClient.cs index 28a37f258..8d74aaaf2 100644 --- a/src/ModelContextProtocol.Core/Client/McpClient.cs +++ b/src/ModelContextProtocol.Core/Client/McpClient.cs @@ -7,6 +7,11 @@ namespace ModelContextProtocol.Client; /// public abstract partial class McpClient : McpSession { + /// Initializes a new instance of the class. + private protected McpClient() + { + } + /// /// Gets the capabilities supported by the connected server. /// diff --git a/src/ModelContextProtocol.Core/Server/McpServer.cs b/src/ModelContextProtocol.Core/Server/McpServer.cs index 2d8ea6826..4f8bf9058 100644 --- a/src/ModelContextProtocol.Core/Server/McpServer.cs +++ b/src/ModelContextProtocol.Core/Server/McpServer.cs @@ -7,6 +7,11 @@ namespace ModelContextProtocol.Server; /// public abstract partial class McpServer : McpSession { + /// Initializes a new instance of the class. + private protected McpServer() + { + } + /// /// Gets the capabilities supported by the client. /// diff --git a/tests/Common/Utils/TestServerTransport.cs b/tests/Common/Utils/TestServerTransport.cs index 43cd5c262..0fc2b6b4d 100644 --- a/tests/Common/Utils/TestServerTransport.cs +++ b/tests/Common/Utils/TestServerTransport.cs @@ -93,10 +93,11 @@ await WriteMessageAsync(new JsonRpcResponse else { // Return a normal sampling response + var result = MockSamplingResult ?? new CreateMessageResult { Content = [new TextContentBlock { Text = "" }], Model = "model" }; await WriteMessageAsync(new JsonRpcResponse { Id = request.Id, - Result = JsonSerializer.SerializeToNode(new CreateMessageResult { Content = [new TextContentBlock { Text = "" }], Model = "model" }, McpJsonUtilities.DefaultOptions), + Result = JsonSerializer.SerializeToNode(result, McpJsonUtilities.DefaultOptions), }, cancellationToken); } } @@ -125,6 +126,12 @@ await WriteMessageAsync(new JsonRpcResponse } } + /// + /// Gets or sets the sampling result to return from sampling/createMessage requests. + /// When null, a default sampling response is returned. + /// + public CreateMessageResult? MockSamplingResult { get; set; } + /// /// Gets or sets the task to return from tasks/get requests. /// diff --git a/tests/ModelContextProtocol.Tests/Configuration/McpServerBuilderExtensionsPromptsTests.cs b/tests/ModelContextProtocol.Tests/Configuration/McpServerBuilderExtensionsPromptsTests.cs index 69405e16c..f8fde1387 100644 --- a/tests/ModelContextProtocol.Tests/Configuration/McpServerBuilderExtensionsPromptsTests.cs +++ b/tests/ModelContextProtocol.Tests/Configuration/McpServerBuilderExtensionsPromptsTests.cs @@ -5,7 +5,7 @@ using ModelContextProtocol.Client; using ModelContextProtocol.Protocol; using ModelContextProtocol.Server; -using Moq; +using ModelContextProtocol.Tests.Utils; using System.Collections; using System.ComponentModel; using System.Text.Json; @@ -314,7 +314,7 @@ public async Task WithPrompts_TargetInstance_UsesTarget() sc.AddMcpServer().WithPrompts(target); McpServerPrompt prompt = sc.BuildServiceProvider().GetServices().First(t => t.ProtocolPrompt.Name == "returns_string"); - var result = await prompt.GetAsync(new RequestContext(new Mock().Object, new JsonRpcRequest { Method = "test", Id = new RequestId("1") }) + var result = await prompt.GetAsync(new RequestContext(McpServer.Create(new TestServerTransport(), new McpServerOptions()), new JsonRpcRequest { Method = "test", Id = new RequestId("1") }) { Params = new GetPromptRequestParams { diff --git a/tests/ModelContextProtocol.Tests/Configuration/McpServerBuilderExtensionsResourcesTests.cs b/tests/ModelContextProtocol.Tests/Configuration/McpServerBuilderExtensionsResourcesTests.cs index 545384a7c..b066f7d5a 100644 --- a/tests/ModelContextProtocol.Tests/Configuration/McpServerBuilderExtensionsResourcesTests.cs +++ b/tests/ModelContextProtocol.Tests/Configuration/McpServerBuilderExtensionsResourcesTests.cs @@ -5,7 +5,7 @@ using ModelContextProtocol.Client; using ModelContextProtocol.Protocol; using ModelContextProtocol.Server; -using Moq; +using ModelContextProtocol.Tests.Utils; using System.Collections; using System.ComponentModel; using System.Threading.Channels; @@ -345,7 +345,7 @@ public async Task WithResources_TargetInstance_UsesTarget() sc.AddMcpServer().WithResources(target); McpServerResource resource = sc.BuildServiceProvider().GetServices().First(t => t.ProtocolResource?.Name == "returns_string"); - var result = await resource.ReadAsync(new RequestContext(new Mock().Object, new JsonRpcRequest { Method = "test", Id = new RequestId("1") }) + var result = await resource.ReadAsync(new RequestContext(McpServer.Create(new TestServerTransport(), new McpServerOptions()), new JsonRpcRequest { Method = "test", Id = new RequestId("1") }) { Params = new() { diff --git a/tests/ModelContextProtocol.Tests/Configuration/McpServerBuilderExtensionsToolsTests.cs b/tests/ModelContextProtocol.Tests/Configuration/McpServerBuilderExtensionsToolsTests.cs index 518b70f00..b3abb111f 100644 --- a/tests/ModelContextProtocol.Tests/Configuration/McpServerBuilderExtensionsToolsTests.cs +++ b/tests/ModelContextProtocol.Tests/Configuration/McpServerBuilderExtensionsToolsTests.cs @@ -5,7 +5,7 @@ using ModelContextProtocol.Client; using ModelContextProtocol.Protocol; using ModelContextProtocol.Server; -using Moq; +using ModelContextProtocol.Tests.Utils; using System.Collections; using System.Collections.Concurrent; using System.ComponentModel; @@ -594,7 +594,7 @@ public async Task WithTools_TargetInstance_UsesTarget() sc.AddMcpServer().WithTools(target, BuilderToolsJsonContext.Default.Options); McpServerTool tool = sc.BuildServiceProvider().GetServices().First(t => t.ProtocolTool.Name == "get_ctor_parameter"); - var result = await tool.InvokeAsync(new RequestContext(new Mock().Object, new JsonRpcRequest { Method = "test", Id = new RequestId("1") }), TestContext.Current.CancellationToken); + var result = await tool.InvokeAsync(new RequestContext(McpServer.Create(new TestServerTransport(), new McpServerOptions()), new JsonRpcRequest { Method = "test", Id = new RequestId("1") }), TestContext.Current.CancellationToken); Assert.Equal(target.GetCtorParameter(), (result.Content[0] as TextContentBlock)?.Text); } diff --git a/tests/ModelContextProtocol.Tests/Server/McpServerPromptTests.cs b/tests/ModelContextProtocol.Tests/Server/McpServerPromptTests.cs index b463514f9..ae6178109 100644 --- a/tests/ModelContextProtocol.Tests/Server/McpServerPromptTests.cs +++ b/tests/ModelContextProtocol.Tests/Server/McpServerPromptTests.cs @@ -2,7 +2,7 @@ using Microsoft.Extensions.DependencyInjection; using ModelContextProtocol.Protocol; using ModelContextProtocol.Server; -using Moq; +using ModelContextProtocol.Tests.Utils; using System.ComponentModel; using System.Reflection; using System.Runtime.InteropServices; @@ -13,6 +13,9 @@ namespace ModelContextProtocol.Tests.Server; public class McpServerPromptTests { + private static McpServer CreateTestServer(IServiceProvider? services = null) => + McpServer.Create(new TestServerTransport(), new McpServerOptions(), serviceProvider: services); + private static JsonRpcRequest CreateTestJsonRpcRequest() { return new JsonRpcRequest @@ -43,18 +46,18 @@ public void Create_InvalidArgs_Throws() [Fact] public async Task SupportsMcpServer() { - Mock mockServer = new(); + McpServer testServer = CreateTestServer(); McpServerPrompt prompt = McpServerPrompt.Create((McpServer server) => { - Assert.Same(mockServer.Object, server); + Assert.Same(testServer, server); return new ChatMessage(ChatRole.User, "Hello"); }); Assert.DoesNotContain("server", prompt.ProtocolPrompt.Arguments?.Select(a => a.Name) ?? []); var result = await prompt.GetAsync( - new RequestContext(mockServer.Object, CreateTestJsonRpcRequest()), + new RequestContext(testServer, CreateTestJsonRpcRequest()), TestContext.Current.CancellationToken); Assert.NotNull(result); Assert.NotNull(result.Messages); @@ -71,8 +74,7 @@ public async Task SupportsCtorInjection() sc.AddSingleton(expectedMyService); IServiceProvider services = sc.BuildServiceProvider(); - Mock mockServer = new(); - mockServer.SetupGet(s => s.Services).Returns(services); + McpServer server = CreateTestServer(services); MethodInfo? testMethod = typeof(HasCtorWithSpecialParameters).GetMethod(nameof(HasCtorWithSpecialParameters.TestPrompt)); Assert.NotNull(testMethod); @@ -83,7 +85,7 @@ public async Task SupportsCtorInjection() }, new() { Services = services }); var result = await prompt.GetAsync( - new RequestContext(mockServer.Object, CreateTestJsonRpcRequest()), + new RequestContext(server, CreateTestJsonRpcRequest()), TestContext.Current.CancellationToken); Assert.NotNull(result); Assert.NotNull(result.Messages); @@ -133,11 +135,11 @@ public async Task SupportsServiceFromDI() Assert.DoesNotContain("actualMyService", prompt.ProtocolPrompt.Arguments?.Select(a => a.Name) ?? []); await Assert.ThrowsAnyAsync(async () => await prompt.GetAsync( - new RequestContext(new Mock().Object, CreateTestJsonRpcRequest()), + new RequestContext(CreateTestServer(), CreateTestJsonRpcRequest()), TestContext.Current.CancellationToken)); var result = await prompt.GetAsync( - new RequestContext(new Mock().Object, CreateTestJsonRpcRequest()) { Services = services }, + new RequestContext(CreateTestServer(), CreateTestJsonRpcRequest()) { Services = services }, TestContext.Current.CancellationToken); Assert.Equal("Hello", Assert.IsType(result.Messages[0].Content).Text); } @@ -158,7 +160,7 @@ public async Task SupportsOptionalServiceFromDI() }, new() { Services = services }); var result = await prompt.GetAsync( - new RequestContext(new Mock().Object, CreateTestJsonRpcRequest()), + new RequestContext(CreateTestServer(), CreateTestJsonRpcRequest()), TestContext.Current.CancellationToken); Assert.Equal("Hello", Assert.IsType(result.Messages[0].Content).Text); } @@ -171,7 +173,7 @@ public async Task SupportsDisposingInstantiatedDisposableTargets() _ => new DisposablePromptType()); var result = await prompt1.GetAsync( - new RequestContext(new Mock().Object, CreateTestJsonRpcRequest()), + new RequestContext(CreateTestServer(), CreateTestJsonRpcRequest()), TestContext.Current.CancellationToken); Assert.Equal("disposals:1", Assert.IsType(result.Messages[0].Content).Text); } @@ -184,7 +186,7 @@ public async Task SupportsAsyncDisposingInstantiatedAsyncDisposableTargets() _ => new AsyncDisposablePromptType()); var result = await prompt1.GetAsync( - new RequestContext(new Mock().Object, CreateTestJsonRpcRequest()), + new RequestContext(CreateTestServer(), CreateTestJsonRpcRequest()), TestContext.Current.CancellationToken); Assert.Equal("asyncDisposals:1", Assert.IsType(result.Messages[0].Content).Text); } @@ -197,7 +199,7 @@ public async Task SupportsAsyncDisposingInstantiatedAsyncDisposableAndDisposable _ => new AsyncDisposableAndDisposablePromptType()); var result = await prompt1.GetAsync( - new RequestContext(new Mock().Object, CreateTestJsonRpcRequest()), + new RequestContext(CreateTestServer(), CreateTestJsonRpcRequest()), TestContext.Current.CancellationToken); Assert.Equal("disposals:0, asyncDisposals:1", Assert.IsType(result.Messages[0].Content).Text); } @@ -213,7 +215,7 @@ public async Task CanReturnGetPromptResult() }); var actual = await prompt.GetAsync( - new RequestContext(new Mock().Object, CreateTestJsonRpcRequest()), + new RequestContext(CreateTestServer(), CreateTestJsonRpcRequest()), TestContext.Current.CancellationToken); Assert.Same(expected, actual); @@ -230,7 +232,7 @@ public async Task CanReturnText() }); var actual = await prompt.GetAsync( - new RequestContext(new Mock().Object, CreateTestJsonRpcRequest()), + new RequestContext(CreateTestServer(), CreateTestJsonRpcRequest()), TestContext.Current.CancellationToken); Assert.NotNull(actual); @@ -256,7 +258,7 @@ public async Task CanReturnPromptMessage() }); var actual = await prompt.GetAsync( - new RequestContext(new Mock().Object, CreateTestJsonRpcRequest()), + new RequestContext(CreateTestServer(), CreateTestJsonRpcRequest()), TestContext.Current.CancellationToken); Assert.NotNull(actual); @@ -288,7 +290,7 @@ public async Task CanReturnPromptMessages() }); var actual = await prompt.GetAsync( - new RequestContext(new Mock().Object, CreateTestJsonRpcRequest()), + new RequestContext(CreateTestServer(), CreateTestJsonRpcRequest()), TestContext.Current.CancellationToken); Assert.NotNull(actual); @@ -315,7 +317,7 @@ public async Task CanReturnChatMessage() }); var actual = await prompt.GetAsync( - new RequestContext(new Mock().Object, CreateTestJsonRpcRequest()), + new RequestContext(CreateTestServer(), CreateTestJsonRpcRequest()), TestContext.Current.CancellationToken); Assert.NotNull(actual); @@ -347,7 +349,7 @@ public async Task CanReturnChatMessages() }); var actual = await prompt.GetAsync( - new RequestContext(new Mock().Object, CreateTestJsonRpcRequest()), + new RequestContext(CreateTestServer(), CreateTestJsonRpcRequest()), TestContext.Current.CancellationToken); Assert.NotNull(actual); @@ -368,7 +370,7 @@ public async Task ThrowsForNullReturn() }); await Assert.ThrowsAsync(async () => await prompt.GetAsync( - new RequestContext(new Mock().Object, CreateTestJsonRpcRequest()), + new RequestContext(CreateTestServer(), CreateTestJsonRpcRequest()), TestContext.Current.CancellationToken)); } @@ -381,7 +383,7 @@ public async Task ThrowsForUnexpectedTypeReturn() }); await Assert.ThrowsAsync(async () => await prompt.GetAsync( - new RequestContext(new Mock().Object, CreateTestJsonRpcRequest()), + new RequestContext(CreateTestServer(), CreateTestJsonRpcRequest()), TestContext.Current.CancellationToken)); } diff --git a/tests/ModelContextProtocol.Tests/Server/McpServerResourceTests.cs b/tests/ModelContextProtocol.Tests/Server/McpServerResourceTests.cs index 695bbf39d..99851b4ec 100644 --- a/tests/ModelContextProtocol.Tests/Server/McpServerResourceTests.cs +++ b/tests/ModelContextProtocol.Tests/Server/McpServerResourceTests.cs @@ -2,7 +2,7 @@ using Microsoft.Extensions.DependencyInjection; using ModelContextProtocol.Protocol; using ModelContextProtocol.Server; -using Moq; +using ModelContextProtocol.Tests.Utils; using System.Reflection; using System.Runtime.InteropServices; using System.Text.Json.Serialization; @@ -21,6 +21,9 @@ private static JsonRpcRequest CreateTestJsonRpcRequest() }; } + private static McpServer CreateTestServer(IServiceProvider? services = null) => + McpServer.Create(new TestServerTransport(), new McpServerOptions(), serviceProvider: services); + public McpServerResourceTests() { #if !NET @@ -143,7 +146,7 @@ public async Task UriTemplate_CreatedFromParameters_LotsOfTypesSupported() McpServerResource t; ReadResourceResult result; - McpServer server = new Mock().Object; + McpServer server = CreateTestServer(); t = McpServerResource.Create(() => "42", new() { Name = Name }); Assert.Equal("resource://mcp/Hello", t.ProtocolResourceTemplate.UriTemplate); @@ -288,7 +291,7 @@ public async Task UriTemplate_NonMatchingUri_DoesNotMatch(string uri) Assert.Equal("resource://mcp/Hello{?arg1}", t.ProtocolResourceTemplate.UriTemplate); Assert.False(t.IsMatch(uri)); await Assert.ThrowsAsync(async () => await t.ReadAsync( - new RequestContext(new Mock().Object, CreateTestJsonRpcRequest()) { Params = new() { Uri = uri } }, + new RequestContext(CreateTestServer(), CreateTestJsonRpcRequest()) { Params = new() { Uri = uri } }, TestContext.Current.CancellationToken)); } @@ -299,7 +302,7 @@ public async Task UriTemplate_IsHostCaseInsensitive(string actualUri, string que { McpServerResource t = McpServerResource.Create(() => "resource", new() { UriTemplate = actualUri }); Assert.NotNull(await t.ReadAsync( - new RequestContext(new Mock().Object, CreateTestJsonRpcRequest()) { Params = new() { Uri = queriedUri } }, + new RequestContext(CreateTestServer(), CreateTestJsonRpcRequest()) { Params = new() { Uri = queriedUri } }, TestContext.Current.CancellationToken)); } @@ -328,7 +331,7 @@ public async Task UriTemplate_MissingParameter_Throws(string uri) McpServerResource t = McpServerResource.Create((string arg1, int arg2) => arg1, new() { Name = "Hello" }); Assert.Equal("resource://mcp/Hello{?arg1,arg2}", t.ProtocolResourceTemplate.UriTemplate); await Assert.ThrowsAsync(async () => await t.ReadAsync( - new RequestContext(new Mock().Object, CreateTestJsonRpcRequest()) { Params = new() { Uri = uri } }, + new RequestContext(CreateTestServer(), CreateTestJsonRpcRequest()) { Params = new() { Uri = uri } }, TestContext.Current.CancellationToken)); } @@ -341,25 +344,25 @@ public async Task UriTemplate_MissingOptionalParameter_Succeeds() ReadResourceResult result; result = await t.ReadAsync( - new RequestContext(new Mock().Object, CreateTestJsonRpcRequest()) { Params = new() { Uri = "resource://mcp/Hello" } }, + new RequestContext(CreateTestServer(), CreateTestJsonRpcRequest()) { Params = new() { Uri = "resource://mcp/Hello" } }, TestContext.Current.CancellationToken); Assert.NotNull(result); Assert.Equal("", ((TextResourceContents)result.Contents[0]).Text); result = await t.ReadAsync( - new RequestContext(new Mock().Object, CreateTestJsonRpcRequest()) { Params = new() { Uri = "resource://mcp/Hello?arg1=first" } }, + new RequestContext(CreateTestServer(), CreateTestJsonRpcRequest()) { Params = new() { Uri = "resource://mcp/Hello?arg1=first" } }, TestContext.Current.CancellationToken); Assert.NotNull(result); Assert.Equal("first", ((TextResourceContents)result.Contents[0]).Text); result = await t.ReadAsync( - new RequestContext(new Mock().Object, CreateTestJsonRpcRequest()) { Params = new() { Uri = "resource://mcp/Hello?arg2=42" } }, + new RequestContext(CreateTestServer(), CreateTestJsonRpcRequest()) { Params = new() { Uri = "resource://mcp/Hello?arg2=42" } }, TestContext.Current.CancellationToken); Assert.NotNull(result); Assert.Equal("42", ((TextResourceContents)result.Contents[0]).Text); result = await t.ReadAsync( - new RequestContext(new Mock().Object, CreateTestJsonRpcRequest()) { Params = new() { Uri = "resource://mcp/Hello?arg1=first&arg2=42" } }, + new RequestContext(CreateTestServer(), CreateTestJsonRpcRequest()) { Params = new() { Uri = "resource://mcp/Hello?arg1=first&arg2=42" } }, TestContext.Current.CancellationToken); Assert.NotNull(result); Assert.Equal("first42", ((TextResourceContents)result.Contents[0]).Text); @@ -368,16 +371,16 @@ public async Task UriTemplate_MissingOptionalParameter_Succeeds() [Fact] public async Task SupportsMcpServer() { - Mock mockServer = new(); + McpServer testServer = CreateTestServer(); McpServerResource resource = McpServerResource.Create((McpServer server) => { - Assert.Same(mockServer.Object, server); + Assert.Same(testServer, server); return "42"; }, new() { Name = "Test" }); var result = await resource.ReadAsync( - new RequestContext(mockServer.Object, CreateTestJsonRpcRequest()) { Params = new() { Uri = "resource://mcp/Test" } }, + new RequestContext(testServer, CreateTestJsonRpcRequest()) { Params = new() { Uri = "resource://mcp/Test" } }, TestContext.Current.CancellationToken); Assert.NotNull(result); Assert.Equal("42", ((TextResourceContents)result.Contents[0]).Text); @@ -392,8 +395,7 @@ public async Task SupportsCtorInjection() sc.AddSingleton(expectedMyService); IServiceProvider services = sc.BuildServiceProvider(); - Mock mockServer = new(); - mockServer.SetupGet(s => s.Services).Returns(services); + McpServer testServer = CreateTestServer(services); MethodInfo? testMethod = typeof(HasCtorWithSpecialParameters).GetMethod(nameof(HasCtorWithSpecialParameters.TestResource)); Assert.NotNull(testMethod); @@ -404,7 +406,7 @@ public async Task SupportsCtorInjection() }, new() { Services = services }); var result = await tool.ReadAsync( - new RequestContext(mockServer.Object, CreateTestJsonRpcRequest()) { Params = new() { Uri = "https://something" } }, + new RequestContext(testServer, CreateTestJsonRpcRequest()) { Params = new() { Uri = "https://something" } }, TestContext.Current.CancellationToken); Assert.NotNull(result); Assert.NotNull(result.Contents); @@ -478,14 +480,14 @@ public async Task SupportsServiceFromDI(ServiceLifetime injectedArgumentLifetime McpServerResource resource = services.GetRequiredService(); - Mock mockServer = new(); + McpServer testServer = CreateTestServer(); await Assert.ThrowsAnyAsync(async () => await resource.ReadAsync( - new RequestContext(mockServer.Object, CreateTestJsonRpcRequest()) { Params = new() { Uri = "resource://mcp/Test" } }, + new RequestContext(testServer, CreateTestJsonRpcRequest()) { Params = new() { Uri = "resource://mcp/Test" } }, TestContext.Current.CancellationToken)); var result = await resource.ReadAsync( - new RequestContext(mockServer.Object, CreateTestJsonRpcRequest()) { Services = services, Params = new() { Uri = "resource://mcp/Test" } }, + new RequestContext(testServer, CreateTestJsonRpcRequest()) { Services = services, Params = new() { Uri = "resource://mcp/Test" } }, TestContext.Current.CancellationToken); Assert.NotNull(result); Assert.Equal("42", ((TextResourceContents)result.Contents[0]).Text); @@ -507,7 +509,7 @@ public async Task SupportsOptionalServiceFromDI() }, new() { Services = services, Name = "Test" }); var result = await resource.ReadAsync( - new RequestContext(new Mock().Object, CreateTestJsonRpcRequest()) { Params = new() { Uri = "resource://mcp/Test" } }, + new RequestContext(CreateTestServer(), CreateTestJsonRpcRequest()) { Params = new() { Uri = "resource://mcp/Test" } }, TestContext.Current.CancellationToken); Assert.NotNull(result); Assert.Equal("42", ((TextResourceContents)result.Contents[0]).Text); @@ -523,7 +525,7 @@ public async Task SupportsDisposingInstantiatedDisposableTargets() _ => new DisposableResourceType()); var result = await resource1.ReadAsync( - new RequestContext(new Mock().Object, CreateTestJsonRpcRequest()) { Params = new() { Uri = "test://static/resource/instanceMethod" } }, + new RequestContext(CreateTestServer(), CreateTestJsonRpcRequest()) { Params = new() { Uri = "test://static/resource/instanceMethod" } }, TestContext.Current.CancellationToken); Assert.NotNull(result); Assert.Equal("0", ((TextResourceContents)result.Contents[0]).Text); @@ -534,14 +536,14 @@ public async Task SupportsDisposingInstantiatedDisposableTargets() [Fact] public async Task CanReturnReadResult() { - Mock mockServer = new(); + McpServer testServer = CreateTestServer(); McpServerResource resource = McpServerResource.Create((McpServer server) => { - Assert.Same(mockServer.Object, server); + Assert.Same(testServer, server); return new ReadResourceResult { Contents = [new TextResourceContents { Text = "hello", Uri = "" }] }; }, new() { Name = "Test" }); var result = await resource.ReadAsync( - new RequestContext(mockServer.Object, CreateTestJsonRpcRequest()) { Params = new() { Uri = "resource://mcp/Test" } }, + new RequestContext(testServer, CreateTestJsonRpcRequest()) { Params = new() { Uri = "resource://mcp/Test" } }, TestContext.Current.CancellationToken); Assert.NotNull(result); Assert.Single(result.Contents); @@ -551,14 +553,14 @@ public async Task CanReturnReadResult() [Fact] public async Task CanReturnResourceContents() { - Mock mockServer = new(); + McpServer testServer = CreateTestServer(); McpServerResource resource = McpServerResource.Create((McpServer server) => { - Assert.Same(mockServer.Object, server); + Assert.Same(testServer, server); return new TextResourceContents { Text = "hello", Uri = "" }; }, new() { Name = "Test", SerializerOptions = JsonContext6.Default.Options }); var result = await resource.ReadAsync( - new RequestContext(mockServer.Object, CreateTestJsonRpcRequest()) { Params = new() { Uri = "resource://mcp/Test" } }, + new RequestContext(testServer, CreateTestJsonRpcRequest()) { Params = new() { Uri = "resource://mcp/Test" } }, TestContext.Current.CancellationToken); Assert.NotNull(result); Assert.Single(result.Contents); @@ -568,10 +570,10 @@ public async Task CanReturnResourceContents() [Fact] public async Task CanReturnCollectionOfResourceContents() { - Mock mockServer = new(); + McpServer testServer = CreateTestServer(); McpServerResource resource = McpServerResource.Create((McpServer server) => { - Assert.Same(mockServer.Object, server); + Assert.Same(testServer, server); return (IList) [ new TextResourceContents { Text = "hello", Uri = "" }, @@ -579,7 +581,7 @@ public async Task CanReturnCollectionOfResourceContents() ]; }, new() { Name = "Test" }); var result = await resource.ReadAsync( - new RequestContext(mockServer.Object, CreateTestJsonRpcRequest()) { Params = new() { Uri = "resource://mcp/Test" } }, + new RequestContext(testServer, CreateTestJsonRpcRequest()) { Params = new() { Uri = "resource://mcp/Test" } }, TestContext.Current.CancellationToken); Assert.NotNull(result); Assert.Equal(2, result.Contents.Count); @@ -590,14 +592,14 @@ public async Task CanReturnCollectionOfResourceContents() [Fact] public async Task CanReturnString() { - Mock mockServer = new(); + McpServer testServer = CreateTestServer(); McpServerResource resource = McpServerResource.Create((McpServer server) => { - Assert.Same(mockServer.Object, server); + Assert.Same(testServer, server); return "42"; }, new() { Name = "Test" }); var result = await resource.ReadAsync( - new RequestContext(mockServer.Object, CreateTestJsonRpcRequest()) { Params = new() { Uri = "resource://mcp/Test" } }, + new RequestContext(testServer, CreateTestJsonRpcRequest()) { Params = new() { Uri = "resource://mcp/Test" } }, TestContext.Current.CancellationToken); Assert.NotNull(result); Assert.Single(result.Contents); @@ -607,14 +609,14 @@ public async Task CanReturnString() [Fact] public async Task CanReturnCollectionOfStrings() { - Mock mockServer = new(); + McpServer testServer = CreateTestServer(); McpServerResource resource = McpServerResource.Create((McpServer server) => { - Assert.Same(mockServer.Object, server); + Assert.Same(testServer, server); return new List { "42", "43" }; }, new() { Name = "Test", SerializerOptions = JsonContext6.Default.Options }); var result = await resource.ReadAsync( - new RequestContext(mockServer.Object, CreateTestJsonRpcRequest()) { Params = new() { Uri = "resource://mcp/Test" } }, + new RequestContext(testServer, CreateTestJsonRpcRequest()) { Params = new() { Uri = "resource://mcp/Test" } }, TestContext.Current.CancellationToken); Assert.NotNull(result); Assert.Equal(2, result.Contents.Count); @@ -625,14 +627,14 @@ public async Task CanReturnCollectionOfStrings() [Fact] public async Task CanReturnDataContent() { - Mock mockServer = new(); + McpServer testServer = CreateTestServer(); McpServerResource resource = McpServerResource.Create((McpServer server) => { - Assert.Same(mockServer.Object, server); + Assert.Same(testServer, server); return new DataContent(new byte[] { 0, 1, 2 }, "application/octet-stream"); }, new() { Name = "Test" }); var result = await resource.ReadAsync( - new RequestContext(mockServer.Object, CreateTestJsonRpcRequest()) { Params = new() { Uri = "resource://mcp/Test" } }, + new RequestContext(testServer, CreateTestJsonRpcRequest()) { Params = new() { Uri = "resource://mcp/Test" } }, TestContext.Current.CancellationToken); Assert.NotNull(result); Assert.Single(result.Contents); @@ -643,10 +645,10 @@ public async Task CanReturnDataContent() [Fact] public async Task CanReturnCollectionOfAIContent() { - Mock mockServer = new(); + McpServer testServer = CreateTestServer(); McpServerResource resource = McpServerResource.Create((McpServer server) => { - Assert.Same(mockServer.Object, server); + Assert.Same(testServer, server); return new List { new TextContent("hello!"), @@ -654,7 +656,7 @@ public async Task CanReturnCollectionOfAIContent() }; }, new() { Name = "Test", SerializerOptions = JsonContext6.Default.Options }); var result = await resource.ReadAsync( - new RequestContext(mockServer.Object, CreateTestJsonRpcRequest()) { Params = new() { Uri = "resource://mcp/Test" } }, + new RequestContext(testServer, CreateTestJsonRpcRequest()) { Params = new() { Uri = "resource://mcp/Test" } }, TestContext.Current.CancellationToken); Assert.NotNull(result); Assert.Equal(2, result.Contents.Count); diff --git a/tests/ModelContextProtocol.Tests/Server/McpServerTests.cs b/tests/ModelContextProtocol.Tests/Server/McpServerTests.cs index 637162962..a10558036 100644 --- a/tests/ModelContextProtocol.Tests/Server/McpServerTests.cs +++ b/tests/ModelContextProtocol.Tests/Server/McpServerTests.cs @@ -807,7 +807,8 @@ private async Task Succeeds_Even_If_No_Handler_Assigned(ServerCapabilities serve [Fact] public async Task AsSamplingChatClient_NoSamplingSupport_Throws() { - await using var server = new TestServerForIChatClient(supportsSampling: false); + await using var transport = new TestServerTransport(); + await using var server = McpServer.Create(transport, _options, LoggerFactory); Assert.Throws(() => server.AsSamplingChatClient()); } @@ -815,7 +816,27 @@ public async Task AsSamplingChatClient_NoSamplingSupport_Throws() [Fact] public async Task AsSamplingChatClient_HandlesRequestResponse() { - await using var server = new TestServerForIChatClient(supportsSampling: true); + await using var transport = new TestServerTransport(); + transport.MockSamplingResult = new CreateMessageResult + { + Content = [new TextContentBlock { Text = "The Eiffel Tower." }], + Model = "amazingmodel", + Role = Role.Assistant, + StopReason = "endTurn", + }; + await using var server = McpServer.Create(transport, _options, LoggerFactory); + var runTask = server.RunAsync(TestContext.Current.CancellationToken); + await InitializeServerAsync(transport, new ClientCapabilities { Sampling = new SamplingCapability() }, TestContext.Current.CancellationToken); + + // Capture the sampling request for validation + CreateMessageRequestParams? capturedParams = null; + transport.OnMessageSent = (message) => + { + if (message is JsonRpcRequest request && request.Method == RequestMethods.SamplingCreateMessage) + { + capturedParams = JsonSerializer.Deserialize(request.Params, McpJsonUtilities.DefaultOptions); + } + }; IChatClient client = server.AsSamplingChatClient(); @@ -839,6 +860,22 @@ public async Task AsSamplingChatClient_HandlesRequestResponse() Assert.Single(response.Messages); Assert.Equal("The Eiffel Tower.", response.Text); Assert.Equal(ChatRole.Assistant, response.Messages[0].Role); + + // Validate the request parameters + Assert.NotNull(capturedParams); + Assert.Equal(0.75f, capturedParams.Temperature); + Assert.Equal(42, capturedParams.MaxTokens); + Assert.Equal(["."], capturedParams.StopSequences); + Assert.Null(capturedParams.IncludeContext); + Assert.Null(capturedParams.Metadata); + Assert.Null(capturedParams.ModelPreferences); + Assert.Equal($"You are a helpful assistant.{Environment.NewLine}More system stuff.", capturedParams.SystemPrompt); + Assert.Equal(2, capturedParams.Messages.Count); + Assert.Equal("I am going to France.", Assert.IsType(Assert.Single(capturedParams.Messages[0].Content)).Text); + Assert.Equal("What is the most famous tower in Paris?", Assert.IsType(Assert.Single(capturedParams.Messages[1].Content)).Text); + + await transport.DisposeAsync(); + await runTask; } [Fact] @@ -890,62 +927,6 @@ private static async Task InitializeServerAsync(TestServerTransport transport, C await tcs.Task.WaitAsync(TestConstants.DefaultTimeout, cancellationToken); } - private sealed class TestServerForIChatClient(bool supportsSampling) : McpServer - { - public override ClientCapabilities? ClientCapabilities => - supportsSampling ? new ClientCapabilities { Sampling = new SamplingCapability() } : - null; - - public override McpServerOptions ServerOptions => new(); - - public override Task SendRequestAsync(JsonRpcRequest request, CancellationToken cancellationToken) - { - CreateMessageRequestParams? rp = JsonSerializer.Deserialize(request.Params, McpJsonUtilities.DefaultOptions); - - Assert.NotNull(rp); - Assert.Equal(0.75f, rp.Temperature); - Assert.Equal(42, rp.MaxTokens); - Assert.Equal(["."], rp.StopSequences); - Assert.Null(rp.IncludeContext); - Assert.Null(rp.Metadata); - Assert.Null(rp.ModelPreferences); - - Assert.Equal($"You are a helpful assistant.{Environment.NewLine}More system stuff.", rp.SystemPrompt); - - Assert.Equal(2, rp.Messages.Count); - Assert.Equal("I am going to France.", Assert.IsType(Assert.Single(rp.Messages[0].Content)).Text); - Assert.Equal("What is the most famous tower in Paris?", Assert.IsType(Assert.Single(rp.Messages[1].Content)).Text); - - CreateMessageResult result = new() - { - Content = [new TextContentBlock { Text = "The Eiffel Tower." }], - Model = "amazingmodel", - Role = Role.Assistant, - StopReason = "endTurn", - }; - - return Task.FromResult(new JsonRpcResponse - { - Id = new RequestId("0"), - Result = JsonSerializer.SerializeToNode(result, McpJsonUtilities.DefaultOptions), - }); - } - - public override ValueTask DisposeAsync() => default; - - public override string? SessionId => throw new NotImplementedException(); - public override string? NegotiatedProtocolVersion => throw new NotImplementedException(); - public override Implementation? ClientInfo => throw new NotImplementedException(); - public override IServiceProvider? Services => throw new NotImplementedException(); - public override LoggingLevel? LoggingLevel => throw new NotImplementedException(); - public override Task SendMessageAsync(JsonRpcMessage message, CancellationToken cancellationToken = default) => - throw new NotImplementedException(); - public override Task RunAsync(CancellationToken cancellationToken = default) => - throw new NotImplementedException(); - public override IAsyncDisposable RegisterNotificationHandler(string method, Func handler) => - throw new NotImplementedException(); - } - [Fact] public async Task NotifyProgress_Should_Be_Handled() { diff --git a/tests/ModelContextProtocol.Tests/Server/McpServerToolTests.cs b/tests/ModelContextProtocol.Tests/Server/McpServerToolTests.cs index 552eaed72..7634862d4 100644 --- a/tests/ModelContextProtocol.Tests/Server/McpServerToolTests.cs +++ b/tests/ModelContextProtocol.Tests/Server/McpServerToolTests.cs @@ -3,7 +3,7 @@ using Microsoft.Extensions.DependencyInjection; using ModelContextProtocol.Protocol; using ModelContextProtocol.Server; -using Moq; +using ModelContextProtocol.Tests.Utils; using System.ComponentModel; using System.Reflection; using System.Runtime.InteropServices; @@ -27,6 +27,9 @@ private static JsonRpcRequest CreateTestJsonRpcRequest() }; } + private static McpServer CreateTestServer(IServiceProvider? services = null) => + McpServer.Create(new TestServerTransport(), new McpServerOptions(), serviceProvider: services); + public McpServerToolTests() { #if !NET @@ -51,18 +54,18 @@ public void Create_InvalidArgs_Throws() [Fact] public async Task SupportsMcpServer() { - Mock mockServer = new(); + McpServer testServer = CreateTestServer(); McpServerTool tool = McpServerTool.Create((McpServer server) => { - Assert.Same(mockServer.Object, server); + Assert.Same(testServer, server); return "42"; }); Assert.DoesNotContain("server", JsonSerializer.Serialize(tool.ProtocolTool.InputSchema, McpJsonUtilities.DefaultOptions)); var result = await tool.InvokeAsync( - new RequestContext(mockServer.Object, CreateTestJsonRpcRequest()), + new RequestContext(testServer, CreateTestJsonRpcRequest()), TestContext.Current.CancellationToken); Assert.Equal("42", (result.Content[0] as TextContentBlock)?.Text); } @@ -76,8 +79,7 @@ public async Task SupportsCtorInjection() sc.AddSingleton(expectedMyService); IServiceProvider services = sc.BuildServiceProvider(); - Mock mockServer = new(); - mockServer.SetupGet(s => s.Services).Returns(services); + McpServer server = CreateTestServer(services); MethodInfo? testMethod = typeof(HasCtorWithSpecialParameters).GetMethod(nameof(HasCtorWithSpecialParameters.TestTool)); Assert.NotNull(testMethod); @@ -88,7 +90,7 @@ public async Task SupportsCtorInjection() }, new() { Services = services }); var result = await tool.InvokeAsync( - new RequestContext(mockServer.Object, CreateTestJsonRpcRequest()), + new RequestContext(server, CreateTestJsonRpcRequest()), TestContext.Current.CancellationToken); Assert.NotNull(result); Assert.NotNull(result.Content); @@ -163,16 +165,16 @@ public async Task SupportsServiceFromDI(ServiceLifetime injectedArgumentLifetime Assert.DoesNotContain("actualMyService", JsonSerializer.Serialize(tool.ProtocolTool.InputSchema, McpJsonUtilities.DefaultOptions)); - Mock mockServer = new(); + McpServer server = CreateTestServer(); var ex = await Assert.ThrowsAsync(async () => await tool.InvokeAsync( - new RequestContext(mockServer.Object, CreateTestJsonRpcRequest()), + new RequestContext(server, CreateTestJsonRpcRequest()), TestContext.Current.CancellationToken)); - mockServer.SetupGet(s => s.Services).Returns(services); + McpServer serverWithServices = CreateTestServer(services); var result = await tool.InvokeAsync( - new RequestContext(mockServer.Object, CreateTestJsonRpcRequest()) { Services = services }, + new RequestContext(serverWithServices, CreateTestJsonRpcRequest()) { Services = services }, TestContext.Current.CancellationToken); Assert.Equal("42", (result.Content[0] as TextContentBlock)?.Text); } @@ -193,7 +195,7 @@ public async Task SupportsOptionalServiceFromDI() }, new() { Services = services }); var result = await tool.InvokeAsync( - new RequestContext(new Mock().Object, CreateTestJsonRpcRequest()), + new RequestContext(CreateTestServer(), CreateTestJsonRpcRequest()), TestContext.Current.CancellationToken); Assert.Equal("42", (result.Content[0] as TextContentBlock)?.Text); } @@ -208,7 +210,7 @@ public async Task SupportsDisposingInstantiatedDisposableTargets() options); var result = await tool1.InvokeAsync( - new RequestContext(new Mock().Object, CreateTestJsonRpcRequest()), + new RequestContext(CreateTestServer(), CreateTestJsonRpcRequest()), TestContext.Current.CancellationToken); Assert.Equal("""{"disposals":1}""", (result.Content[0] as TextContentBlock)?.Text); } @@ -223,7 +225,7 @@ public async Task SupportsAsyncDisposingInstantiatedAsyncDisposableTargets() options); var result = await tool1.InvokeAsync( - new RequestContext(new Mock().Object, CreateTestJsonRpcRequest()), + new RequestContext(CreateTestServer(), CreateTestJsonRpcRequest()), TestContext.Current.CancellationToken); Assert.Equal("""{"asyncDisposals":1}""", (result.Content[0] as TextContentBlock)?.Text); } @@ -242,7 +244,7 @@ public async Task SupportsAsyncDisposingInstantiatedAsyncDisposableAndDisposable options); var result = await tool1.InvokeAsync( - new RequestContext(new Mock().Object, CreateTestJsonRpcRequest()) { Services = services }, + new RequestContext(CreateTestServer(), CreateTestJsonRpcRequest()) { Services = services }, TestContext.Current.CancellationToken); Assert.Equal("""{"asyncDisposals":1,"disposals":0}""", (result.Content[0] as TextContentBlock)?.Text); } @@ -251,10 +253,10 @@ public async Task SupportsAsyncDisposingInstantiatedAsyncDisposableAndDisposable [Fact] public async Task CanReturnCollectionOfAIContent() { - Mock mockServer = new(); - McpServerTool tool = McpServerTool.Create((McpServer server) => + McpServer server = CreateTestServer(); + McpServerTool tool = McpServerTool.Create((McpServer s) => { - Assert.Same(mockServer.Object, server); + Assert.Same(server, s); return new List { new TextContent("text"), new DataContent("data:image/png;base64,1234"), @@ -263,7 +265,7 @@ public async Task CanReturnCollectionOfAIContent() }, new() { SerializerOptions = JsonContext2.Default.Options }); var result = await tool.InvokeAsync( - new RequestContext(mockServer.Object, CreateTestJsonRpcRequest()), + new RequestContext(server, CreateTestJsonRpcRequest()), TestContext.Current.CancellationToken); Assert.Equal(3, result.Content.Count); @@ -283,10 +285,10 @@ public async Task CanReturnCollectionOfAIContent() [InlineData("data:audio/wav;base64,1234", "audio")] public async Task CanReturnSingleAIContent(string data, string type) { - Mock mockServer = new(); - McpServerTool tool = McpServerTool.Create((McpServer server) => + McpServer server = CreateTestServer(); + McpServerTool tool = McpServerTool.Create((McpServer s) => { - Assert.Same(mockServer.Object, server); + Assert.Same(server, s); return type switch { "text" => (AIContent)new TextContent(data), @@ -297,7 +299,7 @@ public async Task CanReturnSingleAIContent(string data, string type) }); var result = await tool.InvokeAsync( - new RequestContext(mockServer.Object, CreateTestJsonRpcRequest()), + new RequestContext(server, CreateTestJsonRpcRequest()), TestContext.Current.CancellationToken); Assert.Single(result.Content); @@ -326,14 +328,14 @@ public async Task CanReturnSingleAIContent(string data, string type) [Fact] public async Task CanReturnNullAIContent() { - Mock mockServer = new(); - McpServerTool tool = McpServerTool.Create((McpServer server) => + McpServer server = CreateTestServer(); + McpServerTool tool = McpServerTool.Create((McpServer s) => { - Assert.Same(mockServer.Object, server); + Assert.Same(server, s); return (string?)null; }); var result = await tool.InvokeAsync( - new RequestContext(mockServer.Object, CreateTestJsonRpcRequest()), + new RequestContext(server, CreateTestJsonRpcRequest()), TestContext.Current.CancellationToken); Assert.Empty(result.Content); } @@ -341,14 +343,14 @@ public async Task CanReturnNullAIContent() [Fact] public async Task CanReturnString() { - Mock mockServer = new(); - McpServerTool tool = McpServerTool.Create((McpServer server) => + McpServer server = CreateTestServer(); + McpServerTool tool = McpServerTool.Create((McpServer s) => { - Assert.Same(mockServer.Object, server); + Assert.Same(server, s); return "42"; }); var result = await tool.InvokeAsync( - new RequestContext(mockServer.Object, CreateTestJsonRpcRequest()), + new RequestContext(server, CreateTestJsonRpcRequest()), TestContext.Current.CancellationToken); Assert.Single(result.Content); Assert.Equal("42", Assert.IsType(result.Content[0]).Text); @@ -357,14 +359,14 @@ public async Task CanReturnString() [Fact] public async Task CanReturnCollectionOfStrings() { - Mock mockServer = new(); - McpServerTool tool = McpServerTool.Create((McpServer server) => + McpServer server = CreateTestServer(); + McpServerTool tool = McpServerTool.Create((McpServer s) => { - Assert.Same(mockServer.Object, server); + Assert.Same(server, s); return new List { "42", "43" }; }, new() { SerializerOptions = JsonContext2.Default.Options }); var result = await tool.InvokeAsync( - new RequestContext(mockServer.Object, CreateTestJsonRpcRequest()), + new RequestContext(server, CreateTestJsonRpcRequest()), TestContext.Current.CancellationToken); Assert.Single(result.Content); Assert.Equal("""["42","43"]""", Assert.IsType(result.Content[0]).Text); @@ -373,14 +375,14 @@ public async Task CanReturnCollectionOfStrings() [Fact] public async Task CanReturnMcpContent() { - Mock mockServer = new(); - McpServerTool tool = McpServerTool.Create((McpServer server) => + McpServer server = CreateTestServer(); + McpServerTool tool = McpServerTool.Create((McpServer s) => { - Assert.Same(mockServer.Object, server); + Assert.Same(server, s); return new TextContentBlock { Text = "42" }; }); var result = await tool.InvokeAsync( - new RequestContext(mockServer.Object, CreateTestJsonRpcRequest()), + new RequestContext(server, CreateTestJsonRpcRequest()), TestContext.Current.CancellationToken); Assert.Single(result.Content); Assert.Equal("42", Assert.IsType(result.Content[0]).Text); @@ -390,10 +392,10 @@ public async Task CanReturnMcpContent() [Fact] public async Task CanReturnCollectionOfMcpContent() { - Mock mockServer = new(); - McpServerTool tool = McpServerTool.Create((McpServer server) => + McpServer server = CreateTestServer(); + McpServerTool tool = McpServerTool.Create((McpServer s) => { - Assert.Same(mockServer.Object, server); + Assert.Same(server, s); return (IList) [ new TextContentBlock { Text = "42" }, @@ -401,7 +403,7 @@ public async Task CanReturnCollectionOfMcpContent() ]; }); var result = await tool.InvokeAsync( - new RequestContext(mockServer.Object, CreateTestJsonRpcRequest()), + new RequestContext(server, CreateTestJsonRpcRequest()), TestContext.Current.CancellationToken); Assert.Equal(2, result.Content.Count); Assert.Equal("42", Assert.IsType(result.Content[0]).Text); @@ -417,14 +419,14 @@ public async Task CanReturnCallToolResult() Content = [new TextContentBlock { Text = "text" }, ImageContentBlock.FromBytes((byte[])[1, 2, 3, 4], "image/png")] }; - Mock mockServer = new(); - McpServerTool tool = McpServerTool.Create((McpServer server) => + McpServer server = CreateTestServer(); + McpServerTool tool = McpServerTool.Create((McpServer s) => { - Assert.Same(mockServer.Object, server); + Assert.Same(server, s); return response; }); var result = await tool.InvokeAsync( - new RequestContext(mockServer.Object, CreateTestJsonRpcRequest()), + new RequestContext(server, CreateTestJsonRpcRequest()), TestContext.Current.CancellationToken); Assert.Same(response, result); @@ -463,8 +465,8 @@ public async Task StructuredOutput_Enabled_ReturnsExpectedSchema(T value) { JsonSerializerOptions options = new() { TypeInfoResolver = new DefaultJsonTypeInfoResolver() }; McpServerTool tool = McpServerTool.Create(() => value, new() { Name = "tool", UseStructuredContent = true, SerializerOptions = options }); - var mockServer = new Mock(); - var request = new RequestContext(mockServer.Object, CreateTestJsonRpcRequest()) + McpServer server = CreateTestServer(); + var request = new RequestContext(server, CreateTestJsonRpcRequest()) { Params = new CallToolRequestParams { Name = "tool" }, }; @@ -481,8 +483,8 @@ public async Task StructuredOutput_Enabled_ReturnsExpectedSchema(T value) public async Task StructuredOutput_Enabled_VoidReturningTools_ReturnsExpectedSchema() { McpServerTool tool = McpServerTool.Create(() => { }); - var mockServer = new Mock(); - var request = new RequestContext(mockServer.Object, CreateTestJsonRpcRequest()) + McpServer server = CreateTestServer(); + var request = new RequestContext(server, CreateTestJsonRpcRequest()) { Params = new CallToolRequestParams { Name = "tool" }, }; @@ -493,7 +495,7 @@ public async Task StructuredOutput_Enabled_VoidReturningTools_ReturnsExpectedSch Assert.Null(result.StructuredContent); tool = McpServerTool.Create(() => Task.CompletedTask); - request = new RequestContext(mockServer.Object, CreateTestJsonRpcRequest()) + request = new RequestContext(server, CreateTestJsonRpcRequest()) { Params = new CallToolRequestParams { Name = "tool" }, }; @@ -504,7 +506,7 @@ public async Task StructuredOutput_Enabled_VoidReturningTools_ReturnsExpectedSch Assert.Null(result.StructuredContent); tool = McpServerTool.Create(() => default(ValueTask)); - request = new RequestContext(mockServer.Object, CreateTestJsonRpcRequest()) + request = new RequestContext(server, CreateTestJsonRpcRequest()) { Params = new CallToolRequestParams { Name = "tool" }, }; @@ -521,8 +523,8 @@ public async Task StructuredOutput_Disabled_ReturnsExpectedSchema(T value) { JsonSerializerOptions options = new() { TypeInfoResolver = new DefaultJsonTypeInfoResolver() }; McpServerTool tool = McpServerTool.Create(() => value, new() { UseStructuredContent = false, SerializerOptions = options }); - var mockServer = new Mock(); - var request = new RequestContext(mockServer.Object, CreateTestJsonRpcRequest()) + McpServer server = CreateTestServer(); + var request = new RequestContext(server, CreateTestJsonRpcRequest()) { Params = new CallToolRequestParams { Name = "tool" }, }; @@ -819,11 +821,11 @@ public void ReturnDescription_StructuredOutputEnabled_WithExplicitDescription_No public async Task EnablePollingAsync_ThrowsInvalidOperationException_WhenTransportIsNotStreamableHttpPost() { // Arrange - Mock mockServer = new(); + McpServer server = CreateTestServer(); var jsonRpcRequest = CreateTestJsonRpcRequest(); // The JsonRpcRequest has no Context, so RelatedTransport will be null - var requestContext = new RequestContext(mockServer.Object, jsonRpcRequest); + var requestContext = new RequestContext(server, jsonRpcRequest); // Act & Assert var exception = await Assert.ThrowsAsync(