Skip to content

Commit 0601d28

Browse files
Remove default value extraction code and linker annotations per feedback
Co-authored-by: eiriktsarpalis <[email protected]>
1 parent 423fe2d commit 0601d28

File tree

2 files changed

+3
-146
lines changed

2 files changed

+3
-146
lines changed

src/ModelContextProtocol.Core/Server/McpServer.Methods.cs

Lines changed: 3 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,7 @@
22
using Microsoft.Extensions.Logging;
33
using ModelContextProtocol.Protocol;
44
using System.Collections.Concurrent;
5-
using System.ComponentModel;
65
using System.Diagnostics.CodeAnalysis;
7-
using System.Reflection;
86
using System.Runtime.CompilerServices;
97
using System.Text;
108
using System.Text.Json;
@@ -259,9 +257,9 @@ public async ValueTask<ElicitResult<T>> ElicitAsync<T>(
259257
var dict = s_elicitResultSchemaCache.GetValue(serializerOptions, _ => new());
260258

261259
#if NET
262-
var schema = dict.GetOrAdd(typeof(T), static (t, s) => BuildRequestSchemaHelper(t, s), serializerOptions);
260+
var schema = dict.GetOrAdd(typeof(T), static (t, s) => BuildRequestSchema(t, s), serializerOptions);
263261
#else
264-
var schema = dict.GetOrAdd(typeof(T), type => BuildRequestSchemaHelper(type, serializerOptions));
262+
var schema = dict.GetOrAdd(typeof(T), type => BuildRequestSchema(type, serializerOptions));
265263
#endif
266264

267265
var request = new ElicitRequestParams
@@ -287,21 +285,14 @@ public async ValueTask<ElicitResult<T>> ElicitAsync<T>(
287285
return new ElicitResult<T> { Action = raw.Action, Content = typed };
288286
}
289287

290-
/// <summary>
291-
/// Helper method for BuildRequestSchema that can be called from lambdas without annotation issues.
292-
/// </summary>
293-
[UnconditionalSuppressMessage("Trimming", "IL2067", Justification = "Type T is preserved via JsonTypeInfo")]
294-
private static ElicitRequestParams.RequestSchema BuildRequestSchemaHelper(Type type, JsonSerializerOptions serializerOptions)
295-
=> BuildRequestSchema(type, serializerOptions);
296-
297288
/// <summary>
298289
/// Builds a request schema for elicitation based on the public serializable properties of <paramref name="type"/>.
299290
/// </summary>
300291
/// <param name="type">The type of the schema being built.</param>
301292
/// <param name="serializerOptions">The serializer options to use.</param>
302293
/// <returns>The built request schema.</returns>
303294
/// <exception cref="McpProtocolException"></exception>
304-
private static ElicitRequestParams.RequestSchema BuildRequestSchema([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] Type type, JsonSerializerOptions serializerOptions)
295+
private static ElicitRequestParams.RequestSchema BuildRequestSchema(Type type, JsonSerializerOptions serializerOptions)
305296
{
306297
var schema = new ElicitRequestParams.RequestSchema();
307298
var props = schema.Properties;
@@ -316,47 +307,11 @@ private static ElicitRequestParams.RequestSchema BuildRequestSchema([Dynamically
316307
foreach (JsonPropertyInfo pi in typeInfo.Properties)
317308
{
318309
var def = CreatePrimitiveSchema(pi.PropertyType, serializerOptions);
319-
320-
// Extract default value from DefaultValueAttribute if present
321-
var propInfo = type.GetProperty(pi.Name);
322-
if (propInfo != null)
323-
{
324-
var defaultValueAttr = propInfo.GetCustomAttribute<System.ComponentModel.DefaultValueAttribute>();
325-
if (defaultValueAttr?.Value != null)
326-
{
327-
SetDefaultValue(def, defaultValueAttr.Value);
328-
}
329-
}
330-
331310
props[pi.Name] = def;
332311
}
333312

334313
return schema;
335314
}
336-
337-
/// <summary>
338-
/// Sets the default value on a primitive schema definition based on the value type.
339-
/// </summary>
340-
/// <param name="schema">The schema to set the default value on.</param>
341-
/// <param name="value">The default value.</param>
342-
private static void SetDefaultValue(ElicitRequestParams.PrimitiveSchemaDefinition schema, object value)
343-
{
344-
switch (schema)
345-
{
346-
case ElicitRequestParams.StringSchema stringSchema:
347-
stringSchema.Default = value?.ToString();
348-
break;
349-
case ElicitRequestParams.NumberSchema numberSchema:
350-
numberSchema.Default = Convert.ToDouble(value);
351-
break;
352-
case ElicitRequestParams.BooleanSchema booleanSchema:
353-
booleanSchema.Default = Convert.ToBoolean(value);
354-
break;
355-
case ElicitRequestParams.EnumSchema enumSchema:
356-
enumSchema.Default = value?.ToString();
357-
break;
358-
}
359-
}
360315

361316
/// <summary>
362317
/// Creates a primitive schema definition for the specified type, if supported.

tests/ModelContextProtocol.Tests/Protocol/ElicitationTypedTests.cs

Lines changed: 0 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -86,19 +86,6 @@ await request.Server.ElicitAsync<string>(
8686
Content = [new TextContentBlock { Text = "unexpected" }],
8787
};
8888
}
89-
else if (request.Params!.Name == "TestElicitationWithDefaults")
90-
{
91-
var result = await request.Server.ElicitAsync<FormWithDefaults>(
92-
message: "Please provide information.",
93-
serializerOptions: ElicitationDefaultsJsonContext.Default.Options,
94-
cancellationToken: CancellationToken.None);
95-
96-
// The test will validate the schema in the client handler
97-
return new CallToolResult
98-
{
99-
Content = [new TextContentBlock { Text = "success" }],
100-
};
101-
}
10289
else
10390
{
10491
Assert.Fail($"Unexpected tool name: {request.Params!.Name}");
@@ -373,89 +360,4 @@ public sealed class Nested
373360
[JsonSerializable(typeof(UnsupportedForm.Nested))]
374361
[JsonSerializable(typeof(JsonElement))]
375362
internal partial class ElicitationUnsupportedJsonContext : JsonSerializerContext;
376-
377-
public sealed class FormWithDefaults
378-
{
379-
[System.ComponentModel.DefaultValue("John Doe")]
380-
public string Name { get; set; } = "John Doe";
381-
382-
[System.ComponentModel.DefaultValue(30)]
383-
public int Age { get; set; } = 30;
384-
385-
[System.ComponentModel.DefaultValue(85.5)]
386-
public double Score { get; set; } = 85.5;
387-
388-
[System.ComponentModel.DefaultValue(true)]
389-
public bool IsActive { get; set; } = true;
390-
391-
[System.ComponentModel.DefaultValue("active")]
392-
public string Status { get; set; } = "active";
393-
}
394-
395-
[JsonSerializable(typeof(FormWithDefaults))]
396-
[JsonSerializable(typeof(JsonElement))]
397-
internal partial class ElicitationDefaultsJsonContext : JsonSerializerContext;
398-
399-
[Fact]
400-
public async Task Elicit_Typed_With_Defaults_Maps_To_Schema_Defaults()
401-
{
402-
await using McpClient client = await CreateMcpClientForServer(new McpClientOptions
403-
{
404-
Handlers = new()
405-
{
406-
ElicitationHandler = async (request, cancellationToken) =>
407-
{
408-
Assert.NotNull(request);
409-
Assert.Equal("Please provide information.", request.Message);
410-
411-
Assert.Equal(5, request.RequestedSchema.Properties.Count);
412-
413-
// Verify that default values from the type are mapped to the schema
414-
foreach (var entry in request.RequestedSchema.Properties)
415-
{
416-
switch (entry.Key)
417-
{
418-
case nameof(FormWithDefaults.Name):
419-
var nameSchema = Assert.IsType<ElicitRequestParams.StringSchema>(entry.Value);
420-
Assert.Equal("John Doe", nameSchema.Default);
421-
break;
422-
423-
case nameof(FormWithDefaults.Age):
424-
var ageSchema = Assert.IsType<ElicitRequestParams.NumberSchema>(entry.Value);
425-
Assert.Equal(30, ageSchema.Default);
426-
break;
427-
428-
case nameof(FormWithDefaults.Score):
429-
var scoreSchema = Assert.IsType<ElicitRequestParams.NumberSchema>(entry.Value);
430-
Assert.Equal(85.5, scoreSchema.Default);
431-
break;
432-
433-
case nameof(FormWithDefaults.IsActive):
434-
var activeSchema = Assert.IsType<ElicitRequestParams.BooleanSchema>(entry.Value);
435-
Assert.True(activeSchema.Default);
436-
break;
437-
438-
case nameof(FormWithDefaults.Status):
439-
var statusSchema = Assert.IsType<ElicitRequestParams.StringSchema>(entry.Value);
440-
Assert.Equal("active", statusSchema.Default);
441-
break;
442-
443-
default:
444-
Assert.Fail($"Unexpected property: {entry.Key}");
445-
break;
446-
}
447-
}
448-
449-
return new ElicitResult
450-
{
451-
Action = "accept",
452-
Content = new Dictionary<string, JsonElement>()
453-
};
454-
},
455-
}
456-
});
457-
458-
var result = await client.CallToolAsync("TestElicitationWithDefaults", cancellationToken: TestContext.Current.CancellationToken);
459-
Assert.Equal("success", (result.Content[0] as TextContentBlock)?.Text);
460-
}
461363
}

0 commit comments

Comments
 (0)