Seal public Protocol reference types to prevent external inheritance (#1232)

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com>
This commit is contained in:
Copilot 2026-02-02 10:15:20 -05:00 • committed by GitHub
commit 712068b161
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 16 additions and 30 deletions

View file

@ -69,7 +69,7 @@ public abstract class ContentBlock
/// Provides a polymorphic converter for the <see cref="ContentBlock"/> class that doesn't require
/// setting <see cref="JsonSerializerOptions.AllowOutOfOrderMetadataProperties"/> explicitly.
[EditorBrowsable(EditorBrowsableState.Never)]
public class Converter : JsonConverter<ContentBlock>
public sealed class Converter : JsonConverter<ContentBlock>
{
/// <inheritdoc/>
public override ContentBlock? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)

View file

@ -103,7 +103,7 @@ public sealed class ElicitRequestParams : RequestParams
public McpTaskMetadata? Task { get; set; }
/// <summary>Represents a request schema used in a form mode elicitation request.</summary>
public class RequestSchema
public sealed class RequestSchema
{
/// <summary>Gets the type of the schema.</summary>
/// <remarks>This value is always "object".</remarks>
@ -161,7 +161,7 @@ public sealed class ElicitRequestParams : RequestParams
/// Provides a polymorphic converter for the <see cref="PrimitiveSchemaDefinition"/> class that doesn't require
/// setting <see cref="JsonSerializerOptions.AllowOutOfOrderMetadataProperties"/> explicitly.
[EditorBrowsable(EditorBrowsableState.Never)]
public class Converter : JsonConverter<PrimitiveSchemaDefinition>
public sealed class Converter : JsonConverter<PrimitiveSchemaDefinition>
{
/// <inheritdoc/>
public override PrimitiveSchemaDefinition? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
@ -315,11 +315,9 @@ public sealed class ElicitRequestParams : RequestParams
{
if (enumNames is not null)
{
// EnumSchema is deprecated but supported for backward compatibility.
// Use the EnumSchema class, which is an alias for LegacyTitledEnumSchema,
// to ensure backward compatibility with existing code relying on that type.
// LegacyTitledEnumSchema is deprecated but supported for backward compatibility.
#pragma warning disable MCP9001
psd = new EnumSchema
psd = new LegacyTitledEnumSchema
#pragma warning restore MCP9001
{
Enum = enumValues,
@ -996,24 +994,12 @@ public sealed class ElicitRequestParams : RequestParams
/// <summary>
/// Represents a legacy schema for an enum type with enumNames.
/// This is a compatibility alias for <see cref="LegacyTitledEnumSchema"/>.
/// </summary>
/// <remarks>
/// This schema is deprecated in favor of <see cref="TitledSingleSelectEnumSchema"/>.
/// </remarks>
[Obsolete(Obsoletions.LegacyTitledEnumSchema_Message, DiagnosticId = Obsoletions.LegacyTitledEnumSchema_DiagnosticId, UrlFormat = Obsoletions.LegacyTitledEnumSchema_Url)]
public sealed class EnumSchema : LegacyTitledEnumSchema
{
}
/// <summary>
/// Represents a legacy schema for an enum type with enumNames.
/// </summary>
/// <remarks>
/// This schema is deprecated in favor of <see cref="TitledSingleSelectEnumSchema"/>.
/// </remarks>
[Obsolete(Obsoletions.LegacyTitledEnumSchema_Message, DiagnosticId = Obsoletions.LegacyTitledEnumSchema_DiagnosticId, UrlFormat = Obsoletions.LegacyTitledEnumSchema_Url)]
public class LegacyTitledEnumSchema : PrimitiveSchemaDefinition
public sealed class LegacyTitledEnumSchema : PrimitiveSchemaDefinition
{
/// <inheritdoc/>
[JsonPropertyName("type")]

View file

@ -12,7 +12,7 @@ namespace ModelContextProtocol.Protocol;
/// but is not serialized as part of the JSON-RPC payload. This includes transport references, execution context,
/// and authenticated user information.
/// </remarks>
public class JsonRpcMessageContext
public sealed class JsonRpcMessageContext
{
/// <summary>
/// Gets or sets the transport the <see cref="JsonRpcMessage"/> was received on or should be sent over.

View file

@ -61,7 +61,7 @@ public abstract class ResourceContents
/// Provides a <see cref="JsonConverter"/> for <see cref="ResourceContents"/>.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
public class Converter : JsonConverter<ResourceContents>
public sealed class Converter : JsonConverter<ResourceContents>
{
/// <inheritdoc/>
public override ResourceContents? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)

View file

@ -298,7 +298,7 @@ public class EnumSchemaTests
// Assert
Assert.NotNull(deserialized);
var result = Assert.IsType<ElicitRequestParams.EnumSchema>(deserialized);
var result = Assert.IsType<ElicitRequestParams.LegacyTitledEnumSchema>(deserialized);
Assert.Equal("string", result.Type);
Assert.Equal("Environment", result.Title);
Assert.Equal("Deployment environment", result.Description);
@ -309,10 +309,10 @@ public class EnumSchemaTests
}
[Fact]
public void EnumSchema_Serializes_Correctly()
public void LegacyTitledEnumSchema_Direct_Serializes_Correctly()
{
// Arrange
var schema = new ElicitRequestParams.EnumSchema
var schema = new ElicitRequestParams.LegacyTitledEnumSchema
{
Title = "Environment",
Description = "Deployment environment",
@ -327,7 +327,7 @@ public class EnumSchemaTests
// Assert
Assert.NotNull(deserialized);
var result = Assert.IsType<ElicitRequestParams.EnumSchema>(deserialized);
var result = Assert.IsType<ElicitRequestParams.LegacyTitledEnumSchema>(deserialized);
Assert.Equal("string", result.Type);
Assert.Equal("Environment", result.Title);
Assert.Equal("Deployment environment", result.Description);
@ -338,9 +338,9 @@ public class EnumSchemaTests
}
[Fact]
public void Enum_WithEnumNames_Deserializes_As_EnumSchema()
public void Enum_WithEnumNames_Deserializes_As_LegacyTitledEnumSchema()
{
// Arrange - JSON with enumNames should deserialize as (deprecated) EnumSchema
// Arrange - JSON with enumNames should deserialize as (deprecated) LegacyTitledEnumSchema
string json = """
{
"type": "string",
@ -356,7 +356,7 @@ public class EnumSchemaTests
// Assert
Assert.NotNull(deserialized);
var result = Assert.IsType<ElicitRequestParams.EnumSchema>(deserialized);
var result = Assert.IsType<ElicitRequestParams.LegacyTitledEnumSchema>(deserialized);
Assert.Equal("string", result.Type);
Assert.Equal("Environment", result.Title);
Assert.Equal("Deployment environment", result.Description);

View file

@ -283,7 +283,7 @@ public static class PrimitiveSchemaDefinitionTests
json,
McpJsonUtilities.DefaultOptions);
Assert.NotNull(result);
var enumSchema = Assert.IsType<ElicitRequestParams.EnumSchema>(result);
var enumSchema = Assert.IsType<ElicitRequestParams.LegacyTitledEnumSchema>(result);
Assert.Equal("string", enumSchema.Type);
Assert.Equal(2, enumSchema.Enum.Count);
Assert.Contains("option1", enumSchema.Enum);