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
12 changed files with 1734 additions and 3 deletions
|
|
@ -17,6 +17,8 @@ public sealed class WeatherTools
|
||||||
}
|
}
|
||||||
|
|
||||||
[McpServerTool, Description("Get weather alerts for a US state.")]
|
[McpServerTool, Description("Get weather alerts for a US state.")]
|
||||||
|
[McpMeta("category", "weather")]
|
||||||
|
[McpMeta("dataSource", "weather.gov")]
|
||||||
public async Task<string> GetAlerts(
|
public async Task<string> GetAlerts(
|
||||||
[Description("The US state to get alerts for. Use the 2 letter abbreviation for the state (e.g. NY).")] string state)
|
[Description("The US state to get alerts for. Use the 2 letter abbreviation for the state (e.g. NY).")] string state)
|
||||||
{
|
{
|
||||||
|
|
@ -46,6 +48,8 @@ public sealed class WeatherTools
|
||||||
}
|
}
|
||||||
|
|
||||||
[McpServerTool, Description("Get weather forecast for a location.")]
|
[McpServerTool, Description("Get weather forecast for a location.")]
|
||||||
|
[McpMeta("category", "weather")]
|
||||||
|
[McpMeta("recommendedModel", "gpt-4")]
|
||||||
public async Task<string> GetForecast(
|
public async Task<string> GetForecast(
|
||||||
[Description("Latitude of the location.")] double latitude,
|
[Description("Latitude of the location.")] double latitude,
|
||||||
[Description("Longitude of the location.")] double longitude)
|
[Description("Longitude of the location.")] double longitude)
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ public sealed class ClientCapabilities
|
||||||
/// </para>
|
/// </para>
|
||||||
/// <para>
|
/// <para>
|
||||||
/// The server can use <see cref="McpServer.RequestRootsAsync"/> to request the list of
|
/// The server can use <see cref="McpServer.RequestRootsAsync"/> to request the list of
|
||||||
/// available roots from the client, which will trigger the client's <see cref="ModelContextProtocol.Client.McpClientHandlers.RootsHandler"/>.
|
/// available roots from the client, which will trigger the client's <see cref="McpClientHandlers.RootsHandler"/>.
|
||||||
/// </para>
|
/// </para>
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[JsonPropertyName("roots")]
|
[JsonPropertyName("roots")]
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ namespace ModelContextProtocol.Protocol;
|
||||||
/// </para>
|
/// </para>
|
||||||
/// <para>
|
/// <para>
|
||||||
/// When this capability is enabled, an MCP server can request the client to provide additional information
|
/// When this capability is enabled, an MCP server can request the client to provide additional information
|
||||||
/// during interactions. The client must set a <see cref="ModelContextProtocol.Client.McpClientHandlers.ElicitationHandler"/> to process these requests.
|
/// during interactions. The client must set a <see cref="McpClientHandlers.ElicitationHandler"/> to process these requests.
|
||||||
/// </para>
|
/// </para>
|
||||||
/// <para>
|
/// <para>
|
||||||
/// This class is intentionally empty as the Model Context Protocol specification does not
|
/// This class is intentionally empty as the Model Context Protocol specification does not
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ namespace ModelContextProtocol.Protocol;
|
||||||
/// </para>
|
/// </para>
|
||||||
/// <para>
|
/// <para>
|
||||||
/// When this capability is enabled, an MCP server can request the client to generate content
|
/// When this capability is enabled, an MCP server can request the client to generate content
|
||||||
/// using an AI model. The client must set a <see cref="ModelContextProtocol.Client.McpClientHandlers.SamplingHandler"/> to process these requests.
|
/// using an AI model. The client must set a <see cref="McpClientHandlers.SamplingHandler"/> to process these requests.
|
||||||
/// </para>
|
/// </para>
|
||||||
/// <para>
|
/// <para>
|
||||||
/// This class is intentionally empty as the Model Context Protocol specification does not
|
/// This class is intentionally empty as the Model Context Protocol specification does not
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ using System.ComponentModel;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
|
using System.Text.Json.Nodes;
|
||||||
|
|
||||||
namespace ModelContextProtocol.Server;
|
namespace ModelContextProtocol.Server;
|
||||||
|
|
||||||
|
|
@ -138,6 +139,11 @@ internal sealed class AIFunctionMcpServerPrompt : McpServerPrompt
|
||||||
Icons = options?.Icons,
|
Icons = options?.Icons,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Populate Meta from options and/or McpMetaAttribute instances if a MethodInfo is available
|
||||||
|
prompt.Meta = function.UnderlyingMethod is not null ?
|
||||||
|
AIFunctionMcpServerTool.CreateMetaFromAttributes(function.UnderlyingMethod, options?.Meta, options?.SerializerOptions) :
|
||||||
|
options?.Meta;
|
||||||
|
|
||||||
return new AIFunctionMcpServerPrompt(function, prompt, options?.Metadata ?? []);
|
return new AIFunctionMcpServerPrompt(function, prompt, options?.Metadata ?? []);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ using System.Reflection;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
|
using System.Text.Json.Nodes;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
namespace ModelContextProtocol.Server;
|
namespace ModelContextProtocol.Server;
|
||||||
|
|
@ -219,6 +220,9 @@ internal sealed class AIFunctionMcpServerResource : McpServerResource
|
||||||
Description = options?.Description,
|
Description = options?.Description,
|
||||||
MimeType = options?.MimeType ?? "application/octet-stream",
|
MimeType = options?.MimeType ?? "application/octet-stream",
|
||||||
Icons = options?.Icons,
|
Icons = options?.Icons,
|
||||||
|
Meta = function.UnderlyingMethod is not null ?
|
||||||
|
AIFunctionMcpServerTool.CreateMetaFromAttributes(function.UnderlyingMethod, options?.Meta, options?.SerializerOptions) :
|
||||||
|
options?.Meta,
|
||||||
};
|
};
|
||||||
|
|
||||||
return new AIFunctionMcpServerResource(function, resource, options?.Metadata ?? []);
|
return new AIFunctionMcpServerResource(function, resource, options?.Metadata ?? []);
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ using System.Diagnostics;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Text.Json.Nodes;
|
using System.Text.Json.Nodes;
|
||||||
|
using System.Text.Json.Serialization.Metadata;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
namespace ModelContextProtocol.Server;
|
namespace ModelContextProtocol.Server;
|
||||||
|
|
@ -143,6 +144,11 @@ internal sealed partial class AIFunctionMcpServerTool : McpServerTool
|
||||||
ReadOnlyHint = options.ReadOnly,
|
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 ?? []);
|
return new AIFunctionMcpServerTool(function, tool, options?.Services, structuredOutputRequiresWrapping, options?.Metadata ?? []);
|
||||||
|
|
@ -351,6 +357,25 @@ internal sealed partial class AIFunctionMcpServerTool : McpServerTool
|
||||||
return metadata.AsReadOnly();
|
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>
|
/// <summary>Regex that flags runs of characters other than ASCII digits or letters.</summary>
|
||||||
#if NET
|
#if NET
|
||||||
[GeneratedRegex("[^0-9A-Za-z]+")]
|
[GeneratedRegex("[^0-9A-Za-z]+")]
|
||||||
|
|
|
||||||
103
src/ModelContextProtocol.Core/Server/McpMetaAttribute.cs
Normal file
103
src/ModelContextProtocol.Core/Server/McpMetaAttribute.cs
Normal file
|
|
@ -0,0 +1,103 @@
|
||||||
|
using ModelContextProtocol.Protocol;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using System.Text.Json;
|
||||||
|
using System.Text.Json.Nodes;
|
||||||
|
|
||||||
|
namespace ModelContextProtocol.Server;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Used to specify metadata for an MCP server primitive (tool, prompt, or resource).
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// <para>
|
||||||
|
/// The metadata is used to populate the <see cref="Tool.Meta"/>, <see cref="Prompt.Meta"/>,
|
||||||
|
/// or <see cref="Resource.Meta"/> property of the corresponding primitive.
|
||||||
|
/// </para>
|
||||||
|
/// <para>
|
||||||
|
/// This attribute can be applied multiple times to a method to specify multiple key/value pairs
|
||||||
|
/// of metadata. However, the same key should not be used more than once; doing so will result
|
||||||
|
/// in undefined behavior.
|
||||||
|
/// </para>
|
||||||
|
/// <para>
|
||||||
|
/// Metadata can be used to attach additional information to primitives, such as model preferences,
|
||||||
|
/// version information, or other custom data that should be communicated to MCP clients.
|
||||||
|
/// </para>
|
||||||
|
/// </remarks>
|
||||||
|
/// <example>
|
||||||
|
/// <code>
|
||||||
|
/// [McpServerTool]
|
||||||
|
/// [McpMeta("model", "gpt-4o")]
|
||||||
|
/// [McpMeta("version", "1.0")]
|
||||||
|
/// [McpMeta("priority", 5.0)]
|
||||||
|
/// [McpMeta("isBeta", true)]
|
||||||
|
/// [McpMeta("tags", JsonValue = """["a","b"]""")]
|
||||||
|
/// public string MyTool(string input) => $"Processed: {input}";
|
||||||
|
/// </code>
|
||||||
|
/// </example>
|
||||||
|
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
|
||||||
|
public sealed class McpMetaAttribute : Attribute
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="McpMetaAttribute"/> class with a string value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">The name (key) of the metadata entry.</param>
|
||||||
|
/// <param name="value">The string value of the metadata entry. If null, the value will be serialized as JSON null.</param>
|
||||||
|
public McpMetaAttribute(string name, string? value = null)
|
||||||
|
{
|
||||||
|
Name = name;
|
||||||
|
JsonValue = value is null ? "null" : JsonSerializer.Serialize(value, McpJsonUtilities.JsonContext.Default.String);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="McpMetaAttribute"/> class with a double value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">The name (key) of the metadata entry.</param>
|
||||||
|
/// <param name="value">The double value of the metadata entry.</param>
|
||||||
|
public McpMetaAttribute(string name, double value)
|
||||||
|
{
|
||||||
|
Name = name;
|
||||||
|
JsonValue = JsonSerializer.Serialize(value, McpJsonUtilities.DefaultOptions.GetTypeInfo(typeof(double)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="McpMetaAttribute"/> class with a boolean value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">The name (key) of the metadata entry.</param>
|
||||||
|
/// <param name="value">The boolean value of the metadata entry.</param>
|
||||||
|
public McpMetaAttribute(string name, bool value)
|
||||||
|
{
|
||||||
|
Name = name;
|
||||||
|
JsonValue = JsonSerializer.Serialize(value, McpJsonUtilities.JsonContext.Default.Boolean);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the name (key) of the metadata entry.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// This value is used as the key in the metadata object. It should be a unique identifier
|
||||||
|
/// for this piece of metadata within the context of the primitive.
|
||||||
|
/// </remarks>
|
||||||
|
public string Name { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the value of the metadata entry as a JSON string.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// <para>
|
||||||
|
/// This value must be well-formed JSON. It will be parsed and added to the metadata <see cref="JsonObject"/>.
|
||||||
|
/// Simple values can be represented as JSON literals like <c>"\"my-string\""</c>, <c>"123"</c>,
|
||||||
|
/// <c>"true"</c>, etc. Complex structures can be represented as JSON objects or arrays.
|
||||||
|
/// </para>
|
||||||
|
/// <para>
|
||||||
|
/// Setting this property will override any value provided via the constructor.
|
||||||
|
/// </para>
|
||||||
|
/// <para>
|
||||||
|
/// For programmatic scenarios where you want to construct complex metadata without dealing with
|
||||||
|
/// JSON strings, use the <see cref="McpServerToolCreateOptions.Meta"/>,
|
||||||
|
/// <see cref="McpServerPromptCreateOptions.Meta"/>, or <see cref="McpServerResourceCreateOptions.Meta"/>
|
||||||
|
/// property to provide a JsonObject directly.
|
||||||
|
/// </para>
|
||||||
|
/// </remarks>
|
||||||
|
[StringSyntax(StringSyntaxAttribute.Json)]
|
||||||
|
public string JsonValue { get; set; }
|
||||||
|
}
|
||||||
|
|
@ -2,6 +2,7 @@ using Microsoft.Extensions.AI;
|
||||||
using ModelContextProtocol.Protocol;
|
using ModelContextProtocol.Protocol;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
|
using System.Text.Json.Nodes;
|
||||||
|
|
||||||
namespace ModelContextProtocol.Server;
|
namespace ModelContextProtocol.Server;
|
||||||
|
|
||||||
|
|
@ -86,6 +87,21 @@ public sealed class McpServerPromptCreateOptions
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public IList<Icon>? Icons { get; set; }
|
public IList<Icon>? Icons { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets metadata reserved by MCP for protocol-level metadata.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// <para>
|
||||||
|
/// This <see cref="JsonObject"/> is used to seed the <see cref="Prompt.Meta"/> property. Any metadata from
|
||||||
|
/// <see cref="McpMetaAttribute"/> instances on the method will be added to this object, but
|
||||||
|
/// properties already present in this <see cref="JsonObject"/> will not be overwritten.
|
||||||
|
/// </para>
|
||||||
|
/// <para>
|
||||||
|
/// Implementations must not make assumptions about its contents.
|
||||||
|
/// </para>
|
||||||
|
/// </remarks>
|
||||||
|
public JsonObject? Meta { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a shallow clone of the current <see cref="McpServerPromptCreateOptions"/> instance.
|
/// Creates a shallow clone of the current <see cref="McpServerPromptCreateOptions"/> instance.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -100,5 +116,6 @@ public sealed class McpServerPromptCreateOptions
|
||||||
SchemaCreateOptions = SchemaCreateOptions,
|
SchemaCreateOptions = SchemaCreateOptions,
|
||||||
Metadata = Metadata,
|
Metadata = Metadata,
|
||||||
Icons = Icons,
|
Icons = Icons,
|
||||||
|
Meta = Meta,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ using Microsoft.Extensions.AI;
|
||||||
using ModelContextProtocol.Protocol;
|
using ModelContextProtocol.Protocol;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
|
using System.Text.Json.Nodes;
|
||||||
|
|
||||||
namespace ModelContextProtocol.Server;
|
namespace ModelContextProtocol.Server;
|
||||||
|
|
||||||
|
|
@ -101,6 +102,21 @@ public sealed class McpServerResourceCreateOptions
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public IList<Icon>? Icons { get; set; }
|
public IList<Icon>? Icons { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets metadata reserved by MCP for protocol-level metadata.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// <para>
|
||||||
|
/// This <see cref="JsonObject"/> is used to seed the <see cref="Resource.Meta"/> property. Any metadata from
|
||||||
|
/// <see cref="McpMetaAttribute"/> instances on the method will be added to this object, but
|
||||||
|
/// properties already present in this <see cref="JsonObject"/> will not be overwritten.
|
||||||
|
/// </para>
|
||||||
|
/// <para>
|
||||||
|
/// Implementations must not make assumptions about its contents.
|
||||||
|
/// </para>
|
||||||
|
/// </remarks>
|
||||||
|
public JsonObject? Meta { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a shallow clone of the current <see cref="McpServerResourceCreateOptions"/> instance.
|
/// Creates a shallow clone of the current <see cref="McpServerResourceCreateOptions"/> instance.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -117,5 +133,6 @@ public sealed class McpServerResourceCreateOptions
|
||||||
SchemaCreateOptions = SchemaCreateOptions,
|
SchemaCreateOptions = SchemaCreateOptions,
|
||||||
Metadata = Metadata,
|
Metadata = Metadata,
|
||||||
Icons = Icons,
|
Icons = Icons,
|
||||||
|
Meta = Meta,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ using Microsoft.Extensions.AI;
|
||||||
using ModelContextProtocol.Protocol;
|
using ModelContextProtocol.Protocol;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
|
using System.Text.Json.Nodes;
|
||||||
|
|
||||||
namespace ModelContextProtocol.Server;
|
namespace ModelContextProtocol.Server;
|
||||||
|
|
||||||
|
|
@ -172,6 +173,21 @@ public sealed class McpServerToolCreateOptions
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public IList<Icon>? Icons { get; set; }
|
public IList<Icon>? Icons { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets metadata reserved by MCP for protocol-level metadata.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// <para>
|
||||||
|
/// This <see cref="JsonObject"/> is used to seed the <see cref="Tool.Meta"/> property. Any metadata from
|
||||||
|
/// <see cref="McpMetaAttribute"/> instances on the method will be added to this object, but
|
||||||
|
/// properties already present in this <see cref="JsonObject"/> will not be overwritten.
|
||||||
|
/// </para>
|
||||||
|
/// <para>
|
||||||
|
/// Implementations must not make assumptions about its contents.
|
||||||
|
/// </para>
|
||||||
|
/// </remarks>
|
||||||
|
public JsonObject? Meta { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a shallow clone of the current <see cref="McpServerToolCreateOptions"/> instance.
|
/// Creates a shallow clone of the current <see cref="McpServerToolCreateOptions"/> instance.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -191,5 +207,6 @@ public sealed class McpServerToolCreateOptions
|
||||||
SchemaCreateOptions = SchemaCreateOptions,
|
SchemaCreateOptions = SchemaCreateOptions,
|
||||||
Metadata = Metadata,
|
Metadata = Metadata,
|
||||||
Icons = Icons,
|
Icons = Icons,
|
||||||
|
Meta = Meta,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
1538
tests/ModelContextProtocol.Tests/Server/McpMetaAttributeTests.cs
Normal file
1538
tests/ModelContextProtocol.Tests/Server/McpMetaAttributeTests.cs
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue