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 /// Provides a polymorphic converter for the <see cref="ContentBlock"/> class that doesn't require
/// setting <see cref="JsonSerializerOptions.AllowOutOfOrderMetadataProperties"/> explicitly. /// setting <see cref="JsonSerializerOptions.AllowOutOfOrderMetadataProperties"/> explicitly.
[EditorBrowsable(EditorBrowsableState.Never)] [EditorBrowsable(EditorBrowsableState.Never)]
public class Converter : JsonConverter<ContentBlock> public sealed class Converter : JsonConverter<ContentBlock>
{ {
/// <inheritdoc/> /// <inheritdoc/>
public override ContentBlock? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) 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; } public McpTaskMetadata? Task { get; set; }
/// <summary>Represents a request schema used in a form mode elicitation request.</summary> /// <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> /// <summary>Gets the type of the schema.</summary>
/// <remarks>This value is always "object".</remarks> /// <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 /// Provides a polymorphic converter for the <see cref="PrimitiveSchemaDefinition"/> class that doesn't require
/// setting <see cref="JsonSerializerOptions.AllowOutOfOrderMetadataProperties"/> explicitly. /// setting <see cref="JsonSerializerOptions.AllowOutOfOrderMetadataProperties"/> explicitly.
[EditorBrowsable(EditorBrowsableState.Never)] [EditorBrowsable(EditorBrowsableState.Never)]
public class Converter : JsonConverter<PrimitiveSchemaDefinition> public sealed class Converter : JsonConverter<PrimitiveSchemaDefinition>
{ {
/// <inheritdoc/> /// <inheritdoc/>
public override PrimitiveSchemaDefinition? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) 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) if (enumNames is not null)
{ {
// EnumSchema is deprecated but supported for backward compatibility. // LegacyTitledEnumSchema 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.
#pragma warning disable MCP9001 #pragma warning disable MCP9001
psd = new EnumSchema psd = new LegacyTitledEnumSchema
#pragma warning restore MCP9001 #pragma warning restore MCP9001
{ {
Enum = enumValues, Enum = enumValues,
@ -996,24 +994,12 @@ public sealed class ElicitRequestParams : RequestParams
/// <summary> /// <summary>
/// Represents a legacy schema for an enum type with enumNames. /// Represents a legacy schema for an enum type with enumNames.
/// This is a compatibility alias for <see cref="LegacyTitledEnumSchema"/>.
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// This schema is deprecated in favor of <see cref="TitledSingleSelectEnumSchema"/>. /// This schema is deprecated in favor of <see cref="TitledSingleSelectEnumSchema"/>.
/// </remarks> /// </remarks>
[Obsolete(Obsoletions.LegacyTitledEnumSchema_Message, DiagnosticId = Obsoletions.LegacyTitledEnumSchema_DiagnosticId, UrlFormat = Obsoletions.LegacyTitledEnumSchema_Url)] [Obsolete(Obsoletions.LegacyTitledEnumSchema_Message, DiagnosticId = Obsoletions.LegacyTitledEnumSchema_DiagnosticId, UrlFormat = Obsoletions.LegacyTitledEnumSchema_Url)]
public sealed class EnumSchema : LegacyTitledEnumSchema public sealed class LegacyTitledEnumSchema : PrimitiveSchemaDefinition
{
}
/// <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
{ {
/// <inheritdoc/> /// <inheritdoc/>
[JsonPropertyName("type")] [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, /// but is not serialized as part of the JSON-RPC payload. This includes transport references, execution context,
/// and authenticated user information. /// and authenticated user information.
/// </remarks> /// </remarks>
public class JsonRpcMessageContext public sealed class JsonRpcMessageContext
{ {
/// <summary> /// <summary>
/// Gets or sets the transport the <see cref="JsonRpcMessage"/> was received on or should be sent over. /// 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"/>. /// Provides a <see cref="JsonConverter"/> for <see cref="ResourceContents"/>.
/// </summary> /// </summary>
[EditorBrowsable(EditorBrowsableState.Never)] [EditorBrowsable(EditorBrowsableState.Never)]
public class Converter : JsonConverter<ResourceContents> public sealed class Converter : JsonConverter<ResourceContents>
{ {
/// <inheritdoc/> /// <inheritdoc/>
public override ResourceContents? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) public override ResourceContents? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)

View file

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

View file

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