Restructure IMcpEndpoint, IMcpClient, and IMcpServer (#723)
* Remove `McpEndpoint` & `IMcpClient` * Revise naming, add abstract classes * Fix missing renames * Move extension methods to instance methods * Add back old API, but obsoleted * Add back obsoleted factory classes * Move deprecation attributes * `SseClientTransport` -> `HttpClientTransport` * Update src/ModelContextProtocol.Core/Server/AugmentedServiceProvider.cs Co-authored-by: Stephen Halter <halter73@gmail.com> * PR feedback * PR feedback * Add back dispose lock * Fix docs projects * PR feedback * Undo `docs/*.md` changes --------- Co-authored-by: Stephen Halter <halter73@gmail.com>
This commit is contained in:
parent
fe2ce2bc60
commit
38b4a26998
7 changed files with 5169 additions and 3786 deletions
|
|
@ -0,0 +1,195 @@
|
|||
using Microsoft.Extensions.AI;
|
||||
using ModelContextProtocol.Protocol;
|
||||
using ModelContextProtocol.Server;
|
||||
using Moq;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace ModelContextProtocol.Tests.Server;
|
||||
|
||||
#pragma warning disable CS0618 // Type or member is obsolete
|
||||
|
||||
public class McpServerExtensionsTests
|
||||
{
|
||||
[Fact]
|
||||
public async Task SampleAsync_Request_Throws_When_Not_McpServer()
|
||||
{
|
||||
var server = new Mock<IMcpServer>(MockBehavior.Strict).Object;
|
||||
|
||||
var ex = await Assert.ThrowsAsync<InvalidOperationException>(async () => await server.SampleAsync(
|
||||
new CreateMessageRequestParams { Messages = [new SamplingMessage { Role = Role.User, Content = new TextContentBlock { Text = "hi" } }] },
|
||||
TestContext.Current.CancellationToken));
|
||||
Assert.Contains("Prefer using 'McpServer.SampleAsync' instead", ex.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SampleAsync_Messages_Throws_When_Not_McpServer()
|
||||
{
|
||||
var server = new Mock<IMcpServer>(MockBehavior.Strict).Object;
|
||||
|
||||
var ex = await Assert.ThrowsAsync<InvalidOperationException>(async () => await server.SampleAsync(
|
||||
[new ChatMessage(ChatRole.User, "hi")], cancellationToken: TestContext.Current.CancellationToken));
|
||||
Assert.Contains("Prefer using 'McpServer.SampleAsync' instead", ex.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AsSamplingChatClient_Throws_When_Not_McpServer()
|
||||
{
|
||||
var server = new Mock<IMcpServer>(MockBehavior.Strict).Object;
|
||||
|
||||
var ex = Assert.Throws<InvalidOperationException>(server.AsSamplingChatClient);
|
||||
Assert.Contains("Prefer using 'McpServer.AsSamplingChatClient' instead", ex.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AsClientLoggerProvider_Throws_When_Not_McpServer()
|
||||
{
|
||||
var server = new Mock<IMcpServer>(MockBehavior.Strict).Object;
|
||||
|
||||
var ex = Assert.Throws<InvalidOperationException>(server.AsClientLoggerProvider);
|
||||
Assert.Contains("Prefer using 'McpServer.AsClientLoggerProvider' instead", ex.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task RequestRootsAsync_Throws_When_Not_McpServer()
|
||||
{
|
||||
var server = new Mock<IMcpServer>(MockBehavior.Strict).Object;
|
||||
|
||||
var ex = await Assert.ThrowsAsync<InvalidOperationException>(async () => await server.RequestRootsAsync(
|
||||
new ListRootsRequestParams(), TestContext.Current.CancellationToken));
|
||||
Assert.Contains("Prefer using 'McpServer.RequestRootsAsync' instead", ex.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ElicitAsync_Throws_When_Not_McpServer()
|
||||
{
|
||||
var server = new Mock<IMcpServer>(MockBehavior.Strict).Object;
|
||||
|
||||
var ex = await Assert.ThrowsAsync<InvalidOperationException>(async () => await server.ElicitAsync(
|
||||
new ElicitRequestParams { Message = "hello" }, TestContext.Current.CancellationToken));
|
||||
Assert.Contains("Prefer using 'McpServer.ElicitAsync' instead", ex.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SampleAsync_Request_Forwards_To_McpServer_SendRequestAsync()
|
||||
{
|
||||
var mockServer = new Mock<McpServer> { CallBase = true };
|
||||
|
||||
var resultPayload = new CreateMessageResult
|
||||
{
|
||||
Content = new TextContentBlock { Text = "resp" },
|
||||
Model = "test-model",
|
||||
Role = Role.Assistant,
|
||||
StopReason = "endTurn",
|
||||
};
|
||||
|
||||
mockServer
|
||||
.Setup(s => s.ClientCapabilities)
|
||||
.Returns(new ClientCapabilities() { Sampling = new() });
|
||||
|
||||
mockServer
|
||||
.Setup(s => s.SendRequestAsync(It.IsAny<JsonRpcRequest>(), It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync(new JsonRpcResponse
|
||||
{
|
||||
Result = JsonSerializer.SerializeToNode(resultPayload, McpJsonUtilities.DefaultOptions),
|
||||
});
|
||||
|
||||
IMcpServer server = mockServer.Object;
|
||||
|
||||
var result = await server.SampleAsync(new CreateMessageRequestParams
|
||||
{
|
||||
Messages = [new SamplingMessage { Role = Role.User, Content = new TextContentBlock { Text = "hi" } }]
|
||||
}, TestContext.Current.CancellationToken);
|
||||
|
||||
Assert.Equal("test-model", result.Model);
|
||||
Assert.Equal(Role.Assistant, result.Role);
|
||||
Assert.Equal("resp", Assert.IsType<TextContentBlock>(result.Content).Text);
|
||||
mockServer.Verify(s => s.SendRequestAsync(It.IsAny<JsonRpcRequest>(), It.IsAny<CancellationToken>()), Times.Once);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SampleAsync_Messages_Forwards_To_McpServer_SendRequestAsync()
|
||||
{
|
||||
var mockServer = new Mock<McpServer> { CallBase = true };
|
||||
|
||||
var resultPayload = new CreateMessageResult
|
||||
{
|
||||
Content = new TextContentBlock { Text = "resp" },
|
||||
Model = "test-model",
|
||||
Role = Role.Assistant,
|
||||
StopReason = "endTurn",
|
||||
};
|
||||
|
||||
mockServer
|
||||
.Setup(s => s.ClientCapabilities)
|
||||
.Returns(new ClientCapabilities() { Sampling = new() });
|
||||
|
||||
mockServer
|
||||
.Setup(s => s.SendRequestAsync(It.IsAny<JsonRpcRequest>(), It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync(new JsonRpcResponse
|
||||
{
|
||||
Result = JsonSerializer.SerializeToNode(resultPayload, McpJsonUtilities.DefaultOptions),
|
||||
});
|
||||
|
||||
IMcpServer server = mockServer.Object;
|
||||
|
||||
var chatResponse = await server.SampleAsync([new ChatMessage(ChatRole.User, "hi")], cancellationToken: TestContext.Current.CancellationToken);
|
||||
|
||||
Assert.Equal("test-model", chatResponse.ModelId);
|
||||
var last = chatResponse.Messages.Last();
|
||||
Assert.Equal(ChatRole.Assistant, last.Role);
|
||||
Assert.Equal("resp", last.Text);
|
||||
mockServer.Verify(s => s.SendRequestAsync(It.IsAny<JsonRpcRequest>(), It.IsAny<CancellationToken>()), Times.Once);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task RequestRootsAsync_Forwards_To_McpServer_SendRequestAsync()
|
||||
{
|
||||
var mockServer = new Mock<McpServer> { CallBase = true };
|
||||
|
||||
var resultPayload = new ListRootsResult { Roots = [new Root { Uri = "root://a" }] };
|
||||
|
||||
mockServer
|
||||
.Setup(s => s.ClientCapabilities)
|
||||
.Returns(new ClientCapabilities() { Roots = new() });
|
||||
|
||||
mockServer
|
||||
.Setup(s => s.SendRequestAsync(It.IsAny<JsonRpcRequest>(), It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync(new JsonRpcResponse
|
||||
{
|
||||
Result = JsonSerializer.SerializeToNode(resultPayload, McpJsonUtilities.DefaultOptions),
|
||||
});
|
||||
|
||||
IMcpServer server = mockServer.Object;
|
||||
|
||||
var result = await server.RequestRootsAsync(new ListRootsRequestParams(), TestContext.Current.CancellationToken);
|
||||
|
||||
Assert.Equal("root://a", result.Roots[0].Uri);
|
||||
mockServer.Verify(s => s.SendRequestAsync(It.IsAny<JsonRpcRequest>(), It.IsAny<CancellationToken>()), Times.Once);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ElicitAsync_Forwards_To_McpServer_SendRequestAsync()
|
||||
{
|
||||
var mockServer = new Mock<McpServer> { CallBase = true };
|
||||
|
||||
var resultPayload = new ElicitResult { Action = "accept" };
|
||||
|
||||
mockServer
|
||||
.Setup(s => s.ClientCapabilities)
|
||||
.Returns(new ClientCapabilities() { Elicitation = new() });
|
||||
|
||||
mockServer
|
||||
.Setup(s => s.SendRequestAsync(It.IsAny<JsonRpcRequest>(), It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync(new JsonRpcResponse
|
||||
{
|
||||
Result = JsonSerializer.SerializeToNode(resultPayload, McpJsonUtilities.DefaultOptions),
|
||||
});
|
||||
|
||||
IMcpServer server = mockServer.Object;
|
||||
|
||||
var result = await server.ElicitAsync(new ElicitRequestParams { Message = "hi" }, TestContext.Current.CancellationToken);
|
||||
|
||||
Assert.Equal("accept", result.Action);
|
||||
mockServer.Verify(s => s.SendRequestAsync(It.IsAny<JsonRpcRequest>(), It.IsAny<CancellationToken>()), Times.Once);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,45 +0,0 @@
|
|||
using ModelContextProtocol.Server;
|
||||
using ModelContextProtocol.Tests.Utils;
|
||||
|
||||
namespace ModelContextProtocol.Tests.Server;
|
||||
|
||||
public class McpServerFactoryTests : LoggedTest
|
||||
{
|
||||
private readonly McpServerOptions _options;
|
||||
|
||||
public McpServerFactoryTests(ITestOutputHelper testOutputHelper)
|
||||
: base(testOutputHelper)
|
||||
{
|
||||
_options = new McpServerOptions
|
||||
{
|
||||
ProtocolVersion = "1.0",
|
||||
InitializationTimeout = TimeSpan.FromSeconds(30)
|
||||
};
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Create_Should_Initialize_With_Valid_Parameters()
|
||||
{
|
||||
// Arrange & Act
|
||||
await using var transport = new TestServerTransport();
|
||||
await using IMcpServer server = McpServerFactory.Create(transport, _options, LoggerFactory);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(server);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Create_Throws_For_Null_ServerTransport()
|
||||
{
|
||||
// Arrange, Act & Assert
|
||||
Assert.Throws<ArgumentNullException>("transport", () => McpServerFactory.Create(null!, _options, LoggerFactory));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Create_Throws_For_Null_Options()
|
||||
{
|
||||
// Arrange, Act & Assert
|
||||
await using var transport = new TestServerTransport();
|
||||
Assert.Throws<ArgumentNullException>("serverOptions", () => McpServerFactory.Create(transport, null!, LoggerFactory));
|
||||
}
|
||||
}
|
||||
|
|
@ -25,7 +25,7 @@ public class McpServerLoggingLevelTests
|
|||
|
||||
var provider = services.BuildServiceProvider();
|
||||
|
||||
provider.GetRequiredService<IMcpServer>();
|
||||
provider.GetRequiredService<McpServer>();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -39,7 +39,7 @@ public class McpServerLoggingLevelTests
|
|||
|
||||
var provider = services.BuildServiceProvider();
|
||||
|
||||
var server = provider.GetRequiredService<IMcpServer>();
|
||||
var server = provider.GetRequiredService<McpServer>();
|
||||
|
||||
Assert.NotNull(server.ServerOptions.Capabilities?.Logging);
|
||||
Assert.NotNull(server.ServerOptions.Capabilities.Logging.SetLoggingLevelHandler);
|
||||
|
|
@ -52,7 +52,7 @@ public class McpServerLoggingLevelTests
|
|||
services.AddMcpServer()
|
||||
.WithStdioServerTransport();
|
||||
var provider = services.BuildServiceProvider();
|
||||
var server = provider.GetRequiredService<IMcpServer>();
|
||||
var server = provider.GetRequiredService<McpServer>();
|
||||
Assert.Null(server.ServerOptions.Capabilities?.Logging);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,9 @@
|
|||
using Microsoft.Extensions.AI;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
using ModelContextProtocol.Protocol;
|
||||
using ModelContextProtocol.Server;
|
||||
using Moq;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text.Json;
|
||||
|
|
@ -43,11 +41,11 @@ public class McpServerPromptTests
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SupportsIMcpServer()
|
||||
public async Task SupportsMcpServer()
|
||||
{
|
||||
Mock<IMcpServer> mockServer = new();
|
||||
Mock<McpServer> mockServer = new();
|
||||
|
||||
McpServerPrompt prompt = McpServerPrompt.Create((IMcpServer server) =>
|
||||
McpServerPrompt prompt = McpServerPrompt.Create((McpServer server) =>
|
||||
{
|
||||
Assert.Same(mockServer.Object, server);
|
||||
return new ChatMessage(ChatRole.User, "Hello");
|
||||
|
|
@ -73,7 +71,7 @@ public class McpServerPromptTests
|
|||
sc.AddSingleton(expectedMyService);
|
||||
IServiceProvider services = sc.BuildServiceProvider();
|
||||
|
||||
Mock<IMcpServer> mockServer = new();
|
||||
Mock<McpServer> mockServer = new();
|
||||
mockServer.SetupGet(s => s.Services).Returns(services);
|
||||
|
||||
MethodInfo? testMethod = typeof(HasCtorWithSpecialParameters).GetMethod(nameof(HasCtorWithSpecialParameters.TestPrompt));
|
||||
|
|
@ -96,11 +94,11 @@ public class McpServerPromptTests
|
|||
private sealed class HasCtorWithSpecialParameters
|
||||
{
|
||||
private readonly MyService _ms;
|
||||
private readonly IMcpServer _server;
|
||||
private readonly McpServer _server;
|
||||
private readonly RequestContext<GetPromptRequestParams> _request;
|
||||
private readonly IProgress<ProgressNotificationValue> _progress;
|
||||
|
||||
public HasCtorWithSpecialParameters(MyService ms, IMcpServer server, RequestContext<GetPromptRequestParams> request, IProgress<ProgressNotificationValue> progress)
|
||||
public HasCtorWithSpecialParameters(MyService ms, McpServer server, RequestContext<GetPromptRequestParams> request, IProgress<ProgressNotificationValue> progress)
|
||||
{
|
||||
Assert.NotNull(ms);
|
||||
Assert.NotNull(server);
|
||||
|
|
@ -135,11 +133,11 @@ public class McpServerPromptTests
|
|||
Assert.DoesNotContain("actualMyService", prompt.ProtocolPrompt.Arguments?.Select(a => a.Name) ?? []);
|
||||
|
||||
await Assert.ThrowsAnyAsync<ArgumentException>(async () => await prompt.GetAsync(
|
||||
new RequestContext<GetPromptRequestParams>(new Mock<IMcpServer>().Object, CreateTestJsonRpcRequest()),
|
||||
new RequestContext<GetPromptRequestParams>(new Mock<McpServer>().Object, CreateTestJsonRpcRequest()),
|
||||
TestContext.Current.CancellationToken));
|
||||
|
||||
var result = await prompt.GetAsync(
|
||||
new RequestContext<GetPromptRequestParams>(new Mock<IMcpServer>().Object, CreateTestJsonRpcRequest()) { Services = services },
|
||||
new RequestContext<GetPromptRequestParams>(new Mock<McpServer>().Object, CreateTestJsonRpcRequest()) { Services = services },
|
||||
TestContext.Current.CancellationToken);
|
||||
Assert.Equal("Hello", Assert.IsType<TextContentBlock>(result.Messages[0].Content).Text);
|
||||
}
|
||||
|
|
@ -160,7 +158,7 @@ public class McpServerPromptTests
|
|||
}, new() { Services = services });
|
||||
|
||||
var result = await prompt.GetAsync(
|
||||
new RequestContext<GetPromptRequestParams>(new Mock<IMcpServer>().Object, CreateTestJsonRpcRequest()),
|
||||
new RequestContext<GetPromptRequestParams>(new Mock<McpServer>().Object, CreateTestJsonRpcRequest()),
|
||||
TestContext.Current.CancellationToken);
|
||||
Assert.Equal("Hello", Assert.IsType<TextContentBlock>(result.Messages[0].Content).Text);
|
||||
}
|
||||
|
|
@ -173,7 +171,7 @@ public class McpServerPromptTests
|
|||
_ => new DisposablePromptType());
|
||||
|
||||
var result = await prompt1.GetAsync(
|
||||
new RequestContext<GetPromptRequestParams>(new Mock<IMcpServer>().Object, CreateTestJsonRpcRequest()),
|
||||
new RequestContext<GetPromptRequestParams>(new Mock<McpServer>().Object, CreateTestJsonRpcRequest()),
|
||||
TestContext.Current.CancellationToken);
|
||||
Assert.Equal("disposals:1", Assert.IsType<TextContentBlock>(result.Messages[0].Content).Text);
|
||||
}
|
||||
|
|
@ -186,7 +184,7 @@ public class McpServerPromptTests
|
|||
_ => new AsyncDisposablePromptType());
|
||||
|
||||
var result = await prompt1.GetAsync(
|
||||
new RequestContext<GetPromptRequestParams>(new Mock<IMcpServer>().Object, CreateTestJsonRpcRequest()),
|
||||
new RequestContext<GetPromptRequestParams>(new Mock<McpServer>().Object, CreateTestJsonRpcRequest()),
|
||||
TestContext.Current.CancellationToken);
|
||||
Assert.Equal("asyncDisposals:1", Assert.IsType<TextContentBlock>(result.Messages[0].Content).Text);
|
||||
}
|
||||
|
|
@ -199,7 +197,7 @@ public class McpServerPromptTests
|
|||
_ => new AsyncDisposableAndDisposablePromptType());
|
||||
|
||||
var result = await prompt1.GetAsync(
|
||||
new RequestContext<GetPromptRequestParams>(new Mock<IMcpServer>().Object, CreateTestJsonRpcRequest()),
|
||||
new RequestContext<GetPromptRequestParams>(new Mock<McpServer>().Object, CreateTestJsonRpcRequest()),
|
||||
TestContext.Current.CancellationToken);
|
||||
Assert.Equal("disposals:0, asyncDisposals:1", Assert.IsType<TextContentBlock>(result.Messages[0].Content).Text);
|
||||
}
|
||||
|
|
@ -215,7 +213,7 @@ public class McpServerPromptTests
|
|||
});
|
||||
|
||||
var actual = await prompt.GetAsync(
|
||||
new RequestContext<GetPromptRequestParams>(new Mock<IMcpServer>().Object, CreateTestJsonRpcRequest()),
|
||||
new RequestContext<GetPromptRequestParams>(new Mock<McpServer>().Object, CreateTestJsonRpcRequest()),
|
||||
TestContext.Current.CancellationToken);
|
||||
|
||||
Assert.Same(expected, actual);
|
||||
|
|
@ -232,7 +230,7 @@ public class McpServerPromptTests
|
|||
});
|
||||
|
||||
var actual = await prompt.GetAsync(
|
||||
new RequestContext<GetPromptRequestParams>(new Mock<IMcpServer>().Object, CreateTestJsonRpcRequest()),
|
||||
new RequestContext<GetPromptRequestParams>(new Mock<McpServer>().Object, CreateTestJsonRpcRequest()),
|
||||
TestContext.Current.CancellationToken);
|
||||
|
||||
Assert.NotNull(actual);
|
||||
|
|
@ -258,7 +256,7 @@ public class McpServerPromptTests
|
|||
});
|
||||
|
||||
var actual = await prompt.GetAsync(
|
||||
new RequestContext<GetPromptRequestParams>(new Mock<IMcpServer>().Object, CreateTestJsonRpcRequest()),
|
||||
new RequestContext<GetPromptRequestParams>(new Mock<McpServer>().Object, CreateTestJsonRpcRequest()),
|
||||
TestContext.Current.CancellationToken);
|
||||
|
||||
Assert.NotNull(actual);
|
||||
|
|
@ -290,7 +288,7 @@ public class McpServerPromptTests
|
|||
});
|
||||
|
||||
var actual = await prompt.GetAsync(
|
||||
new RequestContext<GetPromptRequestParams>(new Mock<IMcpServer>().Object, CreateTestJsonRpcRequest()),
|
||||
new RequestContext<GetPromptRequestParams>(new Mock<McpServer>().Object, CreateTestJsonRpcRequest()),
|
||||
TestContext.Current.CancellationToken);
|
||||
|
||||
Assert.NotNull(actual);
|
||||
|
|
@ -317,7 +315,7 @@ public class McpServerPromptTests
|
|||
});
|
||||
|
||||
var actual = await prompt.GetAsync(
|
||||
new RequestContext<GetPromptRequestParams>(new Mock<IMcpServer>().Object, CreateTestJsonRpcRequest()),
|
||||
new RequestContext<GetPromptRequestParams>(new Mock<McpServer>().Object, CreateTestJsonRpcRequest()),
|
||||
TestContext.Current.CancellationToken);
|
||||
|
||||
Assert.NotNull(actual);
|
||||
|
|
@ -349,7 +347,7 @@ public class McpServerPromptTests
|
|||
});
|
||||
|
||||
var actual = await prompt.GetAsync(
|
||||
new RequestContext<GetPromptRequestParams>(new Mock<IMcpServer>().Object, CreateTestJsonRpcRequest()),
|
||||
new RequestContext<GetPromptRequestParams>(new Mock<McpServer>().Object, CreateTestJsonRpcRequest()),
|
||||
TestContext.Current.CancellationToken);
|
||||
|
||||
Assert.NotNull(actual);
|
||||
|
|
@ -370,7 +368,7 @@ public class McpServerPromptTests
|
|||
});
|
||||
|
||||
await Assert.ThrowsAsync<InvalidOperationException>(async () => await prompt.GetAsync(
|
||||
new RequestContext<GetPromptRequestParams>(new Mock<IMcpServer>().Object, CreateTestJsonRpcRequest()),
|
||||
new RequestContext<GetPromptRequestParams>(new Mock<McpServer>().Object, CreateTestJsonRpcRequest()),
|
||||
TestContext.Current.CancellationToken));
|
||||
}
|
||||
|
||||
|
|
@ -383,7 +381,7 @@ public class McpServerPromptTests
|
|||
});
|
||||
|
||||
await Assert.ThrowsAsync<InvalidOperationException>(async () => await prompt.GetAsync(
|
||||
new RequestContext<GetPromptRequestParams>(new Mock<IMcpServer>().Object, CreateTestJsonRpcRequest()),
|
||||
new RequestContext<GetPromptRequestParams>(new Mock<McpServer>().Object, CreateTestJsonRpcRequest()),
|
||||
TestContext.Current.CancellationToken));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ public partial class McpServerResourceTests
|
|||
|
||||
var provider = services.BuildServiceProvider();
|
||||
|
||||
provider.GetRequiredService<IMcpServer>();
|
||||
provider.GetRequiredService<McpServer>();
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -96,7 +96,7 @@ public partial class McpServerResourceTests
|
|||
|
||||
var provider = services.BuildServiceProvider();
|
||||
|
||||
provider.GetRequiredService<IMcpServer>();
|
||||
provider.GetRequiredService<McpServer>();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -119,7 +119,7 @@ public partial class McpServerResourceTests
|
|||
});
|
||||
var sp = services.BuildServiceProvider();
|
||||
|
||||
sp.GetRequiredService<IMcpServer>();
|
||||
sp.GetRequiredService<McpServer>();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -143,7 +143,7 @@ public partial class McpServerResourceTests
|
|||
|
||||
McpServerResource t;
|
||||
ReadResourceResult? result;
|
||||
IMcpServer server = new Mock<IMcpServer>().Object;
|
||||
McpServer server = new Mock<McpServer>().Object;
|
||||
|
||||
t = McpServerResource.Create(() => "42", new() { Name = Name });
|
||||
Assert.Equal("resource://mcp/Hello", t.ProtocolResourceTemplate.UriTemplate);
|
||||
|
|
@ -153,7 +153,7 @@ public partial class McpServerResourceTests
|
|||
Assert.NotNull(result);
|
||||
Assert.Equal("42", ((TextResourceContents)result.Contents[0]).Text);
|
||||
|
||||
t = McpServerResource.Create((IMcpServer server) => "42", new() { Name = Name });
|
||||
t = McpServerResource.Create((McpServer server) => "42", new() { Name = Name });
|
||||
Assert.Equal("resource://mcp/Hello", t.ProtocolResourceTemplate.UriTemplate);
|
||||
result = await t.ReadAsync(
|
||||
new RequestContext<ReadResourceRequestParams>(server, CreateTestJsonRpcRequest()) { Params = new() { Uri = "resource://mcp/Hello" } },
|
||||
|
|
@ -287,7 +287,7 @@ public partial class McpServerResourceTests
|
|||
McpServerResource t = McpServerResource.Create((string arg1) => arg1, new() { Name = "Hello" });
|
||||
Assert.Equal("resource://mcp/Hello{?arg1}", t.ProtocolResourceTemplate.UriTemplate);
|
||||
Assert.Null(await t.ReadAsync(
|
||||
new RequestContext<ReadResourceRequestParams>(new Mock<IMcpServer>().Object, CreateTestJsonRpcRequest()) { Params = new() { Uri = uri } },
|
||||
new RequestContext<ReadResourceRequestParams>(new Mock<McpServer>().Object, CreateTestJsonRpcRequest()) { Params = new() { Uri = uri } },
|
||||
TestContext.Current.CancellationToken));
|
||||
}
|
||||
|
||||
|
|
@ -298,7 +298,7 @@ public partial class McpServerResourceTests
|
|||
{
|
||||
McpServerResource t = McpServerResource.Create(() => "resource", new() { UriTemplate = actualUri });
|
||||
Assert.NotNull(await t.ReadAsync(
|
||||
new RequestContext<ReadResourceRequestParams>(new Mock<IMcpServer>().Object, CreateTestJsonRpcRequest()) { Params = new() { Uri = queriedUri } },
|
||||
new RequestContext<ReadResourceRequestParams>(new Mock<McpServer>().Object, CreateTestJsonRpcRequest()) { Params = new() { Uri = queriedUri } },
|
||||
TestContext.Current.CancellationToken));
|
||||
}
|
||||
|
||||
|
|
@ -327,7 +327,7 @@ public partial class McpServerResourceTests
|
|||
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<ArgumentException>(async () => await t.ReadAsync(
|
||||
new RequestContext<ReadResourceRequestParams>(new Mock<IMcpServer>().Object, CreateTestJsonRpcRequest()) { Params = new() { Uri = uri } },
|
||||
new RequestContext<ReadResourceRequestParams>(new Mock<McpServer>().Object, CreateTestJsonRpcRequest()) { Params = new() { Uri = uri } },
|
||||
TestContext.Current.CancellationToken));
|
||||
}
|
||||
|
||||
|
|
@ -340,36 +340,36 @@ public partial class McpServerResourceTests
|
|||
ReadResourceResult? result;
|
||||
|
||||
result = await t.ReadAsync(
|
||||
new RequestContext<ReadResourceRequestParams>(new Mock<IMcpServer>().Object, CreateTestJsonRpcRequest()) { Params = new() { Uri = "resource://mcp/Hello" } },
|
||||
new RequestContext<ReadResourceRequestParams>(new Mock<McpServer>().Object, 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<ReadResourceRequestParams>(new Mock<IMcpServer>().Object, CreateTestJsonRpcRequest()) { Params = new() { Uri = "resource://mcp/Hello?arg1=first" } },
|
||||
new RequestContext<ReadResourceRequestParams>(new Mock<McpServer>().Object, 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<ReadResourceRequestParams>(new Mock<IMcpServer>().Object, CreateTestJsonRpcRequest()) { Params = new() { Uri = "resource://mcp/Hello?arg2=42" } },
|
||||
new RequestContext<ReadResourceRequestParams>(new Mock<McpServer>().Object, 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<ReadResourceRequestParams>(new Mock<IMcpServer>().Object, CreateTestJsonRpcRequest()) { Params = new() { Uri = "resource://mcp/Hello?arg1=first&arg2=42" } },
|
||||
new RequestContext<ReadResourceRequestParams>(new Mock<McpServer>().Object, 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);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SupportsIMcpServer()
|
||||
public async Task SupportsMcpServer()
|
||||
{
|
||||
Mock<IMcpServer> mockServer = new();
|
||||
Mock<McpServer> mockServer = new();
|
||||
|
||||
McpServerResource resource = McpServerResource.Create((IMcpServer server) =>
|
||||
McpServerResource resource = McpServerResource.Create((McpServer server) =>
|
||||
{
|
||||
Assert.Same(mockServer.Object, server);
|
||||
return "42";
|
||||
|
|
@ -391,7 +391,7 @@ public partial class McpServerResourceTests
|
|||
sc.AddSingleton(expectedMyService);
|
||||
IServiceProvider services = sc.BuildServiceProvider();
|
||||
|
||||
Mock<IMcpServer> mockServer = new();
|
||||
Mock<McpServer> mockServer = new();
|
||||
mockServer.SetupGet(s => s.Services).Returns(services);
|
||||
|
||||
MethodInfo? testMethod = typeof(HasCtorWithSpecialParameters).GetMethod(nameof(HasCtorWithSpecialParameters.TestResource));
|
||||
|
|
@ -414,11 +414,11 @@ public partial class McpServerResourceTests
|
|||
private sealed class HasCtorWithSpecialParameters
|
||||
{
|
||||
private readonly MyService _ms;
|
||||
private readonly IMcpServer _server;
|
||||
private readonly McpServer _server;
|
||||
private readonly RequestContext<ReadResourceRequestParams> _request;
|
||||
private readonly IProgress<ProgressNotificationValue> _progress;
|
||||
|
||||
public HasCtorWithSpecialParameters(MyService ms, IMcpServer server, RequestContext<ReadResourceRequestParams> request, IProgress<ProgressNotificationValue> progress)
|
||||
public HasCtorWithSpecialParameters(MyService ms, McpServer server, RequestContext<ReadResourceRequestParams> request, IProgress<ProgressNotificationValue> progress)
|
||||
{
|
||||
Assert.NotNull(ms);
|
||||
Assert.NotNull(server);
|
||||
|
|
@ -477,7 +477,7 @@ public partial class McpServerResourceTests
|
|||
|
||||
McpServerResource resource = services.GetRequiredService<McpServerResource>();
|
||||
|
||||
Mock<IMcpServer> mockServer = new();
|
||||
Mock<McpServer> mockServer = new();
|
||||
|
||||
await Assert.ThrowsAnyAsync<ArgumentException>(async () => await resource.ReadAsync(
|
||||
new RequestContext<ReadResourceRequestParams>(mockServer.Object, CreateTestJsonRpcRequest()) { Params = new() { Uri = "resource://mcp/Test" } },
|
||||
|
|
@ -506,7 +506,7 @@ public partial class McpServerResourceTests
|
|||
}, new() { Services = services, Name = "Test" });
|
||||
|
||||
var result = await resource.ReadAsync(
|
||||
new RequestContext<ReadResourceRequestParams>(new Mock<IMcpServer>().Object, CreateTestJsonRpcRequest()) { Params = new() { Uri = "resource://mcp/Test" } },
|
||||
new RequestContext<ReadResourceRequestParams>(new Mock<McpServer>().Object, CreateTestJsonRpcRequest()) { Params = new() { Uri = "resource://mcp/Test" } },
|
||||
TestContext.Current.CancellationToken);
|
||||
Assert.NotNull(result);
|
||||
Assert.Equal("42", ((TextResourceContents)result.Contents[0]).Text);
|
||||
|
|
@ -522,7 +522,7 @@ public partial class McpServerResourceTests
|
|||
_ => new DisposableResourceType());
|
||||
|
||||
var result = await resource1.ReadAsync(
|
||||
new RequestContext<ReadResourceRequestParams>(new Mock<IMcpServer>().Object, CreateTestJsonRpcRequest()) { Params = new() { Uri = "test://static/resource/instanceMethod" } },
|
||||
new RequestContext<ReadResourceRequestParams>(new Mock<McpServer>().Object, CreateTestJsonRpcRequest()) { Params = new() { Uri = "test://static/resource/instanceMethod" } },
|
||||
TestContext.Current.CancellationToken);
|
||||
Assert.NotNull(result);
|
||||
Assert.Equal("0", ((TextResourceContents)result.Contents[0]).Text);
|
||||
|
|
@ -533,8 +533,8 @@ public partial class McpServerResourceTests
|
|||
[Fact]
|
||||
public async Task CanReturnReadResult()
|
||||
{
|
||||
Mock<IMcpServer> mockServer = new();
|
||||
McpServerResource resource = McpServerResource.Create((IMcpServer server) =>
|
||||
Mock<McpServer> mockServer = new();
|
||||
McpServerResource resource = McpServerResource.Create((McpServer server) =>
|
||||
{
|
||||
Assert.Same(mockServer.Object, server);
|
||||
return new ReadResourceResult { Contents = new List<ResourceContents> { new TextResourceContents { Text = "hello" } } };
|
||||
|
|
@ -550,8 +550,8 @@ public partial class McpServerResourceTests
|
|||
[Fact]
|
||||
public async Task CanReturnResourceContents()
|
||||
{
|
||||
Mock<IMcpServer> mockServer = new();
|
||||
McpServerResource resource = McpServerResource.Create((IMcpServer server) =>
|
||||
Mock<McpServer> mockServer = new();
|
||||
McpServerResource resource = McpServerResource.Create((McpServer server) =>
|
||||
{
|
||||
Assert.Same(mockServer.Object, server);
|
||||
return new TextResourceContents { Text = "hello" };
|
||||
|
|
@ -567,8 +567,8 @@ public partial class McpServerResourceTests
|
|||
[Fact]
|
||||
public async Task CanReturnCollectionOfResourceContents()
|
||||
{
|
||||
Mock<IMcpServer> mockServer = new();
|
||||
McpServerResource resource = McpServerResource.Create((IMcpServer server) =>
|
||||
Mock<McpServer> mockServer = new();
|
||||
McpServerResource resource = McpServerResource.Create((McpServer server) =>
|
||||
{
|
||||
Assert.Same(mockServer.Object, server);
|
||||
return (IList<ResourceContents>)
|
||||
|
|
@ -589,8 +589,8 @@ public partial class McpServerResourceTests
|
|||
[Fact]
|
||||
public async Task CanReturnString()
|
||||
{
|
||||
Mock<IMcpServer> mockServer = new();
|
||||
McpServerResource resource = McpServerResource.Create((IMcpServer server) =>
|
||||
Mock<McpServer> mockServer = new();
|
||||
McpServerResource resource = McpServerResource.Create((McpServer server) =>
|
||||
{
|
||||
Assert.Same(mockServer.Object, server);
|
||||
return "42";
|
||||
|
|
@ -606,8 +606,8 @@ public partial class McpServerResourceTests
|
|||
[Fact]
|
||||
public async Task CanReturnCollectionOfStrings()
|
||||
{
|
||||
Mock<IMcpServer> mockServer = new();
|
||||
McpServerResource resource = McpServerResource.Create((IMcpServer server) =>
|
||||
Mock<McpServer> mockServer = new();
|
||||
McpServerResource resource = McpServerResource.Create((McpServer server) =>
|
||||
{
|
||||
Assert.Same(mockServer.Object, server);
|
||||
return new List<string> { "42", "43" };
|
||||
|
|
@ -624,8 +624,8 @@ public partial class McpServerResourceTests
|
|||
[Fact]
|
||||
public async Task CanReturnDataContent()
|
||||
{
|
||||
Mock<IMcpServer> mockServer = new();
|
||||
McpServerResource resource = McpServerResource.Create((IMcpServer server) =>
|
||||
Mock<McpServer> mockServer = new();
|
||||
McpServerResource resource = McpServerResource.Create((McpServer server) =>
|
||||
{
|
||||
Assert.Same(mockServer.Object, server);
|
||||
return new DataContent(new byte[] { 0, 1, 2 }, "application/octet-stream");
|
||||
|
|
@ -642,8 +642,8 @@ public partial class McpServerResourceTests
|
|||
[Fact]
|
||||
public async Task CanReturnCollectionOfAIContent()
|
||||
{
|
||||
Mock<IMcpServer> mockServer = new();
|
||||
McpServerResource resource = McpServerResource.Create((IMcpServer server) =>
|
||||
Mock<McpServer> mockServer = new();
|
||||
McpServerResource resource = McpServerResource.Create((McpServer server) =>
|
||||
{
|
||||
Assert.Same(mockServer.Object, server);
|
||||
return new List<AIContent>
|
||||
|
|
|
|||
|
|
@ -32,12 +32,38 @@ public class McpServerTests : LoggedTest
|
|||
};
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Create_Should_Initialize_With_Valid_Parameters()
|
||||
{
|
||||
// Arrange & Act
|
||||
await using var transport = new TestServerTransport();
|
||||
await using McpServer server = McpServer.Create(transport, _options, LoggerFactory);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(server);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Create_Throws_For_Null_ServerTransport()
|
||||
{
|
||||
// Arrange, Act & Assert
|
||||
Assert.Throws<ArgumentNullException>("transport", () => McpServer.Create(null!, _options, LoggerFactory));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Create_Throws_For_Null_Options()
|
||||
{
|
||||
// Arrange, Act & Assert
|
||||
await using var transport = new TestServerTransport();
|
||||
Assert.Throws<ArgumentNullException>("serverOptions", () => McpServer.Create(transport, null!, LoggerFactory));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Constructor_Should_Initialize_With_Valid_Parameters()
|
||||
{
|
||||
// Arrange & Act
|
||||
await using var transport = new TestServerTransport();
|
||||
await using var server = McpServerFactory.Create(transport, _options, LoggerFactory);
|
||||
await using var server = McpServer.Create(transport, _options, LoggerFactory);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(server);
|
||||
|
|
@ -47,7 +73,7 @@ public class McpServerTests : LoggedTest
|
|||
public void Constructor_Throws_For_Null_Transport()
|
||||
{
|
||||
// Arrange, Act & Assert
|
||||
Assert.Throws<ArgumentNullException>(() => McpServerFactory.Create(null!, _options, LoggerFactory));
|
||||
Assert.Throws<ArgumentNullException>(() => McpServer.Create(null!, _options, LoggerFactory));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -55,7 +81,7 @@ public class McpServerTests : LoggedTest
|
|||
{
|
||||
// Arrange, Act & Assert
|
||||
await using var transport = new TestServerTransport();
|
||||
Assert.Throws<ArgumentNullException>(() => McpServerFactory.Create(transport, null!, LoggerFactory));
|
||||
Assert.Throws<ArgumentNullException>(() => McpServer.Create(transport, null!, LoggerFactory));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -63,7 +89,7 @@ public class McpServerTests : LoggedTest
|
|||
{
|
||||
// Arrange & Act
|
||||
await using var transport = new TestServerTransport();
|
||||
await using var server = McpServerFactory.Create(transport, _options, null);
|
||||
await using var server = McpServer.Create(transport, _options, null);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(server);
|
||||
|
|
@ -74,7 +100,7 @@ public class McpServerTests : LoggedTest
|
|||
{
|
||||
// Arrange & Act
|
||||
await using var transport = new TestServerTransport();
|
||||
await using var server = McpServerFactory.Create(transport, _options, LoggerFactory, null);
|
||||
await using var server = McpServer.Create(transport, _options, LoggerFactory, null);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(server);
|
||||
|
|
@ -85,7 +111,7 @@ public class McpServerTests : LoggedTest
|
|||
{
|
||||
// Arrange
|
||||
await using var transport = new TestServerTransport();
|
||||
await using var server = McpServerFactory.Create(transport, _options, LoggerFactory);
|
||||
await using var server = McpServer.Create(transport, _options, LoggerFactory);
|
||||
var runTask = server.RunAsync(TestContext.Current.CancellationToken);
|
||||
|
||||
// Act & Assert
|
||||
|
|
@ -100,7 +126,7 @@ public class McpServerTests : LoggedTest
|
|||
{
|
||||
// Arrange
|
||||
await using var transport = new TestServerTransport();
|
||||
await using var server = McpServerFactory.Create(transport, _options, LoggerFactory);
|
||||
await using var server = McpServer.Create(transport, _options, LoggerFactory);
|
||||
SetClientCapabilities(server, new ClientCapabilities());
|
||||
|
||||
var action = async () => await server.SampleAsync(new CreateMessageRequestParams { Messages = [] }, CancellationToken.None);
|
||||
|
|
@ -114,7 +140,7 @@ public class McpServerTests : LoggedTest
|
|||
{
|
||||
// Arrange
|
||||
await using var transport = new TestServerTransport();
|
||||
await using var server = McpServerFactory.Create(transport, _options, LoggerFactory);
|
||||
await using var server = McpServer.Create(transport, _options, LoggerFactory);
|
||||
SetClientCapabilities(server, new ClientCapabilities { Sampling = new SamplingCapability() });
|
||||
|
||||
var runTask = server.RunAsync(TestContext.Current.CancellationToken);
|
||||
|
|
@ -136,7 +162,7 @@ public class McpServerTests : LoggedTest
|
|||
{
|
||||
// Arrange
|
||||
await using var transport = new TestServerTransport();
|
||||
await using var server = McpServerFactory.Create(transport, _options, LoggerFactory);
|
||||
await using var server = McpServer.Create(transport, _options, LoggerFactory);
|
||||
SetClientCapabilities(server, new ClientCapabilities());
|
||||
|
||||
// Act & Assert
|
||||
|
|
@ -148,7 +174,7 @@ public class McpServerTests : LoggedTest
|
|||
{
|
||||
// Arrange
|
||||
await using var transport = new TestServerTransport();
|
||||
await using var server = McpServerFactory.Create(transport, _options, LoggerFactory);
|
||||
await using var server = McpServer.Create(transport, _options, LoggerFactory);
|
||||
SetClientCapabilities(server, new ClientCapabilities { Roots = new RootsCapability() });
|
||||
var runTask = server.RunAsync(TestContext.Current.CancellationToken);
|
||||
|
||||
|
|
@ -170,7 +196,7 @@ public class McpServerTests : LoggedTest
|
|||
{
|
||||
// Arrange
|
||||
await using var transport = new TestServerTransport();
|
||||
await using var server = McpServerFactory.Create(transport, _options, LoggerFactory);
|
||||
await using var server = McpServer.Create(transport, _options, LoggerFactory);
|
||||
SetClientCapabilities(server, new ClientCapabilities());
|
||||
|
||||
// Act & Assert
|
||||
|
|
@ -182,7 +208,7 @@ public class McpServerTests : LoggedTest
|
|||
{
|
||||
// Arrange
|
||||
await using var transport = new TestServerTransport();
|
||||
await using var server = McpServerFactory.Create(transport, _options, LoggerFactory);
|
||||
await using var server = McpServer.Create(transport, _options, LoggerFactory);
|
||||
SetClientCapabilities(server, new ClientCapabilities { Elicitation = new ElicitationCapability() });
|
||||
var runTask = server.RunAsync(TestContext.Current.CancellationToken);
|
||||
|
||||
|
|
@ -216,7 +242,7 @@ public class McpServerTests : LoggedTest
|
|||
[Fact]
|
||||
public async Task Can_Handle_Initialize_Requests()
|
||||
{
|
||||
AssemblyName expectedAssemblyName = (Assembly.GetEntryAssembly() ?? typeof(IMcpServer).Assembly).GetName();
|
||||
AssemblyName expectedAssemblyName = (Assembly.GetEntryAssembly() ?? typeof(McpServer).Assembly).GetName();
|
||||
await Can_Handle_Requests(
|
||||
serverCapabilities: null,
|
||||
method: RequestMethods.Initialize,
|
||||
|
|
@ -510,7 +536,7 @@ public class McpServerTests : LoggedTest
|
|||
var options = CreateOptions(serverCapabilities);
|
||||
configureOptions?.Invoke(options);
|
||||
|
||||
await using var server = McpServerFactory.Create(transport, options, LoggerFactory);
|
||||
await using var server = McpServer.Create(transport, options, LoggerFactory);
|
||||
|
||||
var runTask = server.RunAsync(TestContext.Current.CancellationToken);
|
||||
|
||||
|
|
@ -544,7 +570,7 @@ public class McpServerTests : LoggedTest
|
|||
await using var transport = new TestServerTransport();
|
||||
var options = CreateOptions(serverCapabilities);
|
||||
|
||||
var server = McpServerFactory.Create(transport, options, LoggerFactory);
|
||||
var server = McpServer.Create(transport, options, LoggerFactory);
|
||||
await server.DisposeAsync();
|
||||
}
|
||||
|
||||
|
|
@ -589,7 +615,7 @@ public class McpServerTests : LoggedTest
|
|||
public async Task Can_SendMessage_Before_RunAsync()
|
||||
{
|
||||
await using var transport = new TestServerTransport();
|
||||
await using var server = McpServerFactory.Create(transport, _options, LoggerFactory);
|
||||
await using var server = McpServer.Create(transport, _options, LoggerFactory);
|
||||
|
||||
var logNotification = new JsonRpcNotification
|
||||
{
|
||||
|
|
@ -605,22 +631,22 @@ public class McpServerTests : LoggedTest
|
|||
Assert.Same(logNotification, transport.SentMessages[0]);
|
||||
}
|
||||
|
||||
private static void SetClientCapabilities(IMcpServer server, ClientCapabilities capabilities)
|
||||
private static void SetClientCapabilities(McpServer server, ClientCapabilities capabilities)
|
||||
{
|
||||
PropertyInfo? property = server.GetType().GetProperty("ClientCapabilities", BindingFlags.Public | BindingFlags.Instance);
|
||||
Assert.NotNull(property);
|
||||
property.SetValue(server, capabilities);
|
||||
FieldInfo? field = server.GetType().GetField("_clientCapabilities", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
Assert.NotNull(field);
|
||||
field.SetValue(server, capabilities);
|
||||
}
|
||||
|
||||
private sealed class TestServerForIChatClient(bool supportsSampling) : IMcpServer
|
||||
private sealed class TestServerForIChatClient(bool supportsSampling) : McpServer
|
||||
{
|
||||
public ClientCapabilities? ClientCapabilities =>
|
||||
public override ClientCapabilities? ClientCapabilities =>
|
||||
supportsSampling ? new ClientCapabilities { Sampling = new SamplingCapability() } :
|
||||
null;
|
||||
|
||||
public McpServerOptions ServerOptions => new();
|
||||
public override McpServerOptions ServerOptions => new();
|
||||
|
||||
public Task<JsonRpcResponse> SendRequestAsync(JsonRpcRequest request, CancellationToken cancellationToken)
|
||||
public override Task<JsonRpcResponse> SendRequestAsync(JsonRpcRequest request, CancellationToken cancellationToken)
|
||||
{
|
||||
CreateMessageRequestParams? rp = JsonSerializer.Deserialize<CreateMessageRequestParams>(request.Params, McpJsonUtilities.DefaultOptions);
|
||||
|
||||
|
|
@ -653,17 +679,17 @@ public class McpServerTests : LoggedTest
|
|||
});
|
||||
}
|
||||
|
||||
public ValueTask DisposeAsync() => default;
|
||||
public override ValueTask DisposeAsync() => default;
|
||||
|
||||
public string? SessionId => throw new NotImplementedException();
|
||||
public Implementation? ClientInfo => throw new NotImplementedException();
|
||||
public IServiceProvider? Services => throw new NotImplementedException();
|
||||
public LoggingLevel? LoggingLevel => throw new NotImplementedException();
|
||||
public Task SendMessageAsync(JsonRpcMessage message, CancellationToken cancellationToken = default) =>
|
||||
public override string? SessionId => 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 Task RunAsync(CancellationToken cancellationToken = default) =>
|
||||
public override Task RunAsync(CancellationToken cancellationToken = default) =>
|
||||
throw new NotImplementedException();
|
||||
public IAsyncDisposable RegisterNotificationHandler(string method, Func<JsonRpcNotification, CancellationToken, ValueTask> handler) =>
|
||||
public override IAsyncDisposable RegisterNotificationHandler(string method, Func<JsonRpcNotification, CancellationToken, ValueTask> handler) =>
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
|
|
@ -683,7 +709,7 @@ public class McpServerTests : LoggedTest
|
|||
})],
|
||||
};
|
||||
|
||||
var server = McpServerFactory.Create(transport, options, LoggerFactory);
|
||||
var server = McpServer.Create(transport, options, LoggerFactory);
|
||||
|
||||
Task serverTask = server.RunAsync(TestContext.Current.CancellationToken);
|
||||
|
||||
|
|
|
|||
|
|
@ -48,11 +48,11 @@ public partial class McpServerToolTests
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SupportsIMcpServer()
|
||||
public async Task SupportsMcpServer()
|
||||
{
|
||||
Mock<IMcpServer> mockServer = new();
|
||||
Mock<McpServer> mockServer = new();
|
||||
|
||||
McpServerTool tool = McpServerTool.Create((IMcpServer server) =>
|
||||
McpServerTool tool = McpServerTool.Create((McpServer server) =>
|
||||
{
|
||||
Assert.Same(mockServer.Object, server);
|
||||
return "42";
|
||||
|
|
@ -75,7 +75,7 @@ public partial class McpServerToolTests
|
|||
sc.AddSingleton(expectedMyService);
|
||||
IServiceProvider services = sc.BuildServiceProvider();
|
||||
|
||||
Mock<IMcpServer> mockServer = new();
|
||||
Mock<McpServer> mockServer = new();
|
||||
mockServer.SetupGet(s => s.Services).Returns(services);
|
||||
|
||||
MethodInfo? testMethod = typeof(HasCtorWithSpecialParameters).GetMethod(nameof(HasCtorWithSpecialParameters.TestTool));
|
||||
|
|
@ -98,11 +98,11 @@ public partial class McpServerToolTests
|
|||
private sealed class HasCtorWithSpecialParameters
|
||||
{
|
||||
private readonly MyService _ms;
|
||||
private readonly IMcpServer _server;
|
||||
private readonly McpServer _server;
|
||||
private readonly RequestContext<CallToolRequestParams> _request;
|
||||
private readonly IProgress<ProgressNotificationValue> _progress;
|
||||
|
||||
public HasCtorWithSpecialParameters(MyService ms, IMcpServer server, RequestContext<CallToolRequestParams> request, IProgress<ProgressNotificationValue> progress)
|
||||
public HasCtorWithSpecialParameters(MyService ms, McpServer server, RequestContext<CallToolRequestParams> request, IProgress<ProgressNotificationValue> progress)
|
||||
{
|
||||
Assert.NotNull(ms);
|
||||
Assert.NotNull(server);
|
||||
|
|
@ -162,7 +162,7 @@ public partial class McpServerToolTests
|
|||
|
||||
Assert.DoesNotContain("actualMyService", JsonSerializer.Serialize(tool.ProtocolTool.InputSchema, McpJsonUtilities.DefaultOptions));
|
||||
|
||||
Mock<IMcpServer> mockServer = new();
|
||||
Mock<McpServer> mockServer = new();
|
||||
|
||||
var ex = await Assert.ThrowsAsync<ArgumentException>(async () => await tool.InvokeAsync(
|
||||
new RequestContext<CallToolRequestParams>(mockServer.Object, CreateTestJsonRpcRequest()),
|
||||
|
|
@ -192,7 +192,7 @@ public partial class McpServerToolTests
|
|||
}, new() { Services = services });
|
||||
|
||||
var result = await tool.InvokeAsync(
|
||||
new RequestContext<CallToolRequestParams>(new Mock<IMcpServer>().Object, CreateTestJsonRpcRequest()),
|
||||
new RequestContext<CallToolRequestParams>(new Mock<McpServer>().Object, CreateTestJsonRpcRequest()),
|
||||
TestContext.Current.CancellationToken);
|
||||
Assert.Equal("42", (result.Content[0] as TextContentBlock)?.Text);
|
||||
}
|
||||
|
|
@ -207,7 +207,7 @@ public partial class McpServerToolTests
|
|||
options);
|
||||
|
||||
var result = await tool1.InvokeAsync(
|
||||
new RequestContext<CallToolRequestParams>(new Mock<IMcpServer>().Object, CreateTestJsonRpcRequest()),
|
||||
new RequestContext<CallToolRequestParams>(new Mock<McpServer>().Object, CreateTestJsonRpcRequest()),
|
||||
TestContext.Current.CancellationToken);
|
||||
Assert.Equal("""{"disposals":1}""", (result.Content[0] as TextContentBlock)?.Text);
|
||||
}
|
||||
|
|
@ -222,7 +222,7 @@ public partial class McpServerToolTests
|
|||
options);
|
||||
|
||||
var result = await tool1.InvokeAsync(
|
||||
new RequestContext<CallToolRequestParams>(new Mock<IMcpServer>().Object, CreateTestJsonRpcRequest()),
|
||||
new RequestContext<CallToolRequestParams>(new Mock<McpServer>().Object, CreateTestJsonRpcRequest()),
|
||||
TestContext.Current.CancellationToken);
|
||||
Assert.Equal("""{"asyncDisposals":1}""", (result.Content[0] as TextContentBlock)?.Text);
|
||||
}
|
||||
|
|
@ -241,7 +241,7 @@ public partial class McpServerToolTests
|
|||
options);
|
||||
|
||||
var result = await tool1.InvokeAsync(
|
||||
new RequestContext<CallToolRequestParams>(new Mock<IMcpServer>().Object, CreateTestJsonRpcRequest()) { Services = services },
|
||||
new RequestContext<CallToolRequestParams>(new Mock<McpServer>().Object, CreateTestJsonRpcRequest()) { Services = services },
|
||||
TestContext.Current.CancellationToken);
|
||||
Assert.Equal("""{"asyncDisposals":1,"disposals":0}""", (result.Content[0] as TextContentBlock)?.Text);
|
||||
}
|
||||
|
|
@ -250,8 +250,8 @@ public partial class McpServerToolTests
|
|||
[Fact]
|
||||
public async Task CanReturnCollectionOfAIContent()
|
||||
{
|
||||
Mock<IMcpServer> mockServer = new();
|
||||
McpServerTool tool = McpServerTool.Create((IMcpServer server) =>
|
||||
Mock<McpServer> mockServer = new();
|
||||
McpServerTool tool = McpServerTool.Create((McpServer server) =>
|
||||
{
|
||||
Assert.Same(mockServer.Object, server);
|
||||
return new List<AIContent> {
|
||||
|
|
@ -282,8 +282,8 @@ public partial class McpServerToolTests
|
|||
[InlineData("data:audio/wav;base64,1234", "audio")]
|
||||
public async Task CanReturnSingleAIContent(string data, string type)
|
||||
{
|
||||
Mock<IMcpServer> mockServer = new();
|
||||
McpServerTool tool = McpServerTool.Create((IMcpServer server) =>
|
||||
Mock<McpServer> mockServer = new();
|
||||
McpServerTool tool = McpServerTool.Create((McpServer server) =>
|
||||
{
|
||||
Assert.Same(mockServer.Object, server);
|
||||
return type switch
|
||||
|
|
@ -325,8 +325,8 @@ public partial class McpServerToolTests
|
|||
[Fact]
|
||||
public async Task CanReturnNullAIContent()
|
||||
{
|
||||
Mock<IMcpServer> mockServer = new();
|
||||
McpServerTool tool = McpServerTool.Create((IMcpServer server) =>
|
||||
Mock<McpServer> mockServer = new();
|
||||
McpServerTool tool = McpServerTool.Create((McpServer server) =>
|
||||
{
|
||||
Assert.Same(mockServer.Object, server);
|
||||
return (string?)null;
|
||||
|
|
@ -340,8 +340,8 @@ public partial class McpServerToolTests
|
|||
[Fact]
|
||||
public async Task CanReturnString()
|
||||
{
|
||||
Mock<IMcpServer> mockServer = new();
|
||||
McpServerTool tool = McpServerTool.Create((IMcpServer server) =>
|
||||
Mock<McpServer> mockServer = new();
|
||||
McpServerTool tool = McpServerTool.Create((McpServer server) =>
|
||||
{
|
||||
Assert.Same(mockServer.Object, server);
|
||||
return "42";
|
||||
|
|
@ -356,8 +356,8 @@ public partial class McpServerToolTests
|
|||
[Fact]
|
||||
public async Task CanReturnCollectionOfStrings()
|
||||
{
|
||||
Mock<IMcpServer> mockServer = new();
|
||||
McpServerTool tool = McpServerTool.Create((IMcpServer server) =>
|
||||
Mock<McpServer> mockServer = new();
|
||||
McpServerTool tool = McpServerTool.Create((McpServer server) =>
|
||||
{
|
||||
Assert.Same(mockServer.Object, server);
|
||||
return new List<string> { "42", "43" };
|
||||
|
|
@ -372,8 +372,8 @@ public partial class McpServerToolTests
|
|||
[Fact]
|
||||
public async Task CanReturnMcpContent()
|
||||
{
|
||||
Mock<IMcpServer> mockServer = new();
|
||||
McpServerTool tool = McpServerTool.Create((IMcpServer server) =>
|
||||
Mock<McpServer> mockServer = new();
|
||||
McpServerTool tool = McpServerTool.Create((McpServer server) =>
|
||||
{
|
||||
Assert.Same(mockServer.Object, server);
|
||||
return new TextContentBlock { Text = "42" };
|
||||
|
|
@ -389,8 +389,8 @@ public partial class McpServerToolTests
|
|||
[Fact]
|
||||
public async Task CanReturnCollectionOfMcpContent()
|
||||
{
|
||||
Mock<IMcpServer> mockServer = new();
|
||||
McpServerTool tool = McpServerTool.Create((IMcpServer server) =>
|
||||
Mock<McpServer> mockServer = new();
|
||||
McpServerTool tool = McpServerTool.Create((McpServer server) =>
|
||||
{
|
||||
Assert.Same(mockServer.Object, server);
|
||||
return (IList<ContentBlock>)
|
||||
|
|
@ -416,8 +416,8 @@ public partial class McpServerToolTests
|
|||
Content = new List<ContentBlock> { new TextContentBlock { Text = "text" }, new ImageContentBlock { Data = "1234", MimeType = "image/png" } }
|
||||
};
|
||||
|
||||
Mock<IMcpServer> mockServer = new();
|
||||
McpServerTool tool = McpServerTool.Create((IMcpServer server) =>
|
||||
Mock<McpServer> mockServer = new();
|
||||
McpServerTool tool = McpServerTool.Create((McpServer server) =>
|
||||
{
|
||||
Assert.Same(mockServer.Object, server);
|
||||
return response;
|
||||
|
|
@ -436,7 +436,7 @@ public partial class McpServerToolTests
|
|||
[Fact]
|
||||
public async Task SupportsSchemaCreateOptions()
|
||||
{
|
||||
AIJsonSchemaCreateOptions schemaCreateOptions = new ()
|
||||
AIJsonSchemaCreateOptions schemaCreateOptions = new()
|
||||
{
|
||||
TransformSchemaNode = (context, node) =>
|
||||
{
|
||||
|
|
@ -462,7 +462,7 @@ public partial class McpServerToolTests
|
|||
{
|
||||
JsonSerializerOptions options = new() { TypeInfoResolver = new DefaultJsonTypeInfoResolver() };
|
||||
McpServerTool tool = McpServerTool.Create(() => value, new() { Name = "tool", UseStructuredContent = true, SerializerOptions = options });
|
||||
var mockServer = new Mock<IMcpServer>();
|
||||
var mockServer = new Mock<McpServer>();
|
||||
var request = new RequestContext<CallToolRequestParams>(mockServer.Object, CreateTestJsonRpcRequest())
|
||||
{
|
||||
Params = new CallToolRequestParams { Name = "tool" },
|
||||
|
|
@ -480,7 +480,7 @@ public partial class McpServerToolTests
|
|||
public async Task StructuredOutput_Enabled_VoidReturningTools_ReturnsExpectedSchema()
|
||||
{
|
||||
McpServerTool tool = McpServerTool.Create(() => { });
|
||||
var mockServer = new Mock<IMcpServer>();
|
||||
var mockServer = new Mock<McpServer>();
|
||||
var request = new RequestContext<CallToolRequestParams>(mockServer.Object, CreateTestJsonRpcRequest())
|
||||
{
|
||||
Params = new CallToolRequestParams { Name = "tool" },
|
||||
|
|
@ -520,7 +520,7 @@ public partial class McpServerToolTests
|
|||
{
|
||||
JsonSerializerOptions options = new() { TypeInfoResolver = new DefaultJsonTypeInfoResolver() };
|
||||
McpServerTool tool = McpServerTool.Create(() => value, new() { UseStructuredContent = false, SerializerOptions = options });
|
||||
var mockServer = new Mock<IMcpServer>();
|
||||
var mockServer = new Mock<McpServer>();
|
||||
var request = new RequestContext<CallToolRequestParams>(mockServer.Object, CreateTestJsonRpcRequest())
|
||||
{
|
||||
Params = new CallToolRequestParams { Name = "tool" },
|
||||
|
|
|
|||
Loading…
Reference in a new issue