Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@
<!-- Product dependencies netstandard -->
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
<PackageVersion Include="Microsoft.Bcl.Memory" Version="9.0.4" />
<PackageVersion Include="Microsoft.Extensions.Hosting.Abstractions" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.3" />
<PackageVersion Include="System.IO.Pipelines" Version="8.0.0" />
<PackageVersion Include="System.Text.Json" Version="8.0.5" />
<PackageVersion Include="System.Threading.Channels" Version="8.0.0" />
<PackageVersion Include="System.Diagnostics.DiagnosticSource" Version="9.0.1" />
</ItemGroup>

<!-- Product dependencies LTS -->
Expand Down
2 changes: 1 addition & 1 deletion samples/EverythingServer/EverythingServer.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\src\ModelContextProtocol\ModelContextProtocol.csproj" />
<ProjectReference Include="..\..\src\ModelContextProtocol.AspNetCore\ModelContextProtocol.AspNetCore.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\src\ModelContextProtocol\ModelContextProtocol.csproj" />
<ProjectReference Include="..\..\src\ModelContextProtocol.AspNetCore\ModelContextProtocol.AspNetCore.csproj" />
</ItemGroup>

</Project>
4 changes: 2 additions & 2 deletions samples/TestServerWithHosting/TestServerWithHosting.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net9.0;net8.0;net472</TargetFrameworks>
<TargetFrameworks>net9.0;net8.0</TargetFrameworks>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<!--
Expand All @@ -23,7 +23,7 @@
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\src\ModelContextProtocol\ModelContextProtocol.csproj" />
<ProjectReference Include="..\..\src\ModelContextProtocol.AspNetCore\ModelContextProtocol.AspNetCore.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
using ModelContextProtocol;

namespace Microsoft.Extensions.DependencyInjection;

/// <summary>
Expand All @@ -21,7 +19,7 @@ internal sealed class DefaultMcpServerBuilder : IMcpServerBuilder
/// <exception cref="ArgumentNullException">Thrown when <paramref name="services"/> is null.</exception>
public DefaultMcpServerBuilder(IServiceCollection services)
{
Throw.IfNull(services);
ArgumentNullException.ThrowIfNull(services);

Services = services;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using ModelContextProtocol;
using ModelContextProtocol.AspNetCore;
using ModelContextProtocol.AspNetCore.Configuration;
using ModelContextProtocol.Protocol;
using ModelContextProtocol.Server;
using System.Diagnostics.CodeAnalysis;
Expand Down Expand Up @@ -38,7 +39,7 @@ public static partial class McpServerBuilderExtensions
this IMcpServerBuilder builder,
JsonSerializerOptions? serializerOptions = null)
{
Throw.IfNull(builder);
ArgumentNullException.ThrowIfNull(builder);

foreach (var toolMethod in typeof(TToolType).GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance))
{
Expand All @@ -61,8 +62,8 @@ public static partial class McpServerBuilderExtensions
/// <exception cref="ArgumentNullException"><paramref name="tools"/> is <see langword="null"/>.</exception>
public static IMcpServerBuilder WithTools(this IMcpServerBuilder builder, IEnumerable<McpServerTool> tools)
{
Throw.IfNull(builder);
Throw.IfNull(tools);
ArgumentNullException.ThrowIfNull(builder);
ArgumentNullException.ThrowIfNull(tools);

foreach (var tool in tools)
{
Expand Down Expand Up @@ -90,8 +91,8 @@ public static IMcpServerBuilder WithTools(this IMcpServerBuilder builder, IEnume
[RequiresUnreferencedCode(WithToolsRequiresUnreferencedCodeMessage)]
public static IMcpServerBuilder WithTools(this IMcpServerBuilder builder, IEnumerable<Type> toolTypes, JsonSerializerOptions? serializerOptions = null)
{
Throw.IfNull(builder);
Throw.IfNull(toolTypes);
ArgumentNullException.ThrowIfNull(builder);
ArgumentNullException.ThrowIfNull(toolTypes);

foreach (var toolType in toolTypes)
{
Expand Down Expand Up @@ -143,7 +144,7 @@ public static IMcpServerBuilder WithTools(this IMcpServerBuilder builder, IEnume
[RequiresUnreferencedCode(WithToolsRequiresUnreferencedCodeMessage)]
public static IMcpServerBuilder WithToolsFromAssembly(this IMcpServerBuilder builder, Assembly? toolAssembly = null, JsonSerializerOptions? serializerOptions = null)
{
Throw.IfNull(builder);
ArgumentNullException.ThrowIfNull(builder);

toolAssembly ??= Assembly.GetCallingAssembly();

Expand Down Expand Up @@ -178,7 +179,7 @@ where t.GetCustomAttribute<McpServerToolTypeAttribute>() is not null
this IMcpServerBuilder builder,
JsonSerializerOptions? serializerOptions = null)
{
Throw.IfNull(builder);
ArgumentNullException.ThrowIfNull(builder);

foreach (var promptMethod in typeof(TPromptType).GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance))
{
Expand All @@ -201,8 +202,8 @@ where t.GetCustomAttribute<McpServerToolTypeAttribute>() is not null
/// <exception cref="ArgumentNullException"><paramref name="prompts"/> is <see langword="null"/>.</exception>
public static IMcpServerBuilder WithPrompts(this IMcpServerBuilder builder, IEnumerable<McpServerPrompt> prompts)
{
Throw.IfNull(builder);
Throw.IfNull(prompts);
ArgumentNullException.ThrowIfNull(builder);
ArgumentNullException.ThrowIfNull(prompts);

foreach (var prompt in prompts)
{
Expand Down Expand Up @@ -230,8 +231,8 @@ public static IMcpServerBuilder WithPrompts(this IMcpServerBuilder builder, IEnu
[RequiresUnreferencedCode(WithPromptsRequiresUnreferencedCodeMessage)]
public static IMcpServerBuilder WithPrompts(this IMcpServerBuilder builder, IEnumerable<Type> promptTypes, JsonSerializerOptions? serializerOptions = null)
{
Throw.IfNull(builder);
Throw.IfNull(promptTypes);
ArgumentNullException.ThrowIfNull(builder);
ArgumentNullException.ThrowIfNull(promptTypes);

foreach (var promptType in promptTypes)
{
Expand Down Expand Up @@ -283,7 +284,7 @@ public static IMcpServerBuilder WithPrompts(this IMcpServerBuilder builder, IEnu
[RequiresUnreferencedCode(WithPromptsRequiresUnreferencedCodeMessage)]
public static IMcpServerBuilder WithPromptsFromAssembly(this IMcpServerBuilder builder, Assembly? promptAssembly = null, JsonSerializerOptions? serializerOptions = null)
{
Throw.IfNull(builder);
ArgumentNullException.ThrowIfNull(builder);

promptAssembly ??= Assembly.GetCallingAssembly();

Expand Down Expand Up @@ -315,7 +316,7 @@ where t.GetCustomAttribute<McpServerPromptTypeAttribute>() is not null
DynamicallyAccessedMemberTypes.PublicConstructors)] TResourceType>(
this IMcpServerBuilder builder)
{
Throw.IfNull(builder);
ArgumentNullException.ThrowIfNull(builder);

foreach (var resourceTemplateMethod in typeof(TResourceType).GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance))
{
Expand All @@ -338,8 +339,8 @@ where t.GetCustomAttribute<McpServerPromptTypeAttribute>() is not null
/// <exception cref="ArgumentNullException"><paramref name="resourceTemplates"/> is <see langword="null"/>.</exception>
public static IMcpServerBuilder WithResources(this IMcpServerBuilder builder, IEnumerable<McpServerResource> resourceTemplates)
{
Throw.IfNull(builder);
Throw.IfNull(resourceTemplates);
ArgumentNullException.ThrowIfNull(builder);
ArgumentNullException.ThrowIfNull(resourceTemplates);

foreach (var resourceTemplate in resourceTemplates)
{
Expand All @@ -366,8 +367,8 @@ public static IMcpServerBuilder WithResources(this IMcpServerBuilder builder, IE
[RequiresUnreferencedCode(WithResourcesRequiresUnreferencedCodeMessage)]
public static IMcpServerBuilder WithResources(this IMcpServerBuilder builder, IEnumerable<Type> resourceTemplateTypes)
{
Throw.IfNull(builder);
Throw.IfNull(resourceTemplateTypes);
ArgumentNullException.ThrowIfNull(builder);
ArgumentNullException.ThrowIfNull(resourceTemplateTypes);

foreach (var resourceTemplateType in resourceTemplateTypes)
{
Expand Down Expand Up @@ -418,7 +419,7 @@ public static IMcpServerBuilder WithResources(this IMcpServerBuilder builder, IE
[RequiresUnreferencedCode(WithResourcesRequiresUnreferencedCodeMessage)]
public static IMcpServerBuilder WithResourcesFromAssembly(this IMcpServerBuilder builder, Assembly? resourceAssembly = null)
{
Throw.IfNull(builder);
ArgumentNullException.ThrowIfNull(builder);

resourceAssembly ??= Assembly.GetCallingAssembly();

Expand Down Expand Up @@ -453,7 +454,7 @@ where t.GetCustomAttribute<McpServerResourceTypeAttribute>() is not null
/// </remarks>
public static IMcpServerBuilder WithListResourceTemplatesHandler(this IMcpServerBuilder builder, Func<RequestContext<ListResourceTemplatesRequestParams>, CancellationToken, ValueTask<ListResourceTemplatesResult>> handler)
{
Throw.IfNull(builder);
ArgumentNullException.ThrowIfNull(builder);

builder.Services.Configure<McpServerHandlers>(s => s.ListResourceTemplatesHandler = handler);
return builder;
Expand Down Expand Up @@ -486,7 +487,7 @@ public static IMcpServerBuilder WithListResourceTemplatesHandler(this IMcpServer
/// </remarks>
public static IMcpServerBuilder WithListToolsHandler(this IMcpServerBuilder builder, Func<RequestContext<ListToolsRequestParams>, CancellationToken, ValueTask<ListToolsResult>> handler)
{
Throw.IfNull(builder);
ArgumentNullException.ThrowIfNull(builder);

builder.Services.Configure<McpServerHandlers>(s => s.ListToolsHandler = handler);
return builder;
Expand All @@ -506,7 +507,7 @@ public static IMcpServerBuilder WithListToolsHandler(this IMcpServerBuilder buil
/// </remarks>
public static IMcpServerBuilder WithCallToolHandler(this IMcpServerBuilder builder, Func<RequestContext<CallToolRequestParams>, CancellationToken, ValueTask<CallToolResponse>> handler)
{
Throw.IfNull(builder);
ArgumentNullException.ThrowIfNull(builder);

builder.Services.Configure<McpServerHandlers>(s => s.CallToolHandler = handler);
return builder;
Expand Down Expand Up @@ -539,7 +540,7 @@ public static IMcpServerBuilder WithCallToolHandler(this IMcpServerBuilder build
/// </remarks>
public static IMcpServerBuilder WithListPromptsHandler(this IMcpServerBuilder builder, Func<RequestContext<ListPromptsRequestParams>, CancellationToken, ValueTask<ListPromptsResult>> handler)
{
Throw.IfNull(builder);
ArgumentNullException.ThrowIfNull(builder);

builder.Services.Configure<McpServerHandlers>(s => s.ListPromptsHandler = handler);
return builder;
Expand All @@ -554,7 +555,7 @@ public static IMcpServerBuilder WithListPromptsHandler(this IMcpServerBuilder bu
/// <exception cref="ArgumentNullException"><paramref name="builder"/> is <see langword="null"/>.</exception>
public static IMcpServerBuilder WithGetPromptHandler(this IMcpServerBuilder builder, Func<RequestContext<GetPromptRequestParams>, CancellationToken, ValueTask<GetPromptResult>> handler)
{
Throw.IfNull(builder);
ArgumentNullException.ThrowIfNull(builder);

builder.Services.Configure<McpServerHandlers>(s => s.GetPromptHandler = handler);
return builder;
Expand All @@ -575,7 +576,7 @@ public static IMcpServerBuilder WithGetPromptHandler(this IMcpServerBuilder buil
/// </remarks>
public static IMcpServerBuilder WithListResourcesHandler(this IMcpServerBuilder builder, Func<RequestContext<ListResourcesRequestParams>, CancellationToken, ValueTask<ListResourcesResult>> handler)
{
Throw.IfNull(builder);
ArgumentNullException.ThrowIfNull(builder);

builder.Services.Configure<McpServerHandlers>(s => s.ListResourcesHandler = handler);
return builder;
Expand All @@ -594,7 +595,7 @@ public static IMcpServerBuilder WithListResourcesHandler(this IMcpServerBuilder
/// </remarks>
public static IMcpServerBuilder WithReadResourceHandler(this IMcpServerBuilder builder, Func<RequestContext<ReadResourceRequestParams>, CancellationToken, ValueTask<ReadResourceResult>> handler)
{
Throw.IfNull(builder);
ArgumentNullException.ThrowIfNull(builder);

builder.Services.Configure<McpServerHandlers>(s => s.ReadResourceHandler = handler);
return builder;
Expand All @@ -613,7 +614,7 @@ public static IMcpServerBuilder WithReadResourceHandler(this IMcpServerBuilder b
/// </remarks>
public static IMcpServerBuilder WithCompleteHandler(this IMcpServerBuilder builder, Func<RequestContext<CompleteRequestParams>, CancellationToken, ValueTask<CompleteResult>> handler)
{
Throw.IfNull(builder);
ArgumentNullException.ThrowIfNull(builder);

builder.Services.Configure<McpServerHandlers>(s => s.CompleteHandler = handler);
return builder;
Expand Down Expand Up @@ -643,7 +644,7 @@ public static IMcpServerBuilder WithCompleteHandler(this IMcpServerBuilder build
/// </remarks>
public static IMcpServerBuilder WithSubscribeToResourcesHandler(this IMcpServerBuilder builder, Func<RequestContext<SubscribeRequestParams>, CancellationToken, ValueTask<EmptyResult>> handler)
{
Throw.IfNull(builder);
ArgumentNullException.ThrowIfNull(builder);

builder.Services.Configure<McpServerHandlers>(s => s.SubscribeToResourcesHandler = handler);
return builder;
Expand Down Expand Up @@ -673,7 +674,7 @@ public static IMcpServerBuilder WithSubscribeToResourcesHandler(this IMcpServerB
/// </remarks>
public static IMcpServerBuilder WithUnsubscribeFromResourcesHandler(this IMcpServerBuilder builder, Func<RequestContext<UnsubscribeRequestParams>, CancellationToken, ValueTask<EmptyResult>> handler)
{
Throw.IfNull(builder);
ArgumentNullException.ThrowIfNull(builder);

builder.Services.Configure<McpServerHandlers>(s => s.UnsubscribeFromResourcesHandler = handler);
return builder;
Expand All @@ -700,7 +701,7 @@ public static IMcpServerBuilder WithUnsubscribeFromResourcesHandler(this IMcpSer
/// </remarks>
public static IMcpServerBuilder WithSetLoggingLevelHandler(this IMcpServerBuilder builder, Func<RequestContext<SetLevelRequestParams>, CancellationToken, ValueTask<EmptyResult>> handler)
{
Throw.IfNull(builder);
ArgumentNullException.ThrowIfNull(builder);

builder.Services.Configure<McpServerHandlers>(s => s.SetLoggingLevelHandler = handler);
return builder;
Expand Down Expand Up @@ -728,10 +729,15 @@ public static IMcpServerBuilder WithSetLoggingLevelHandler(this IMcpServerBuilde
/// <exception cref="ArgumentNullException"><paramref name="builder"/> is <see langword="null"/>.</exception>
public static IMcpServerBuilder WithStdioServerTransport(this IMcpServerBuilder builder)
{
Throw.IfNull(builder);
ArgumentNullException.ThrowIfNull(builder);

AddSingleSessionServerDependencies(builder.Services);
builder.Services.AddSingleton<ITransport, StdioServerTransport>();
builder.Services.AddSingleton<ITransport>(sp =>
{
var serverOptions = sp.GetRequiredService<IOptions<McpServerOptions>>();
var loggerFactory = sp.GetService<ILoggerFactory>();
return new StdioServerTransport(serverOptions.Value, loggerFactory);
});

return builder;
}
Expand All @@ -751,16 +757,43 @@ public static IMcpServerBuilder WithStreamServerTransport(
Stream inputStream,
Stream outputStream)
{
Throw.IfNull(builder);
Throw.IfNull(inputStream);
Throw.IfNull(outputStream);
ArgumentNullException.ThrowIfNull(builder);
ArgumentNullException.ThrowIfNull(inputStream);
ArgumentNullException.ThrowIfNull(outputStream);

AddSingleSessionServerDependencies(builder.Services);
builder.Services.AddSingleton<ITransport>(new StreamServerTransport(inputStream, outputStream));

return builder;
}

/// <summary>
/// Adds the services necessary for <see cref="M:McpEndpointRouteBuilderExtensions.MapMcp"/>
/// to handle MCP requests and sessions using the MCP Streamable HTTP transport. For more information on configuring the underlying HTTP server
/// to control things like port binding custom TLS certificates, see the <see href="https://learn.microsoft.com/aspnet/core/fundamentals/minimal-apis">Minimal APIs quick reference</see>.
/// </summary>
/// <param name="builder">The builder instance.</param>
/// <param name="configureOptions">Configures options for the Streamable HTTP transport. This allows configuring per-session
/// <see cref="McpServerOptions"/> and running logic before and after a session.</param>
/// <returns>The builder provided in <paramref name="builder"/>.</returns>
/// <exception cref="ArgumentNullException"><paramref name="builder"/> is <see langword="null"/>.</exception>
public static IMcpServerBuilder WithHttpTransport(this IMcpServerBuilder builder, Action<HttpServerTransportOptions>? configureOptions = null)
{
ArgumentNullException.ThrowIfNull(builder);

builder.Services.TryAddSingleton<StreamableHttpHandler>();
builder.Services.TryAddSingleton<SseHandler>();
builder.Services.AddHostedService<IdleTrackingBackgroundService>();
builder.Services.AddDataProtection();

if (configureOptions is not null)
{
builder.Services.Configure(configureOptions);
}

return builder;
}

private static void AddSingleSessionServerDependencies(IServiceCollection services)
{
services.AddHostedService<SingleSessionMcpServerHostedService>();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
using Microsoft.Extensions.Options;
using ModelContextProtocol;
using ModelContextProtocol.Server;

namespace Microsoft.Extensions.DependencyInjection;
namespace ModelContextProtocol.AspNetCore.Configuration;

/// <summary>
/// Configures the McpServerOptions using addition services from DI.
Expand All @@ -24,7 +23,7 @@ internal sealed class McpServerOptionsSetup(
/// <param name="options">The options instance to be configured.</param>
public void Configure(McpServerOptions options)
{
Throw.IfNull(options);
ArgumentNullException.ThrowIfNull(options);

// Collect all of the provided tools into a tools collection. If the options already has
// a collection, add to it, otherwise create a new one. We want to maintain the identity
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Options;
using ModelContextProtocol.AspNetCore.Configuration;
using ModelContextProtocol.Server;

namespace Microsoft.Extensions.DependencyInjection;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using Microsoft.Extensions.Hosting;
using ModelContextProtocol.Server;

namespace ModelContextProtocol.Server;
namespace ModelContextProtocol.AspNetCore.Configuration;

/// <summary>
/// Hosted service for a single-session (e.g. stdio) MCP server.
Expand Down
Loading
Loading