Add explicit [Experimental] protected constructors to McpClient and McpServer (#1363)

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com>
Co-authored-by: jeffhandley <1031940+jeffhandley@users.noreply.github.com>
Co-authored-by: Jeff Handley <jeffhandley@users.noreply.github.com>
This commit is contained in:
Copilot 2026-02-23 21:37:39 -05:00 • committed by GitHub
commit 124b43b5c1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 44 additions and 2 deletions

View file

@ -24,6 +24,7 @@ If you use experimental APIs, you will get one of the diagnostics shown below. T
| Diagnostic ID | Description |
| :------------ | :---------- |
| `MCPEXP001` | MCP experimental APIs including Tasks and Extensions. Tasks provide a mechanism for asynchronous long-running operations that can be polled for status and results (see [MCP Tasks specification](https://modelcontextprotocol.io/specification/draft/basic/utilities/tasks)). Extensions provide a framework for extending the Model Context Protocol while maintaining interoperability (see [SEP-2133](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2133)). |
| `MCPEXP002` | Subclassing `McpClient` and `McpServer` is experimental and subject to change (see [#1363](https://github.com/modelcontextprotocol/csharp-sdk/pull/1363)). |
## Obsolete APIs
@ -34,4 +35,4 @@ When APIs are marked as obsolete, a diagnostic is emitted to warn users that the
| Diagnostic ID | Status | Description |
| :------------ | :----- | :---------- |
| `MCP9001` | In place | The `EnumSchema` and `LegacyTitledEnumSchema` APIs are deprecated as of specification version 2025-11-25. Use the current schema APIs instead. |
| `MCP9002` | Removed | The `AddXxxFilter` extension methods on `IMcpServerBuilder` (e.g., `AddListToolsFilter`, `AddCallToolFilter`, `AddIncomingMessageFilter`) were superseded by `WithRequestFilters()` and `WithMessageFilters()`. |
| `MCP9002` | Removed | The `AddXxxFilter` extension methods on `IMcpServerBuilder` (e.g., `AddListToolsFilter`, `AddCallToolFilter`, `AddIncomingMessageFilter`) were superseded by `WithRequestFilters()` and `WithMessageFilters()`. |

View file

@ -56,4 +56,19 @@ internal static class Experimentals
/// URL for the experimental MCP Extensions feature.
/// </summary>
public const string Extensions_Url = "https://github.com/modelcontextprotocol/csharp-sdk/blob/main/docs/list-of-diagnostics.md#mcpexp001";
/// <summary>
/// Diagnostic ID for experimental subclassing of McpClient and McpServer.
/// </summary>
public const string Subclassing_DiagnosticId = "MCPEXP002";
/// <summary>
/// Message for experimental subclassing of McpClient and McpServer.
/// </summary>
public const string Subclassing_Message = "Subclassing McpClient and McpServer is experimental and subject to change.";
/// <summary>
/// URL for experimental subclassing of McpClient and McpServer.
/// </summary>
public const string Subclassing_Url = "https://github.com/modelcontextprotocol/csharp-sdk/pull/1363";
}

View file

@ -1,4 +1,5 @@
using ModelContextProtocol.Protocol;
using System.Diagnostics.CodeAnalysis;
using ModelContextProtocol.Protocol;
namespace ModelContextProtocol.Client;
@ -7,6 +8,14 @@ namespace ModelContextProtocol.Client;
/// </summary>
public abstract partial class McpClient : McpSession
{
/// <summary>
/// Initializes a new instance of the <see cref="McpClient"/> class.
/// </summary>
[Experimental(Experimentals.Subclassing_DiagnosticId, UrlFormat = Experimentals.Subclassing_Url)]
protected McpClient()
{
}
/// <summary>
/// Gets the capabilities supported by the connected server.
/// </summary>

View file

@ -6,6 +6,7 @@ using System.Text.Json;
namespace ModelContextProtocol.Client;
/// <inheritdoc/>
#pragma warning disable MCPEXP002
internal sealed partial class McpClientImpl : McpClient
{
private static Implementation DefaultImplementation { get; } = new()
@ -37,6 +38,7 @@ internal sealed partial class McpClientImpl : McpClient
/// <param name="options">Options for the client, defining protocol version and capabilities.</param>
/// <param name="loggerFactory">The logger factory.</param>
internal McpClientImpl(ITransport transport, string endpointName, McpClientOptions? options, ILoggerFactory? loggerFactory)
#pragma warning restore MCPEXP002
{
options ??= new();

View file

@ -3,7 +3,9 @@ using System.Diagnostics;
namespace ModelContextProtocol.Server;
#pragma warning disable MCPEXP002
internal sealed class DestinationBoundMcpServer(McpServerImpl server, ITransport? transport) : McpServer
#pragma warning restore MCPEXP002
{
public override string? SessionId => transport?.SessionId ?? server.SessionId;
public override string? NegotiatedProtocolVersion => server.NegotiatedProtocolVersion;

View file

@ -1,3 +1,4 @@
using System.Diagnostics.CodeAnalysis;
using ModelContextProtocol.Protocol;
namespace ModelContextProtocol.Server;
@ -7,6 +8,14 @@ namespace ModelContextProtocol.Server;
/// </summary>
public abstract partial class McpServer : McpSession
{
/// <summary>
/// Initializes a new instance of the <see cref="McpServer"/> class.
/// </summary>
[Experimental(Experimentals.Subclassing_DiagnosticId, UrlFormat = Experimentals.Subclassing_Url)]
protected McpServer()
{
}
/// <summary>
/// Gets the capabilities supported by the client.
/// </summary>

View file

@ -9,6 +9,7 @@ using System.Text.Json.Serialization.Metadata;
namespace ModelContextProtocol.Server;
/// <inheritdoc />
#pragma warning disable MCPEXP002
internal sealed partial class McpServerImpl : McpServer
{
internal static Implementation DefaultImplementation { get; } = new()
@ -54,6 +55,7 @@ internal sealed partial class McpServerImpl : McpServer
/// <param name="serviceProvider">Optional service provider to use for dependency injection</param>
/// <exception cref="McpException">The server was incorrectly configured.</exception>
public McpServerImpl(ITransport transport, McpServerOptions options, ILoggerFactory? loggerFactory, IServiceProvider? serviceProvider)
#pragma warning restore MCPEXP002
{
Throw.IfNull(transport);
Throw.IfNull(options);

View file

@ -943,7 +943,9 @@ public class McpServerTests : LoggedTest
await tcs.Task.WaitAsync(TestConstants.DefaultTimeout, cancellationToken);
}
#pragma warning disable MCPEXP002
private sealed class TestServerForIChatClient(bool supportsSampling) : McpServer
#pragma warning restore MCPEXP002
{
public override ClientCapabilities? ClientCapabilities =>
supportsSampling ? new ClientCapabilities { Sampling = new SamplingCapability() } :