Improve how to host McpServer (#30)
This commit is contained in:
parent
30f3f192ca
commit
257a97a659
18 changed files with 538 additions and 45 deletions
|
|
@ -17,6 +17,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "McpDotNet.Extensions.AI", "
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "McpDotNet.Extensions.AI.Tests", "tests\McpDotNet.Extensions.AI.Tests\McpDotNet.Extensions.AI.Tests.csproj", "{67BEF596-AD39-4BDD-B505-31DE7FF0C8D2}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "McpDotNet.Extensions.AI.Tests", "tests\McpDotNet.Extensions.AI.Tests\McpDotNet.Extensions.AI.Tests.csproj", "{67BEF596-AD39-4BDD-B505-31DE7FF0C8D2}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestServerWithHosting", "samples\TestServerWithHosting\TestServerWithHosting.csproj", "{6499876E-2F76-44A8-B6EB-5B889C6E9B7F}"
|
||||||
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{02EA681E-C7D8-13C7-8484-4AC65E1B71E8}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
|
@ -51,10 +55,19 @@ Global
|
||||||
{67BEF596-AD39-4BDD-B505-31DE7FF0C8D2}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{67BEF596-AD39-4BDD-B505-31DE7FF0C8D2}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{67BEF596-AD39-4BDD-B505-31DE7FF0C8D2}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{67BEF596-AD39-4BDD-B505-31DE7FF0C8D2}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{67BEF596-AD39-4BDD-B505-31DE7FF0C8D2}.Release|Any CPU.Build.0 = Release|Any CPU
|
{67BEF596-AD39-4BDD-B505-31DE7FF0C8D2}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{6499876E-2F76-44A8-B6EB-5B889C6E9B7F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{6499876E-2F76-44A8-B6EB-5B889C6E9B7F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{6499876E-2F76-44A8-B6EB-5B889C6E9B7F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{6499876E-2F76-44A8-B6EB-5B889C6E9B7F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
|
GlobalSection(NestedProjects) = preSolution
|
||||||
|
{76E295FA-9E85-7B99-332A-2CDBFCD5860A} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
|
||||||
|
{CA0BB450-1903-2F92-A68D-1285976551D6} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
|
||||||
|
{6499876E-2F76-44A8-B6EB-5B889C6E9B7F} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
|
||||||
|
EndGlobalSection
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
SolutionGuid = {384A3888-751F-4D75-9AE5-587330582D89}
|
SolutionGuid = {384A3888-751F-4D75-9AE5-587330582D89}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
|
|
|
||||||
37
samples/TestServerWithHosting/Program.cs
Normal file
37
samples/TestServerWithHosting/Program.cs
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
using McpDotNet;
|
||||||
|
using Microsoft.Extensions.Hosting;
|
||||||
|
using Serilog;
|
||||||
|
|
||||||
|
Log.Logger = new LoggerConfiguration()
|
||||||
|
.MinimumLevel.Verbose() // Capture all log levels
|
||||||
|
.WriteTo.File(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "logs", "TestServer_.log"),
|
||||||
|
rollingInterval: RollingInterval.Day,
|
||||||
|
outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Message:lj}{NewLine}{Exception}")
|
||||||
|
.WriteTo.Debug()
|
||||||
|
.WriteTo.Console()
|
||||||
|
.CreateLogger();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Log.Information("Starting server...");
|
||||||
|
|
||||||
|
var builder = Host.CreateApplicationBuilder(args);
|
||||||
|
builder.Services.AddSerilog();
|
||||||
|
builder.Services.AddMcpServer()
|
||||||
|
.WithStdioServerTransport()
|
||||||
|
.WithCallToolHandler(async (r, ct) => new McpDotNet.Protocol.Types.CallToolResponse());
|
||||||
|
|
||||||
|
var app = builder.Build();
|
||||||
|
|
||||||
|
await app.RunAsync();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Fatal(ex, "Host terminated unexpectedly");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
await Log.CloseAndFlushAsync();
|
||||||
|
}
|
||||||
22
samples/TestServerWithHosting/TestServerWithHosting.csproj
Normal file
22
samples/TestServerWithHosting/TestServerWithHosting.csproj
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.0" />
|
||||||
|
<PackageReference Include="Serilog.Extensions.Hosting" Version="9.0.0" />
|
||||||
|
<PackageReference Include="Serilog.Sinks.Console" Version="6.0.0" />
|
||||||
|
<PackageReference Include="Serilog.Sinks.Debug" Version="3.0.0" />
|
||||||
|
<PackageReference Include="Serilog.Sinks.File" Version="6.0.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\src\mcpdotnet\mcpdotnet.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
22
src/mcpdotnet/Configuration/DefaultMcpServerBuilder.cs
Normal file
22
src/mcpdotnet/Configuration/DefaultMcpServerBuilder.cs
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
|
namespace McpDotNet.Configuration;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Default implementation of <see cref="IMcpServerBuilder"/>.
|
||||||
|
/// </summary>
|
||||||
|
internal class DefaultMcpServerBuilder : IMcpServerBuilder
|
||||||
|
{
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public IServiceCollection Services { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="DefaultMcpServerBuilder"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="services"></param>
|
||||||
|
/// <exception cref="ArgumentNullException"></exception>
|
||||||
|
public DefaultMcpServerBuilder(IServiceCollection services)
|
||||||
|
{
|
||||||
|
Services = services ?? throw new ArgumentNullException(nameof(services));
|
||||||
|
}
|
||||||
|
}
|
||||||
15
src/mcpdotnet/Configuration/IMcpServerBuilder.cs
Normal file
15
src/mcpdotnet/Configuration/IMcpServerBuilder.cs
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
using McpDotNet.Server;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
|
namespace McpDotNet.Configuration;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Builder for configuring <see cref="IMcpServer"/> instances.
|
||||||
|
/// </summary>
|
||||||
|
public interface IMcpServerBuilder
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the service collection.
|
||||||
|
/// </summary>
|
||||||
|
IServiceCollection Services { get; }
|
||||||
|
}
|
||||||
132
src/mcpdotnet/Configuration/McpServerBuilderExtensions.cs
Normal file
132
src/mcpdotnet/Configuration/McpServerBuilderExtensions.cs
Normal file
|
|
@ -0,0 +1,132 @@
|
||||||
|
using McpDotNet.Configuration;
|
||||||
|
using McpDotNet.Protocol.Transport;
|
||||||
|
using McpDotNet.Protocol.Types;
|
||||||
|
using McpDotNet.Server;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
|
namespace McpDotNet;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Extension to configure the MCP server
|
||||||
|
/// </summary>
|
||||||
|
public static class McpServerBuilderExtensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a server transport that uses stdin/stdout for communication.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="builder">The builder instance.</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static IMcpServerBuilder WithStdioServerTransport(this IMcpServerBuilder builder)
|
||||||
|
{
|
||||||
|
builder.Services.AddSingleton<IServerTransport, StdioServerTransport>();
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the handler for list tools requests.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="builder">The builder instance.</param>
|
||||||
|
/// <param name="handler">The handler.</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static IMcpServerBuilder WithListToolsHandler(this IMcpServerBuilder builder, Func<ListToolsRequestParams, CancellationToken, Task<ListToolsResult>> handler)
|
||||||
|
{
|
||||||
|
builder.Services.Configure<McpServerDelegates>(s => s.ListToolsHandler = handler);
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the handler for call tool requests.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="builder">The builder instance.</param>
|
||||||
|
/// <param name="handler">The handler.</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static IMcpServerBuilder WithCallToolHandler(this IMcpServerBuilder builder, Func<CallToolRequestParams, CancellationToken, Task<CallToolResponse>> handler)
|
||||||
|
{
|
||||||
|
builder.Services.Configure<McpServerDelegates>(s => s.CallToolHandler = handler);
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the handler for list prompts requests.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="builder">The builder instance.</param>
|
||||||
|
/// <param name="handler">The handler.</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static IMcpServerBuilder WithListPromptsHandler(this IMcpServerBuilder builder, Func<ListPromptsRequestParams, CancellationToken, Task<ListPromptsResult>> handler)
|
||||||
|
{
|
||||||
|
builder.Services.Configure<McpServerDelegates>(s => s.ListPromptsHandler = handler);
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the handler for get prompt requests.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="builder">The builder instance.</param>
|
||||||
|
/// <param name="handler">The handler.</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static IMcpServerBuilder WithGetPromptHandler(this IMcpServerBuilder builder, Func<GetPromptRequestParams, CancellationToken, Task<GetPromptResult>> handler)
|
||||||
|
{
|
||||||
|
builder.Services.Configure<McpServerDelegates>(s => s.GetPromptHandler = handler);
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the handler for list resources requests.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="builder">The builder instance.</param>
|
||||||
|
/// <param name="handler">The handler.</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static IMcpServerBuilder WithListResourcesHandler(this IMcpServerBuilder builder, Func<ListResourcesRequestParams, CancellationToken, Task<ListResourcesResult>> handler)
|
||||||
|
{
|
||||||
|
builder.Services.Configure<McpServerDelegates>(s => s.ListResourcesHandler = handler);
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the handler for read resources requests.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="builder">The builder instance.</param>
|
||||||
|
/// <param name="handler">The handler.</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static IMcpServerBuilder WithReadResourceHandler(this IMcpServerBuilder builder, Func<ReadResourceRequestParams, CancellationToken, Task<ReadResourceResult>> handler)
|
||||||
|
{
|
||||||
|
builder.Services.Configure<McpServerDelegates>(s => s.ReadResourceHandler = handler);
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the handler for get resources requests.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="builder">The builder instance.</param>
|
||||||
|
/// <param name="handler">The handler.</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static IMcpServerBuilder WithGetCompletionHandler(this IMcpServerBuilder builder, Func<CompleteRequestParams, CancellationToken, Task<CompleteResult>> handler)
|
||||||
|
{
|
||||||
|
builder.Services.Configure<McpServerDelegates>(s => s.GetCompletionHandler = handler);
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the handler for subscribe to resources messages.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="builder">The builder instance.</param>
|
||||||
|
/// <param name="handler">The handler.</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static IMcpServerBuilder WithSubscribeToResourcesHandler(this IMcpServerBuilder builder, Func<string, CancellationToken, Task> handler)
|
||||||
|
{
|
||||||
|
builder.Services.Configure<McpServerDelegates>(s => s.SubscribeToResourcesHandler = handler);
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets or sets the handler for subscribe to resources messages.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="builder">The builder instance.</param>
|
||||||
|
/// <param name="handler">The handler.</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static IMcpServerBuilder WithUnsubscribeFromResourcesHandler(this IMcpServerBuilder builder, Func<string, CancellationToken, Task> handler)
|
||||||
|
{
|
||||||
|
builder.Services.Configure<McpServerDelegates>(s => s.UnsubscribeFromResourcesHandler = handler);
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,63 @@
|
||||||
|
using System.Reflection;
|
||||||
|
using McpDotNet.Configuration;
|
||||||
|
using McpDotNet.Hosting;
|
||||||
|
using McpDotNet.Protocol.Types;
|
||||||
|
using McpDotNet.Server;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
|
namespace McpDotNet;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Extension to host the MCP server
|
||||||
|
/// </summary>
|
||||||
|
public static class McpServerServiceCollectionExtension
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Adds the MCP server to the service collection with default options.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="services"></param>
|
||||||
|
/// <param name="configureOptions"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static IMcpServerBuilder AddMcpServer(this IServiceCollection services, Action<McpServerOptions>? configureOptions = null)
|
||||||
|
{
|
||||||
|
var options = CreateDefaultServerOptions();
|
||||||
|
configureOptions?.Invoke(options);
|
||||||
|
|
||||||
|
return AddMcpServer(services, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds the MCP server to the service collection with the provided options.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="services"></param>
|
||||||
|
/// <param name="serverOptions"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static IMcpServerBuilder AddMcpServer(this IServiceCollection services, McpServerOptions serverOptions)
|
||||||
|
{
|
||||||
|
services.AddSingleton(serverOptions);
|
||||||
|
services.AddSingleton<IMcpServerFactory, McpServerFactory>();
|
||||||
|
services.AddHostedService<McpServerHostedService>();
|
||||||
|
services.AddOptions();
|
||||||
|
|
||||||
|
services.AddSingleton<IMcpServer>(sp => sp.GetRequiredService<IMcpServerFactory>().CreateServer());
|
||||||
|
|
||||||
|
return new DefaultMcpServerBuilder(services);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static McpServerOptions CreateDefaultServerOptions()
|
||||||
|
{
|
||||||
|
var assemblyName = Assembly.GetEntryAssembly()?.GetName();
|
||||||
|
|
||||||
|
return new McpServerOptions()
|
||||||
|
{
|
||||||
|
ServerInfo = new Implementation() { Name = assemblyName?.Name ?? "McpServer", Version = assemblyName?.Version?.ToString() ?? "1.0.0" },
|
||||||
|
Capabilities = new ServerCapabilities()
|
||||||
|
{
|
||||||
|
Tools = new(),
|
||||||
|
Resources = new(),
|
||||||
|
Prompts = new(),
|
||||||
|
},
|
||||||
|
ProtocolVersion = "2024-11-05"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
28
src/mcpdotnet/Hosting/McpServerHostedService.cs
Normal file
28
src/mcpdotnet/Hosting/McpServerHostedService.cs
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
using McpDotNet.Server;
|
||||||
|
using Microsoft.Extensions.Hosting;
|
||||||
|
|
||||||
|
namespace McpDotNet.Hosting;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Hosted service for the MCP server.
|
||||||
|
/// </summary>
|
||||||
|
public class McpServerHostedService : BackgroundService
|
||||||
|
{
|
||||||
|
private readonly IMcpServer _server;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new instance of the McpServerHostedService.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="server">The MCP server instance</param>
|
||||||
|
/// <exception cref="ArgumentNullException"></exception>
|
||||||
|
public McpServerHostedService(IMcpServer server)
|
||||||
|
{
|
||||||
|
_server = server ?? throw new ArgumentNullException(nameof(server));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
||||||
|
{
|
||||||
|
await _server.StartAsync(stoppingToken);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using McpDotNet.Protocol.Messages;
|
|
||||||
using McpDotNet.Utils.Json;
|
|
||||||
using McpDotNet.Logging;
|
using McpDotNet.Logging;
|
||||||
|
using McpDotNet.Protocol.Messages;
|
||||||
|
using McpDotNet.Server;
|
||||||
|
using McpDotNet.Utils.Json;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
namespace McpDotNet.Protocol.Transport;
|
namespace McpDotNet.Protocol.Transport;
|
||||||
|
|
||||||
|
|
@ -19,6 +20,16 @@ public sealed class StdioServerTransport : TransportBase, IServerTransport
|
||||||
|
|
||||||
private string EndpointName => $"Server (stdio) ({_serverName})";
|
private string EndpointName => $"Server (stdio) ({_serverName})";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the StdioServerTransport class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="serverOptions">The server options.</param>
|
||||||
|
/// <param name="loggerFactory">A logger factory for creating loggers.</param>
|
||||||
|
public StdioServerTransport(McpServerOptions serverOptions, ILoggerFactory loggerFactory)
|
||||||
|
: this(serverOptions.ServerInfo.Name, loggerFactory)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the StdioServerTransport class.
|
/// Initializes a new instance of the StdioServerTransport class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -64,7 +75,7 @@ public sealed class StdioServerTransport : TransportBase, IServerTransport
|
||||||
{
|
{
|
||||||
var json = JsonSerializer.Serialize(message, _jsonOptions);
|
var json = JsonSerializer.Serialize(message, _jsonOptions);
|
||||||
_logger.TransportSendingMessage(EndpointName, id, json);
|
_logger.TransportSendingMessage(EndpointName, id, json);
|
||||||
|
|
||||||
using (Console.OpenStandardOutput())
|
using (Console.OpenStandardOutput())
|
||||||
{
|
{
|
||||||
await Console.Out.WriteLineAsync(json.AsMemory(), cancellationToken);
|
await Console.Out.WriteLineAsync(json.AsMemory(), cancellationToken);
|
||||||
|
|
@ -159,7 +170,7 @@ public sealed class StdioServerTransport : TransportBase, IServerTransport
|
||||||
private async Task CleanupAsync(CancellationToken cancellationToken)
|
private async Task CleanupAsync(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
_logger.TransportCleaningUp(EndpointName);
|
_logger.TransportCleaningUp(EndpointName);
|
||||||
|
|
||||||
_shutdownCts?.Cancel();
|
_shutdownCts?.Cancel();
|
||||||
_shutdownCts?.Dispose();
|
_shutdownCts?.Dispose();
|
||||||
_shutdownCts = null;
|
_shutdownCts = null;
|
||||||
|
|
|
||||||
13
src/mcpdotnet/Server/IMcpServerFactory.cs
Normal file
13
src/mcpdotnet/Server/IMcpServerFactory.cs
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
namespace McpDotNet.Server;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Factory for creating <see cref="IMcpServer"/> instances.
|
||||||
|
/// </summary>
|
||||||
|
public interface IMcpServerFactory
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new server instance.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
IMcpServer CreateServer();
|
||||||
|
}
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
|
|
||||||
using System.Text.Json.Nodes;
|
using System.Text.Json.Nodes;
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using McpDotNet.Protocol.Types;
|
|
||||||
using McpDotNet.Shared;
|
|
||||||
using McpDotNet.Protocol.Transport;
|
|
||||||
using McpDotNet.Logging;
|
using McpDotNet.Logging;
|
||||||
using McpDotNet.Protocol.Messages;
|
using McpDotNet.Protocol.Messages;
|
||||||
|
using McpDotNet.Protocol.Transport;
|
||||||
|
using McpDotNet.Protocol.Types;
|
||||||
|
using McpDotNet.Shared;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
namespace McpDotNet.Server;
|
namespace McpDotNet.Server;
|
||||||
|
|
||||||
|
|
@ -22,22 +22,22 @@ internal class McpServer : McpJsonRpcEndpoint, IMcpServer
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="transport">Transport to use for the server</param>
|
/// <param name="transport">Transport to use for the server</param>
|
||||||
/// <param name="options">Configuration options for this server, including capabilities.
|
/// <param name="options">Configuration options for this server, including capabilities.
|
||||||
/// Make sure to accurately reflect exactly what capabilities the server supports and does not support.</param>
|
/// Make sure to accurately reflect exactly what capabilities the server supports and does not support.</param>
|
||||||
/// <param name="serverInstructions">Optional server instructions to send to clients</param>
|
|
||||||
/// <param name="loggerFactory">Logger factory to use for logging</param>
|
/// <param name="loggerFactory">Logger factory to use for logging</param>
|
||||||
/// <exception cref="McpServerException"></exception>
|
/// <exception cref="McpServerException"></exception>
|
||||||
public McpServer(IServerTransport transport, McpServerOptions options, string? serverInstructions, ILoggerFactory loggerFactory)
|
public McpServer(IServerTransport transport, McpServerOptions options, ILoggerFactory loggerFactory)
|
||||||
: base(transport, loggerFactory)
|
: base(transport, loggerFactory)
|
||||||
{
|
{
|
||||||
_serverTransport = transport;
|
_serverTransport = transport;
|
||||||
_options = options;
|
_options = options;
|
||||||
_logger = loggerFactory.CreateLogger<McpServer>();
|
_logger = loggerFactory.CreateLogger<McpServer>();
|
||||||
ServerInstructions = serverInstructions;
|
ServerInstructions = options.ServerInstructions;
|
||||||
|
|
||||||
if (options.Capabilities?.Tools != null)
|
if (options.Capabilities?.Tools != null)
|
||||||
{
|
{
|
||||||
SetRequestHandler<ListToolsRequestParams, ListToolsResult>("tools/list",
|
SetRequestHandler<ListToolsRequestParams, ListToolsResult>("tools/list",
|
||||||
async (request) => {
|
async (request) =>
|
||||||
|
{
|
||||||
if (ListToolsHandler == null)
|
if (ListToolsHandler == null)
|
||||||
{
|
{
|
||||||
// Setting the capability, but not a handler means we have nothing to return to the server
|
// Setting the capability, but not a handler means we have nothing to return to the server
|
||||||
|
|
@ -49,7 +49,8 @@ internal class McpServer : McpJsonRpcEndpoint, IMcpServer
|
||||||
});
|
});
|
||||||
|
|
||||||
SetRequestHandler<CallToolRequestParams, CallToolResponse>("tools/call",
|
SetRequestHandler<CallToolRequestParams, CallToolResponse>("tools/call",
|
||||||
async (request) => {
|
async (request) =>
|
||||||
|
{
|
||||||
if (CallToolHandler == null)
|
if (CallToolHandler == null)
|
||||||
{
|
{
|
||||||
// Setting the capability, but not a handler means we have nothing to return to the server
|
// Setting the capability, but not a handler means we have nothing to return to the server
|
||||||
|
|
@ -265,7 +266,7 @@ internal class McpServer : McpJsonRpcEndpoint, IMcpServer
|
||||||
if (ClientCapabilities?.Roots == null)
|
if (ClientCapabilities?.Roots == null)
|
||||||
{
|
{
|
||||||
throw new McpServerException("Client does not support roots");
|
throw new McpServerException("Client does not support roots");
|
||||||
}
|
}
|
||||||
|
|
||||||
return await SendRequestAsync<ListRootsResult>(
|
return await SendRequestAsync<ListRootsResult>(
|
||||||
new JsonRpcRequest
|
new JsonRpcRequest
|
||||||
|
|
|
||||||
88
src/mcpdotnet/Server/McpServerDelegates.cs
Normal file
88
src/mcpdotnet/Server/McpServerDelegates.cs
Normal file
|
|
@ -0,0 +1,88 @@
|
||||||
|
using McpDotNet.Protocol.Types;
|
||||||
|
|
||||||
|
namespace McpDotNet.Server;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Container for delegates that can be applied to an MCP server.
|
||||||
|
/// </summary>
|
||||||
|
public class McpServerDelegates
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the handler for list tools requests.
|
||||||
|
/// </summary>
|
||||||
|
public Func<ListToolsRequestParams, CancellationToken, Task<ListToolsResult>>? ListToolsHandler { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the handler for call tool requests.
|
||||||
|
/// </summary>
|
||||||
|
public Func<CallToolRequestParams, CancellationToken, Task<CallToolResponse>>? CallToolHandler { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the handler for list prompts requests.
|
||||||
|
/// </summary>
|
||||||
|
public Func<ListPromptsRequestParams, CancellationToken, Task<ListPromptsResult>>? ListPromptsHandler { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the handler for get prompt requests.
|
||||||
|
/// </summary>
|
||||||
|
public Func<GetPromptRequestParams, CancellationToken, Task<GetPromptResult>>? GetPromptHandler { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the handler for list resources requests.
|
||||||
|
/// </summary>
|
||||||
|
public Func<ListResourcesRequestParams, CancellationToken, Task<ListResourcesResult>>? ListResourcesHandler { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the handler for read resources requests.
|
||||||
|
/// </summary>
|
||||||
|
public Func<ReadResourceRequestParams, CancellationToken, Task<ReadResourceResult>>? ReadResourceHandler { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the handler for get resources requests.
|
||||||
|
/// </summary>
|
||||||
|
public Func<CompleteRequestParams, CancellationToken, Task<CompleteResult>>? GetCompletionHandler { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the handler for subscribe to resources messages.
|
||||||
|
/// </summary>
|
||||||
|
public Func<string, CancellationToken, Task>? SubscribeToResourcesHandler { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the handler for subscribe to resources messages.
|
||||||
|
/// </summary>
|
||||||
|
public Func<string, CancellationToken, Task>? UnsubscribeFromResourcesHandler { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Applies the delegates to the server.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="server"></param>
|
||||||
|
public void Apply(IMcpServer server)
|
||||||
|
{
|
||||||
|
if (ListToolsHandler != null)
|
||||||
|
server.ListToolsHandler = ListToolsHandler;
|
||||||
|
|
||||||
|
if (CallToolHandler != null)
|
||||||
|
server.CallToolHandler = CallToolHandler;
|
||||||
|
|
||||||
|
if (ListPromptsHandler != null)
|
||||||
|
server.ListPromptsHandler = ListPromptsHandler;
|
||||||
|
|
||||||
|
if (GetPromptHandler != null)
|
||||||
|
server.GetPromptHandler = GetPromptHandler;
|
||||||
|
|
||||||
|
if (ListResourcesHandler != null)
|
||||||
|
server.ListResourcesHandler = ListResourcesHandler;
|
||||||
|
|
||||||
|
if (ReadResourceHandler != null)
|
||||||
|
server.ReadResourceHandler = ReadResourceHandler;
|
||||||
|
|
||||||
|
if (GetCompletionHandler != null)
|
||||||
|
server.GetCompletionHandler = GetCompletionHandler;
|
||||||
|
|
||||||
|
if (SubscribeToResourcesHandler != null)
|
||||||
|
server.SubscribeToResourcesHandler = SubscribeToResourcesHandler;
|
||||||
|
|
||||||
|
if (UnsubscribeFromResourcesHandler != null)
|
||||||
|
server.UnsubscribeFromResourcesHandler = UnsubscribeFromResourcesHandler;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
using Microsoft.Extensions.Logging;
|
using McpDotNet.Protocol.Transport;
|
||||||
using McpDotNet.Protocol.Transport;
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
|
||||||
namespace McpDotNet.Server;
|
namespace McpDotNet.Server;
|
||||||
|
|
||||||
|
|
@ -13,12 +14,12 @@ namespace McpDotNet.Server;
|
||||||
///
|
///
|
||||||
/// You must register handlers for all supported capabilities on the server instance, before calling BeginListeningAsync.
|
/// You must register handlers for all supported capabilities on the server instance, before calling BeginListeningAsync.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class McpServerFactory
|
public class McpServerFactory : IMcpServerFactory
|
||||||
{
|
{
|
||||||
private readonly IServerTransport _serverTransport;
|
private readonly IServerTransport _serverTransport;
|
||||||
private readonly McpServerOptions _options;
|
private readonly McpServerOptions _options;
|
||||||
private readonly ILoggerFactory _loggerFactory;
|
private readonly ILoggerFactory _loggerFactory;
|
||||||
private readonly string? _serverInstructions;
|
private readonly McpServerDelegates? _serverDelegates;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="McpServerFactory"/> class.
|
/// Initializes a new instance of the <see cref="McpServerFactory"/> class.
|
||||||
|
|
@ -26,15 +27,14 @@ public class McpServerFactory
|
||||||
/// <param name="serverTransport">Transport to use for the server</param>
|
/// <param name="serverTransport">Transport to use for the server</param>
|
||||||
/// <param name="options">Configuration options for this server, including capabilities.
|
/// <param name="options">Configuration options for this server, including capabilities.
|
||||||
/// Make sure to accurately reflect exactly what capabilities the server supports and does not support.</param>
|
/// Make sure to accurately reflect exactly what capabilities the server supports and does not support.</param>
|
||||||
/// <param name="serverInstructions">Optional server instructions to send to clients</param>
|
|
||||||
/// <param name="loggerFactory">Logger factory to use for logging</param>
|
/// <param name="loggerFactory">Logger factory to use for logging</param>
|
||||||
public McpServerFactory(IServerTransport serverTransport, McpServerOptions options, ILoggerFactory loggerFactory,
|
/// <param name="serverDelegates"></param>
|
||||||
string? serverInstructions = null)
|
public McpServerFactory(IServerTransport serverTransport, McpServerOptions options, ILoggerFactory loggerFactory, IOptions<McpServerDelegates>? serverDelegates = null)
|
||||||
{
|
{
|
||||||
_serverTransport = serverTransport;
|
_serverTransport = serverTransport ?? throw new ArgumentNullException(nameof(serverTransport));
|
||||||
_options = options;
|
_options = options ?? throw new ArgumentNullException(nameof(options));
|
||||||
_loggerFactory = loggerFactory;
|
_loggerFactory = loggerFactory ?? throw new ArgumentNullException(nameof(loggerFactory));
|
||||||
_serverInstructions = serverInstructions;
|
_serverDelegates = serverDelegates?.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -44,6 +44,10 @@ public class McpServerFactory
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IMcpServer CreateServer()
|
public IMcpServer CreateServer()
|
||||||
{
|
{
|
||||||
return new McpServer(_serverTransport, _options, _serverInstructions, _loggerFactory);
|
var server = new McpServer(_serverTransport, _options, _loggerFactory);
|
||||||
|
|
||||||
|
_serverDelegates?.Apply(server);
|
||||||
|
|
||||||
|
return server;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,4 +29,9 @@ public record McpServerOptions
|
||||||
/// Timeout for initialization sequence.
|
/// Timeout for initialization sequence.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public TimeSpan InitializationTimeout { get; init; } = TimeSpan.FromSeconds(60);
|
public TimeSpan InitializationTimeout { get; init; } = TimeSpan.FromSeconds(60);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Optional server instructions to send to clients
|
||||||
|
/// </summary>
|
||||||
|
public string ServerInstructions { get; init; } = string.Empty;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@
|
||||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||||
<!-- Assembly properties -->
|
<!-- Assembly properties -->
|
||||||
<AssemblyName>mcpdotnet</AssemblyName>
|
<AssemblyName>mcpdotnet</AssemblyName>
|
||||||
<RootNamespace>mcpdotnet</RootNamespace>
|
<RootNamespace>McpDotNet</RootNamespace>
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
<IncludeSymbols>true</IncludeSymbols>
|
<IncludeSymbols>true</IncludeSymbols>
|
||||||
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
|
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
|
||||||
|
|
@ -35,6 +35,7 @@
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="9.0.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="9.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="9.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,9 @@
|
||||||
using McpDotNet.Protocol.Transport;
|
using System.Text;
|
||||||
|
using McpDotNet.Protocol.Transport;
|
||||||
using McpDotNet.Protocol.Types;
|
using McpDotNet.Protocol.Types;
|
||||||
using McpDotNet.Server;
|
using McpDotNet.Server;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Logging.Abstractions;
|
|
||||||
using Serilog;
|
using Serilog;
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
internal class Program
|
internal class Program
|
||||||
{
|
{
|
||||||
|
|
@ -38,11 +37,11 @@ internal class Program
|
||||||
Resources = new(),
|
Resources = new(),
|
||||||
Prompts = new(),
|
Prompts = new(),
|
||||||
},
|
},
|
||||||
ProtocolVersion = "2024-11-05"
|
ProtocolVersion = "2024-11-05",
|
||||||
|
ServerInstructions = "This is a test server with only stub functionality",
|
||||||
};
|
};
|
||||||
var loggerFactory = CreateLoggerFactory();
|
var loggerFactory = CreateLoggerFactory();
|
||||||
McpServerFactory factory = new McpServerFactory(new StdioServerTransport("TestServer", loggerFactory), options, loggerFactory,
|
McpServerFactory factory = new McpServerFactory(new StdioServerTransport("TestServer", loggerFactory), options, loggerFactory);
|
||||||
"This is a test server with only stub functionality");
|
|
||||||
IMcpServer server = factory.CreateServer();
|
IMcpServer server = factory.CreateServer();
|
||||||
|
|
||||||
Console.WriteLine("Server object created, registering handlers.");
|
Console.WriteLine("Server object created, registering handlers.");
|
||||||
|
|
@ -51,7 +50,7 @@ internal class Program
|
||||||
static CreateMessageRequestParams CreateRequestSamplingParams(string context, string uri, int maxTokens = 100)
|
static CreateMessageRequestParams CreateRequestSamplingParams(string context, string uri, int maxTokens = 100)
|
||||||
{
|
{
|
||||||
return new CreateMessageRequestParams()
|
return new CreateMessageRequestParams()
|
||||||
{
|
{
|
||||||
Messages = [new SamplingMessage()
|
Messages = [new SamplingMessage()
|
||||||
{
|
{
|
||||||
Role = Role.User,
|
Role = Role.User,
|
||||||
|
|
@ -61,10 +60,10 @@ internal class Program
|
||||||
Text = $"Resource {uri} context: {context}"
|
Text = $"Resource {uri} context: {context}"
|
||||||
}
|
}
|
||||||
}],
|
}],
|
||||||
SystemPrompt = "You are a helpful test server.",
|
SystemPrompt = "You are a helpful test server.",
|
||||||
MaxTokens = maxTokens,
|
MaxTokens = maxTokens,
|
||||||
Temperature = 0.7f,
|
Temperature = 0.7f,
|
||||||
IncludeContext = ContextInclusion.ThisServer
|
IncludeContext = ContextInclusion.ThisServer
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
@ -74,9 +73,9 @@ internal class Program
|
||||||
{
|
{
|
||||||
return Task.FromResult(new ListToolsResult()
|
return Task.FromResult(new ListToolsResult()
|
||||||
{
|
{
|
||||||
Tools =
|
Tools =
|
||||||
[
|
[
|
||||||
new Tool()
|
new Tool()
|
||||||
{
|
{
|
||||||
Name = "echo",
|
Name = "echo",
|
||||||
Description = "Echoes the input back to the client.",
|
Description = "Echoes the input back to the client.",
|
||||||
|
|
@ -122,8 +121,8 @@ internal class Program
|
||||||
}
|
}
|
||||||
else if (request.Name == "sampleLLM")
|
else if (request.Name == "sampleLLM")
|
||||||
{
|
{
|
||||||
if (request.Arguments is null ||
|
if (request.Arguments is null ||
|
||||||
!request.Arguments.TryGetValue("prompt", out var prompt) ||
|
!request.Arguments.TryGetValue("prompt", out var prompt) ||
|
||||||
!request.Arguments.TryGetValue("maxTokens", out var maxTokens))
|
!request.Arguments.TryGetValue("maxTokens", out var maxTokens))
|
||||||
{
|
{
|
||||||
throw new McpServerException("Missing required arguments 'prompt' and 'maxTokens'");
|
throw new McpServerException("Missing required arguments 'prompt' and 'maxTokens'");
|
||||||
|
|
@ -200,10 +199,10 @@ internal class Program
|
||||||
throw new McpServerException("Invalid cursor");
|
throw new McpServerException("Invalid cursor");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int endIndex = Math.Min(startIndex + pageSize, resources.Count);
|
int endIndex = Math.Min(startIndex + pageSize, resources.Count);
|
||||||
string? nextCursor = null;
|
string? nextCursor = null;
|
||||||
|
|
||||||
if (endIndex < resources.Count)
|
if (endIndex < resources.Count)
|
||||||
{
|
{
|
||||||
nextCursor = Convert.ToBase64String(Encoding.UTF8.GetBytes(endIndex.ToString()));
|
nextCursor = Convert.ToBase64String(Encoding.UTF8.GetBytes(endIndex.ToString()));
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="9.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Logging" Version="9.0.0" />
|
||||||
<PackageReference Include="Serilog.Extensions.Logging" Version="9.0.0" />
|
<PackageReference Include="Serilog.Extensions.Logging" Version="9.0.0" />
|
||||||
<PackageReference Include="Serilog.Sinks.File" Version="6.0.0" />
|
<PackageReference Include="Serilog.Sinks.File" Version="6.0.0" />
|
||||||
|
|
|
||||||
38
tests/mcpdotnet.Tests/Server/McpServerDelegatesTests.cs
Normal file
38
tests/mcpdotnet.Tests/Server/McpServerDelegatesTests.cs
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
using McpDotNet.Protocol.Types;
|
||||||
|
using McpDotNet.Server;
|
||||||
|
using Moq;
|
||||||
|
|
||||||
|
namespace mcpdotnet.Tests.Server;
|
||||||
|
|
||||||
|
public class McpServerDelegatesTests
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void Applies_All_Given_Delegates()
|
||||||
|
{
|
||||||
|
var container = new McpServerDelegates();
|
||||||
|
var server = new Mock<IMcpServer>();
|
||||||
|
server.SetupAllProperties();
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
container.Apply(server.Object);
|
||||||
|
|
||||||
|
Assert.Equal(container.ListToolsHandler, server.Object.ListToolsHandler);
|
||||||
|
Assert.Equal(container.CallToolHandler, server.Object.CallToolHandler);
|
||||||
|
Assert.Equal(container.ListPromptsHandler, server.Object.ListPromptsHandler);
|
||||||
|
Assert.Equal(container.GetPromptHandler, server.Object.GetPromptHandler);
|
||||||
|
Assert.Equal(container.ListResourcesHandler, server.Object.ListResourcesHandler);
|
||||||
|
Assert.Equal(container.ReadResourceHandler, server.Object.ReadResourceHandler);
|
||||||
|
Assert.Equal(container.GetCompletionHandler, server.Object.GetCompletionHandler);
|
||||||
|
Assert.Equal(container.SubscribeToResourcesHandler, server.Object.SubscribeToResourcesHandler);
|
||||||
|
Assert.Equal(container.UnsubscribeFromResourcesHandler, server.Object.UnsubscribeFromResourcesHandler);
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue