Overhaul McpClientFactory/McpServerFactory (#87)
Handlers are now specified before connecting the client/server. Otherwise, race conditions exist. Handlers move into being a part of the McpClientOptions/McpServerOptions, so that they're provided to the factories. Where relevant, the handlers are specified as part of the capability descriptors, so that they go hand in hand. The factories are no longer stateful. Instead of allocating a factory and then calling a create method on it, you just call a static factory method.
This commit is contained in:
parent
63b24a4036
commit
08b0a04dab
1 changed files with 1306 additions and 2243 deletions
|
|
@ -1,54 +1,43 @@
|
|||
using McpDotNet.Protocol.Messages;
|
||||
using McpDotNet.Protocol.Types;
|
||||
using McpDotNet.Protocol.Types;
|
||||
using McpDotNet.Server;
|
||||
|
||||
namespace McpDotNet.Tests.Server;
|
||||
|
||||
public class McpServerDelegatesTests
|
||||
public class McpServerHandlerTests
|
||||
{
|
||||
[Fact]
|
||||
public void Applies_All_Given_Delegates()
|
||||
public void AllPropertiesAreSettable()
|
||||
{
|
||||
var container = new McpServerDelegates();
|
||||
var server = new ExposeSetHandlersServer();
|
||||
var handlers = new McpServerHandlers();
|
||||
|
||||
container.ListToolsHandler = (p, c) => Task.FromResult(new ListToolsResult());
|
||||
container.CallToolHandler = (p, c) => Task.FromResult(new CallToolResponse());
|
||||
container.ListPromptsHandler = (p, c) => Task.FromResult(new ListPromptsResult());
|
||||
container.GetPromptHandler = (p, c) => Task.FromResult(new GetPromptResult());
|
||||
container.ListResourcesHandler = (p, c) => Task.FromResult(new ListResourcesResult());
|
||||
container.ReadResourceHandler = (p, c) => Task.FromResult(new ReadResourceResult());
|
||||
container.GetCompletionHandler = (p, c) => Task.FromResult(new CompleteResult());
|
||||
container.SubscribeToResourcesHandler = (s, c) => Task.CompletedTask;
|
||||
container.UnsubscribeFromResourcesHandler = (s, c) => Task.CompletedTask;
|
||||
Assert.Null(handlers.ListToolsHandler);
|
||||
Assert.Null(handlers.CallToolHandler);
|
||||
Assert.Null(handlers.ListPromptsHandler);
|
||||
Assert.Null(handlers.GetPromptHandler);
|
||||
Assert.Null(handlers.ListResourcesHandler);
|
||||
Assert.Null(handlers.ReadResourceHandler);
|
||||
Assert.Null(handlers.GetCompletionHandler);
|
||||
Assert.Null(handlers.SubscribeToResourcesHandler);
|
||||
Assert.Null(handlers.UnsubscribeFromResourcesHandler);
|
||||
|
||||
container.Apply(server);
|
||||
handlers.ListToolsHandler = (p, c) => Task.FromResult(new ListToolsResult());
|
||||
handlers.CallToolHandler = (p, c) => Task.FromResult(new CallToolResponse());
|
||||
handlers.ListPromptsHandler = (p, c) => Task.FromResult(new ListPromptsResult());
|
||||
handlers.GetPromptHandler = (p, c) => Task.FromResult(new GetPromptResult());
|
||||
handlers.ListResourcesHandler = (p, c) => Task.FromResult(new ListResourcesResult());
|
||||
handlers.ReadResourceHandler = (p, c) => Task.FromResult(new ReadResourceResult());
|
||||
handlers.GetCompletionHandler = (p, c) => Task.FromResult(new CompleteResult());
|
||||
handlers.SubscribeToResourcesHandler = (s, c) => Task.CompletedTask;
|
||||
handlers.UnsubscribeFromResourcesHandler = (s, c) => Task.CompletedTask;
|
||||
|
||||
Assert.Equal(container.ListToolsHandler, server.Handlers[OperationNames.ListTools]);
|
||||
Assert.Equal(container.CallToolHandler, server.Handlers[OperationNames.CallTool]);
|
||||
Assert.Equal(container.ListPromptsHandler, server.Handlers[OperationNames.ListPrompts]);
|
||||
Assert.Equal(container.GetPromptHandler, server.Handlers[OperationNames.GetPrompt]);
|
||||
Assert.Equal(container.ListResourcesHandler, server.Handlers[OperationNames.ListResources]);
|
||||
Assert.Equal(container.ReadResourceHandler, server.Handlers[OperationNames.ReadResource]);
|
||||
Assert.Equal(container.GetCompletionHandler, server.Handlers[OperationNames.GetCompletion]);
|
||||
Assert.Equal(container.SubscribeToResourcesHandler, server.Handlers[OperationNames.SubscribeToResources]);
|
||||
Assert.Equal(container.UnsubscribeFromResourcesHandler, server.Handlers[OperationNames.UnsubscribeFromResources]);
|
||||
}
|
||||
|
||||
private sealed class ExposeSetHandlersServer : IMcpServer
|
||||
{
|
||||
public Dictionary<string, Delegate> Handlers = [];
|
||||
|
||||
public void SetOperationHandler(string operationName, Delegate handler) => Handlers[operationName] = handler;
|
||||
|
||||
public ValueTask DisposeAsync() => default;
|
||||
public bool IsInitialized => throw new NotImplementedException();
|
||||
public ClientCapabilities? ClientCapabilities => throw new NotImplementedException();
|
||||
public Implementation? ClientInfo => throw new NotImplementedException();
|
||||
public IServiceProvider? ServiceProvider => throw new NotImplementedException();
|
||||
public void AddNotificationHandler(string method, Func<JsonRpcNotification, Task> handler) => throw new NotImplementedException();
|
||||
public Task SendMessageAsync(IJsonRpcMessage message, CancellationToken cancellationToken = default) => throw new NotImplementedException();
|
||||
public Task<T> SendRequestAsync<T>(JsonRpcRequest request, CancellationToken cancellationToken) where T : class => throw new NotImplementedException();
|
||||
public Task StartAsync(CancellationToken cancellationToken = default) => throw new NotImplementedException();
|
||||
Assert.NotNull(handlers.ListToolsHandler);
|
||||
Assert.NotNull(handlers.CallToolHandler);
|
||||
Assert.NotNull(handlers.ListPromptsHandler);
|
||||
Assert.NotNull(handlers.GetPromptHandler);
|
||||
Assert.NotNull(handlers.ListResourcesHandler);
|
||||
Assert.NotNull(handlers.ReadResourceHandler);
|
||||
Assert.NotNull(handlers.GetCompletionHandler);
|
||||
Assert.NotNull(handlers.SubscribeToResourcesHandler);
|
||||
Assert.NotNull(handlers.UnsubscribeFromResourcesHandler);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue