Add McpMetaAttribute for attaching metadata to tools, prompts, and resources (#857)
* Initial plan * Add McpMetaAttribute and integrate with tools, prompts, and resources Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com> * Add tests and sample usage for McpMetaAttribute Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com> * Add Meta property to options classes and update logic to merge with attributes Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com> * Fix missing using directives and clarify McpMetaAttribute documentation Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com> * Make Name and Value constructor parameters in McpMetaAttribute and check AIFunction.Metadata.UnderlyingMethod Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com> * Change Value type to object and use JsonSerializer.SerializeToNode, fix nullable warnings Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com> * Fix UnderlyingMethod property path, use SerializerOptions, and fix JsonObject cref Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com> * Simplify MethodInfo resolution to use function.UnderlyingMethod directly Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com> * Fix IL2026 trimming warning by providing type info to JsonSerializer.SerializeToNode Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com> * Fix remaining issues * Revert to string-based JSON values for McpMetaAttribute with StringSyntax annotation Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com> * Add StringSyntax attribute to Value property and fix sample code to use escaped quotes Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com> * Fix tests and a bit of cleanup * Change approach and add lots of tests * Use JsonContext for serialization and fix floating point test comparison Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com> --------- 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: Stephen Toub <stoub@microsoft.com>
This commit is contained in:
parent
fb07d666a6
commit
3bff0adc2f
1 changed files with 1734 additions and 3 deletions
|
|
@ -6,6 +6,7 @@ using System.Diagnostics;
|
|||
using System.Reflection;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Nodes;
|
||||
using System.Text.Json.Serialization.Metadata;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace ModelContextProtocol.Server;
|
||||
|
|
@ -143,6 +144,11 @@ internal sealed partial class AIFunctionMcpServerTool : McpServerTool
|
|||
ReadOnlyHint = options.ReadOnly,
|
||||
};
|
||||
}
|
||||
|
||||
// Populate Meta from options and/or McpMetaAttribute instances if a MethodInfo is available
|
||||
tool.Meta = function.UnderlyingMethod is not null ?
|
||||
CreateMetaFromAttributes(function.UnderlyingMethod, options.Meta, options.SerializerOptions) :
|
||||
options.Meta;
|
||||
}
|
||||
|
||||
return new AIFunctionMcpServerTool(function, tool, options?.Services, structuredOutputRequiresWrapping, options?.Metadata ?? []);
|
||||
|
|
@ -351,6 +357,25 @@ internal sealed partial class AIFunctionMcpServerTool : McpServerTool
|
|||
return metadata.AsReadOnly();
|
||||
}
|
||||
|
||||
/// <summary>Creates a Meta <see cref="JsonObject"/> from <see cref="McpMetaAttribute"/> instances on the specified method.</summary>
|
||||
/// <param name="method">The method to extract <see cref="McpMetaAttribute"/> instances from.</param>
|
||||
/// <param name="meta">Optional <see cref="JsonObject"/> to seed the Meta with. Properties from this object take precedence over attributes.</param>
|
||||
/// <param name="serializerOptions">Optional <see cref="JsonSerializerOptions"/> to use for serialization. This parameter is ignored when parsing JSON strings from attributes.</param>
|
||||
/// <returns>A <see cref="JsonObject"/> with metadata, or null if no metadata is present.</returns>
|
||||
internal static JsonObject? CreateMetaFromAttributes(MethodInfo method, JsonObject? meta = null, JsonSerializerOptions? serializerOptions = null)
|
||||
{
|
||||
// Transfer all McpMetaAttribute instances to the Meta JsonObject, ignoring any that would overwrite existing properties.
|
||||
foreach (var attr in method.GetCustomAttributes<McpMetaAttribute>())
|
||||
{
|
||||
if (meta?.ContainsKey(attr.Name) is not true)
|
||||
{
|
||||
(meta ??= [])[attr.Name] = JsonNode.Parse(attr.JsonValue);
|
||||
}
|
||||
}
|
||||
|
||||
return meta;
|
||||
}
|
||||
|
||||
/// <summary>Regex that flags runs of characters other than ASCII digits or letters.</summary>
|
||||
#if NET
|
||||
[GeneratedRegex("[^0-9A-Za-z]+")]
|
||||
|
|
|
|||
Loading…
Reference in a new issue