Skip to content

Add ModelContextProtocol.Core package #428

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Jun 2, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
1 change: 1 addition & 0 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
<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.Diagnostics.DiagnosticSource" Version="8.0.1" />
<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" />
Expand Down
7 changes: 7 additions & 0 deletions ModelContextProtocol.sln
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EverythingServer", "samples
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ModelContextProtocol.AspNetCore", "src\ModelContextProtocol.AspNetCore\ModelContextProtocol.AspNetCore.csproj", "{37B6A5E0-9995-497D-8B43-3BC6870CC716}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ModelContextProtocol.Hosting", "src\ModelContextProtocol.Hosting\ModelContextProtocol.Hosting.csproj", "{3F5C7E8A-F123-4D2B-8B9A-1E2F3D4C5B6A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ModelContextProtocol.AspNetCore.Tests", "tests\ModelContextProtocol.AspNetCore.Tests\ModelContextProtocol.AspNetCore.Tests.csproj", "{85557BA6-3D29-4C95-A646-2A972B1C2F25}"
EndProject
Global
Expand Down Expand Up @@ -106,6 +108,10 @@ Global
{37B6A5E0-9995-497D-8B43-3BC6870CC716}.Debug|Any CPU.Build.0 = Debug|Any CPU
{37B6A5E0-9995-497D-8B43-3BC6870CC716}.Release|Any CPU.ActiveCfg = Release|Any CPU
{37B6A5E0-9995-497D-8B43-3BC6870CC716}.Release|Any CPU.Build.0 = Release|Any CPU
{3F5C7E8A-F123-4D2B-8B9A-1E2F3D4C5B6A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3F5C7E8A-F123-4D2B-8B9A-1E2F3D4C5B6A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3F5C7E8A-F123-4D2B-8B9A-1E2F3D4C5B6A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3F5C7E8A-F123-4D2B-8B9A-1E2F3D4C5B6A}.Release|Any CPU.Build.0 = Release|Any CPU
{85557BA6-3D29-4C95-A646-2A972B1C2F25}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{85557BA6-3D29-4C95-A646-2A972B1C2F25}.Debug|Any CPU.Build.0 = Debug|Any CPU
{85557BA6-3D29-4C95-A646-2A972B1C2F25}.Release|Any CPU.ActiveCfg = Release|Any CPU
Expand All @@ -127,6 +133,7 @@ Global
{0D1552DC-E6ED-4AAC-5562-12F8352F46AA} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
{17B8453F-AB72-99C5-E5EA-D0B065A6AE65} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
{37B6A5E0-9995-497D-8B43-3BC6870CC716} = {A2F1F52A-9107-4BF8-8C3F-2F6670E7D0AD}
{3F5C7E8A-F123-4D2B-8B9A-1E2F3D4C5B6A} = {A2F1F52A-9107-4BF8-8C3F-2F6670E7D0AD}
{85557BA6-3D29-4C95-A646-2A972B1C2F25} = {2A77AF5C-138A-4EBB-9A13-9205DCD67928}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
Expand Down
1 change: 0 additions & 1 deletion samples/AspNetCoreSseServer/AspNetCoreSseServer.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
</PropertyGroup>

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

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.Hosting\ModelContextProtocol.Hosting.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.Hosting\ModelContextProtocol.Hosting.csproj" />
</ItemGroup>

</Project>
2 changes: 1 addition & 1 deletion samples/TestServerWithHosting/TestServerWithHosting.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
</ItemGroup>

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

</Project>
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.DependencyInjection.Extensions;
using ModelContextProtocol.AspNetCore;
using ModelContextProtocol.Server;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,9 @@
<ItemGroup>
<None Include="README.md" pack="true" PackagePath="\" />
</ItemGroup>

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

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ namespace Microsoft.Extensions.DependencyInjection;

/// <summary>
/// Default implementation of <see cref="IMcpServerBuilder"/> that enables fluent configuration
/// of the Model Context Protocol (MCP) server. This builder is returned by the
/// <see cref="McpServerServiceCollectionExtensions.AddMcpServer"/> extension method and
/// of the Model Context Protocol (MCP) server. This builder is returned by the
/// <see cref="McpServerServiceCollectionExtensions.AddMcpServer"/> extension method and
/// provides access to the service collection for registering additional MCP components.
/// </summary>
internal sealed class DefaultMcpServerBuilder : IMcpServerBuilder
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ namespace Microsoft.Extensions.DependencyInjection;
/// and server transports, allowing for comprehensive server configuration through a chain of method calls.
/// </para>
/// <para>
/// The builder is obtained from the <see cref="McpServerServiceCollectionExtensions.AddMcpServer"/> extension
/// The builder is obtained from the <see cref="McpServerServiceCollectionExtensions.AddMcpServer"/> extension
/// method and provides access to the underlying service collection via the <see cref="Services"/> property.
/// </para>
/// </remarks>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using ModelContextProtocol;
using ModelContextProtocol.Hosting;
using ModelContextProtocol.Protocol;
using ModelContextProtocol.Server;
using System.Diagnostics.CodeAnalysis;
Expand Down Expand Up @@ -124,7 +125,7 @@ public static IMcpServerBuilder WithTools(this IMcpServerBuilder builder, IEnume
/// <para>
/// This method scans the specified assembly (or the calling assembly if none is provided) for classes
/// marked with the <see cref="McpServerToolTypeAttribute"/>. It then discovers all methods within those
/// classes that are marked with the <see cref="McpServerToolAttribute"/> and registers them as <see cref="McpServerTool"/>s
/// classes that are marked with the <see cref="McpServerToolAttribute"/> and registers them as <see cref="McpServerTool"/>s
/// in the <paramref name="builder"/>'s <see cref="IServiceCollection"/>.
/// </para>
/// <para>
Expand Down Expand Up @@ -264,7 +265,7 @@ public static IMcpServerBuilder WithPrompts(this IMcpServerBuilder builder, IEnu
/// <para>
/// This method scans the specified assembly (or the calling assembly if none is provided) for classes
/// marked with the <see cref="McpServerPromptTypeAttribute"/>. It then discovers all methods within those
/// classes that are marked with the <see cref="McpServerPromptAttribute"/> and registers them as <see cref="McpServerPrompt"/>s
/// classes that are marked with the <see cref="McpServerPromptAttribute"/> and registers them as <see cref="McpServerPrompt"/>s
/// in the <paramref name="builder"/>'s <see cref="IServiceCollection"/>.
/// </para>
/// <para>
Expand Down Expand Up @@ -399,7 +400,7 @@ public static IMcpServerBuilder WithResources(this IMcpServerBuilder builder, IE
/// <para>
/// This method scans the specified assembly (or the calling assembly if none is provided) for classes
/// marked with the <see cref="McpServerResourceTypeAttribute"/>. It then discovers all members within those
/// classes that are marked with the <see cref="McpServerResourceAttribute"/> and registers them as <see cref="McpServerResource"/>s
/// classes that are marked with the <see cref="McpServerResourceAttribute"/> and registers them as <see cref="McpServerResource"/>s
/// in the <paramref name="builder"/>'s <see cref="IServiceCollection"/>.
/// </para>
/// <para>
Expand Down Expand Up @@ -480,7 +481,7 @@ public static IMcpServerBuilder WithListResourceTemplatesHandler(this IMcpServer
/// </para>
/// <para>
/// This method is typically paired with <see cref="WithCallToolHandler"/> to provide a complete tools implementation,
/// where <see cref="WithListToolsHandler"/> advertises available tools and <see cref="WithCallToolHandler"/>
/// where <see cref="WithListToolsHandler"/> advertises available tools and <see cref="WithCallToolHandler"/>
/// executes them when invoked by clients.
/// </para>
/// </remarks>
Expand Down Expand Up @@ -533,7 +534,7 @@ public static IMcpServerBuilder WithCallToolHandler(this IMcpServerBuilder build
/// </para>
/// <para>
/// This method is typically paired with <see cref="WithGetPromptHandler"/> to provide a complete prompts implementation,
/// where <see cref="WithListPromptsHandler"/> advertises available prompts and <see cref="WithGetPromptHandler"/>
/// where <see cref="WithListPromptsHandler"/> advertises available prompts and <see cref="WithGetPromptHandler"/>
/// produces them when invoked by clients.
/// </para>
/// </remarks>
Expand Down Expand Up @@ -608,7 +609,7 @@ public static IMcpServerBuilder WithReadResourceHandler(this IMcpServerBuilder b
/// <returns>The builder provided in <paramref name="builder"/>.</returns>
/// <exception cref="ArgumentNullException"><paramref name="builder"/> is <see langword="null"/>.</exception>
/// <remarks>
/// The completion handler is invoked when clients request suggestions for argument values.
/// The completion handler is invoked when clients request suggestions for argument values.
/// This enables auto-complete functionality for both prompt arguments and resource references.
/// </remarks>
public static IMcpServerBuilder WithCompleteHandler(this IMcpServerBuilder builder, Func<RequestContext<CompleteRequestParams>, CancellationToken, ValueTask<CompleteResult>> handler)
Expand Down Expand Up @@ -731,7 +732,12 @@ public static IMcpServerBuilder WithStdioServerTransport(this IMcpServerBuilder
Throw.IfNull(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 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.Hosting;

/// <summary>
/// Configures the McpServerOptions using addition services from DI.
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.Hosting;
using ModelContextProtocol.Server;

namespace Microsoft.Extensions.DependencyInjection;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net9.0;net8.0;netstandard2.0</TargetFrameworks>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<IsPackable>true</IsPackable>
<PackageId>ModelContextProtocol.Hosting</PackageId>
<Description>Hosting and dependency injection extensions for the C# Model Context Protocol (MCP) SDK.</Description>
<PackageReadmeFile>README.md</PackageReadmeFile>
<LangVersion>preview</LangVersion>
</PropertyGroup>

<PropertyGroup Condition="'$(TargetFramework)' != 'netstandard2.0'">
<IsAotCompatible>true</IsAotCompatible>
</PropertyGroup>

<ItemGroup>
<Compile Include="..\Common\Throw.cs" Link="Throw.cs" />
</ItemGroup>

<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
<Compile Include="..\Common\Polyfills\**\*.cs" />
</ItemGroup>

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

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" />
</ItemGroup>

<ItemGroup>
<None Include="README.md" pack="true" PackagePath="\" />
</ItemGroup>

</Project>
54 changes: 54 additions & 0 deletions src/ModelContextProtocol.Hosting/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# Hosting extensions for the MCP C# SDK

[![NuGet preview version](https://img.shields.io/nuget/vpre/ModelContextProtocol.Hosting.svg)](https://www.nuget.org/packages/ModelContextProtocol.Hosting/absoluteLatest)

Hosting and dependency injection extensions for the official C# SDK for the [Model Context Protocol](https://modelcontextprotocol.io/), enabling .NET applications, services, and libraries to implement and interact with MCP clients and servers. Please visit our [API documentation](https://modelcontextprotocol.github.io/csharp-sdk/api/ModelContextProtocol.html) for more details on available functionality.

> [!NOTE]
> This project is in preview; breaking changes can be introduced without prior notice.

## About MCP

The Model Context Protocol (MCP) is an open protocol that standardizes how applications provide context to Large Language Models (LLMs). It enables secure integration between LLMs and various data sources and tools.

For more information about MCP:

- [Official Documentation](https://modelcontextprotocol.io/)
- [Protocol Specification](https://spec.modelcontextprotocol.io/)
- [GitHub Organization](https://github.com/modelcontextprotocol)

## Installation

To get started, install the package from NuGet

```
dotnet new console
dotnet add package ModelContextProtocol.Hosting --prerelease
```

## Getting Started

This package provides hosting and dependency injection extensions for the core ModelContextProtocol package. It includes configuration builders, hosted services, and transport implementations for stdio and stream-based communications.

```csharp
// Program.cs for a console application
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.DependencyInjection;
using ModelContextProtocol.Server;
using System.ComponentModel;

var builder = Host.CreateApplicationBuilder(args);
builder.Services.AddMcpServer()
.WithStdioServerTransport()
.WithToolsFromAssembly();

var app = builder.Build();
await app.RunAsync();

[McpServerToolType]
public static class EchoTool
{
[McpServerTool, Description("Echoes the message back to the client.")]
public static string Echo(string message) => $"hello {message}";
}
```
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.Hosting;

/// <summary>
/// Hosted service for a single-session (e.g. stdio) MCP server.
Expand Down
16 changes: 6 additions & 10 deletions src/ModelContextProtocol/Client/SseClientTransport.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,17 +57,13 @@ public SseClientTransport(SseClientTransportOptions transportOptions, HttpClient
/// <inheritdoc />
public async Task<ITransport> ConnectAsync(CancellationToken cancellationToken = default)
{
switch (_options.TransportMode)
return _options.TransportMode switch
{
case HttpTransportMode.AutoDetect:
return new AutoDetectingClientSessionTransport(_options, _httpClient, _loggerFactory, Name);
case HttpTransportMode.StreamableHttp:
return new StreamableHttpClientSessionTransport(Name, _options, _httpClient, messageChannel: null, _loggerFactory);
case HttpTransportMode.Sse:
return await ConnectSseTransportAsync(cancellationToken).ConfigureAwait(false);
default:
throw new InvalidOperationException($"Unsupported transport mode: {_options.TransportMode}");
}
HttpTransportMode.AutoDetect => new AutoDetectingClientSessionTransport(_options, _httpClient, _loggerFactory, Name),
HttpTransportMode.StreamableHttp => new StreamableHttpClientSessionTransport(Name, _options, _httpClient, messageChannel: null, _loggerFactory),
HttpTransportMode.Sse => await ConnectSseTransportAsync(cancellationToken).ConfigureAwait(false),
_ => throw new InvalidOperationException($"Unsupported transport mode: {_options.TransportMode}"),
};
}

private async Task<ITransport> ConnectSseTransportAsync(CancellationToken cancellationToken)
Expand Down
2 changes: 1 addition & 1 deletion src/ModelContextProtocol/ModelContextProtocol.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
<Compile Include="..\Common\Polyfills\**\*.cs" />
<PackageReference Include="Microsoft.Bcl.Memory" />
<PackageReference Include="System.Diagnostics.DiagnosticSource" />
<PackageReference Include="System.Text.Json" />
<PackageReference Include="System.Threading.Channels" />
</ItemGroup>
Expand All @@ -34,7 +35,6 @@
<!-- Dependencies needed by all -->
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.AI.Abstractions" />
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" />
<PackageReference Include="System.Net.ServerSentEvents" />
</ItemGroup>
Expand Down
3 changes: 1 addition & 2 deletions src/ModelContextProtocol/Server/McpServerPrompt.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,7 @@ namespace ModelContextProtocol.Server;
/// <para>
/// Most commonly, <see cref="McpServerPrompt"/> instances are created using the static <see cref="M:McpServerPrompt.Create"/> methods.
/// These methods enable creating an <see cref="McpServerPrompt"/> for a method, specified via a <see cref="Delegate"/> or
/// <see cref="MethodInfo"/>, and are what are used implicitly by <see cref="McpServerBuilderExtensions.WithPromptsFromAssembly"/> and
/// <see cref="M:McpServerBuilderExtensions.WithPrompts"/>. The <see cref="M:McpServerPrompt.Create"/> methods
/// <see cref="MethodInfo"/>, and are what are used implicitly by WithPromptsFromAssembly and WithPrompts. The <see cref="M:McpServerPrompt.Create"/> methods
/// create <see cref="McpServerPrompt"/> instances capable of working with a large variety of .NET method signatures, automatically handling
/// how parameters are marshaled into the method from the JSON received from the MCP client, and how the return value is marshaled back
/// into the <see cref="GetPromptResult"/> that's then serialized and sent back to the client.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ namespace ModelContextProtocol.Server;
/// <remarks>
/// <para>
/// This attribute is applied to methods that should be exposed as prompts in the Model Context Protocol. When a class
/// containing methods marked with this attribute is registered with <see cref="McpServerBuilderExtensions"/>,
/// containing methods marked with this attribute is registered with McpServerBuilderExtensions,
/// these methods become available as prompts that can be called by MCP clients.
/// </para>
/// <para>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,8 @@ namespace ModelContextProtocol.Server;
/// <para>
/// This attribute is used to mark a class containing methods that should be automatically
/// discovered and registered as <see cref="McpServerPrompt"/>s. When combined with discovery methods like
/// <see cref="McpServerBuilderExtensions.WithPromptsFromAssembly"/>, it enables automatic registration
/// of prompts without explicitly listing each prompt class. The attribute is not necessary when a reference
/// to the type is provided directly to a method like <see cref="McpServerBuilderExtensions.WithPrompts{T}"/>.
/// WithPromptsFromAssembly, it enables automatic registration of prompts without explicitly listing each prompt class.
/// The attribute is not necessary when a reference to the type is provided directly to a method like WithPrompts.
/// </para>
/// <para>
/// Within a class marked with this attribute, individual methods that should be exposed as
Expand Down
Loading
Loading