Skip to content

Commit 3eb3e63

Browse files
committed
Fix remaining issues
1 parent 86c9393 commit 3eb3e63

File tree

4 files changed

+186
-84
lines changed

4 files changed

+186
-84
lines changed

src/ModelContextProtocol.Core/Server/AIFunctionMcpServerPrompt.cs

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -140,14 +140,9 @@ private static AIFunctionFactoryOptions CreateAIFunctionFactoryOptions(
140140
};
141141

142142
// Populate Meta from options and/or McpMetaAttribute instances if a MethodInfo is available
143-
if (function.UnderlyingMethod is not null)
144-
{
145-
prompt.Meta = AIFunctionMcpServerTool.CreateMetaFromAttributes(function.UnderlyingMethod, options?.Meta, options?.SerializerOptions);
146-
}
147-
else if (options?.Meta is not null)
148-
{
149-
prompt.Meta = options.Meta;
150-
}
143+
prompt.Meta = function.UnderlyingMethod is not null ?
144+
AIFunctionMcpServerTool.CreateMetaFromAttributes(function.UnderlyingMethod, options?.Meta, options?.SerializerOptions) :
145+
options?.Meta;
151146

152147
return new AIFunctionMcpServerPrompt(function, prompt, options?.Metadata ?? []);
153148
}

src/ModelContextProtocol.Core/Server/AIFunctionMcpServerResource.cs

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -212,17 +212,6 @@ private static AIFunctionFactoryOptions CreateAIFunctionFactoryOptions(
212212

213213
string name = options?.Name ?? function.Name;
214214

215-
// Populate Meta from options and/or McpMetaAttribute instances if a MethodInfo is available
216-
JsonObject? meta = null;
217-
if (function.UnderlyingMethod is not null)
218-
{
219-
meta = AIFunctionMcpServerTool.CreateMetaFromAttributes(function.UnderlyingMethod, options?.Meta, options?.SerializerOptions);
220-
}
221-
else if (options?.Meta is not null)
222-
{
223-
meta = options.Meta;
224-
}
225-
226215
ResourceTemplate resource = new()
227216
{
228217
UriTemplate = options?.UriTemplate ?? DeriveUriTemplate(name, function),
@@ -231,7 +220,9 @@ private static AIFunctionFactoryOptions CreateAIFunctionFactoryOptions(
231220
Description = options?.Description,
232221
MimeType = options?.MimeType ?? "application/octet-stream",
233222
Icons = options?.Icons,
234-
Meta = meta,
223+
Meta = function.UnderlyingMethod is not null ?
224+
AIFunctionMcpServerTool.CreateMetaFromAttributes(function.UnderlyingMethod, options?.Meta, options?.SerializerOptions) :
225+
options?.Meta,
235226
};
236227

237228
return new AIFunctionMcpServerResource(function, resource, options?.Metadata ?? []);

src/ModelContextProtocol.Core/Server/AIFunctionMcpServerTool.cs

Lines changed: 26 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using System.Reflection;
77
using System.Text.Json;
88
using System.Text.Json.Nodes;
9+
using System.Text.Json.Serialization.Metadata;
910
using System.Text.RegularExpressions;
1011

1112
namespace ModelContextProtocol.Server;
@@ -145,14 +146,9 @@ options.OpenWorld is not null ||
145146
}
146147

147148
// Populate Meta from options and/or McpMetaAttribute instances if a MethodInfo is available
148-
if (function.UnderlyingMethod is not null)
149-
{
150-
tool.Meta = CreateMetaFromAttributes(function.UnderlyingMethod, options.Meta, options.SerializerOptions);
151-
}
152-
else if (options.Meta is not null)
153-
{
154-
tool.Meta = options.Meta;
155-
}
149+
tool.Meta = function.UnderlyingMethod is not null ?
150+
CreateMetaFromAttributes(function.UnderlyingMethod, options.Meta, options.SerializerOptions) :
151+
options.Meta;
156152
}
157153

158154
return new AIFunctionMcpServerTool(function, tool, options?.Services, structuredOutputRequiresWrapping, options?.Metadata ?? []);
@@ -361,25 +357,35 @@ internal static IReadOnlyList<object> CreateMetadata(MethodInfo method)
361357
return metadata.AsReadOnly();
362358
}
363359

364-
/// <summary>Creates a Meta JsonObject from McpMetaAttribute instances on the specified method.</summary>
365-
/// <param name="method">The method to extract McpMetaAttribute instances from.</param>
366-
/// <param name="seedMeta">Optional JsonObject to seed the Meta with. Properties from this object take precedence over attributes.</param>
367-
/// <param name="serializerOptions">Optional JsonSerializerOptions to use for serialization. Defaults to McpJsonUtilities.DefaultOptions if not provided.</param>
368-
/// <returns>A JsonObject with metadata, or null if no metadata is present.</returns>
369-
internal static JsonObject? CreateMetaFromAttributes(MethodInfo method, JsonObject? seedMeta = null, JsonSerializerOptions? serializerOptions = null)
360+
/// <summary>Creates a Meta <see cref="JsonObject"/> from <see cref="McpMetaAttribute"/> instances on the specified method.</summary>
361+
/// <param name="method">The method to extract <see cref="McpMetaAttribute"/> instances from.</param>
362+
/// <param name="meta">Optional <see cref="JsonObject"/> to seed the Meta with. Properties from this object take precedence over attributes.</param>
363+
/// <param name="serializerOptions">Optional <see cref="JsonSerializerOptions"/> to use for serialization. Defaults to <see cref="McpJsonUtilities.DefaultOptions"/> if not provided.</param>
364+
/// <returns>A <see cref="JsonObject"/> with metadata, or null if no metadata is present.</returns>
365+
internal static JsonObject? CreateMetaFromAttributes(MethodInfo method, JsonObject? meta = null, JsonSerializerOptions? serializerOptions = null)
370366
{
371-
// Get all McpMetaAttribute instances from the method
367+
// Get all McpMetaAttribute instances from the method.
372368
var metaAttributes = method.GetCustomAttributes<McpMetaAttribute>();
373369

374-
JsonObject? meta = seedMeta;
375-
JsonSerializerOptions options = serializerOptions ?? McpJsonUtilities.DefaultOptions;
376370
foreach (var attr in metaAttributes)
377371
{
378-
meta ??= new JsonObject();
379-
// Only add the attribute property if it doesn't already exist in the seed
372+
meta ??= [];
380373
if (!meta.ContainsKey(attr.Name))
381374
{
382-
meta[attr.Name] = JsonSerializer.SerializeToNode(attr.Value, options.GetTypeInfo(typeof(object)));
375+
JsonTypeInfo? valueTypeInfo = null;
376+
if (attr.Value?.GetType() is { } valueType)
377+
{
378+
if (serializerOptions?.TryGetTypeInfo(valueType, out valueTypeInfo) is not true &&
379+
McpJsonUtilities.DefaultOptions.TryGetTypeInfo(valueType, out valueTypeInfo) is not true)
380+
{
381+
// Throw using GetTypeInfo in order to get a good exception message.
382+
(serializerOptions ?? McpJsonUtilities.DefaultOptions).GetTypeInfo(valueType);
383+
}
384+
385+
Debug.Assert(valueTypeInfo is not null, "GetTypeInfo should have thrown an exception");
386+
}
387+
388+
meta[attr.Name] = valueTypeInfo is not null ? JsonSerializer.SerializeToNode(attr.Value, valueTypeInfo) : null;
383389
}
384390
}
385391

0 commit comments

Comments
 (0)