* 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>
1538 lines
60 KiB
C#
1538 lines
60 KiB
C#
using ModelContextProtocol.Server;
|
|
using System.Text.Json;
|
|
using System.Text.Json.Nodes;
|
|
|
|
namespace ModelContextProtocol.Tests.Server;
|
|
|
|
public partial class McpMetaAttributeTests
|
|
{
|
|
#region Direct Attribute Instantiation Tests
|
|
|
|
[Fact]
|
|
public void McpMetaAttribute_StringConstructor_WithValue_RoundtripsCorrectly()
|
|
{
|
|
var attr = new McpMetaAttribute("key", "test-value");
|
|
|
|
Assert.Equal("key", attr.Name);
|
|
Assert.Equal("\"test-value\"", attr.JsonValue);
|
|
|
|
// Verify it can be parsed back as JSON
|
|
var node = JsonNode.Parse(attr.JsonValue);
|
|
Assert.NotNull(node);
|
|
Assert.Equal(JsonValueKind.String, node.GetValueKind());
|
|
Assert.Equal("test-value", node.GetValue<string>());
|
|
}
|
|
|
|
[Fact]
|
|
public void McpMetaAttribute_StringConstructor_WithNull_SerializesAsJsonNull()
|
|
{
|
|
var attr = new McpMetaAttribute("key", (string?)null);
|
|
|
|
Assert.Equal("key", attr.Name);
|
|
Assert.Equal("null", attr.JsonValue);
|
|
|
|
// Verify it parses as JSON null
|
|
var node = JsonNode.Parse(attr.JsonValue);
|
|
Assert.Null(node);
|
|
}
|
|
|
|
[Fact]
|
|
public void McpMetaAttribute_StringConstructor_WithEmptyString_RoundtripsCorrectly()
|
|
{
|
|
var attr = new McpMetaAttribute("key", "");
|
|
|
|
Assert.Equal("key", attr.Name);
|
|
Assert.Equal("\"\"", attr.JsonValue);
|
|
|
|
var node = JsonNode.Parse(attr.JsonValue);
|
|
Assert.NotNull(node);
|
|
Assert.Equal("", node.GetValue<string>());
|
|
}
|
|
|
|
[Fact]
|
|
public void McpMetaAttribute_StringConstructor_WithSpecialCharacters_RoundtripsCorrectly()
|
|
{
|
|
var testString = "Line1\nLine2\tTab\"Quote";
|
|
var attr = new McpMetaAttribute("key", testString);
|
|
|
|
Assert.Equal("key", attr.Name);
|
|
|
|
var node = JsonNode.Parse(attr.JsonValue);
|
|
Assert.NotNull(node);
|
|
Assert.Equal(testString, node.GetValue<string>());
|
|
}
|
|
|
|
[Fact]
|
|
public void McpMetaAttribute_StringConstructor_WithUnicode_RoundtripsCorrectly()
|
|
{
|
|
var testString = "Hello 世界 🌍";
|
|
var attr = new McpMetaAttribute("key", testString);
|
|
|
|
Assert.Equal("key", attr.Name);
|
|
|
|
var node = JsonNode.Parse(attr.JsonValue);
|
|
Assert.NotNull(node);
|
|
Assert.Equal(testString, node.GetValue<string>());
|
|
}
|
|
|
|
[Fact]
|
|
public void McpMetaAttribute_DoubleConstructor_WithPositiveValue_RoundtripsCorrectly()
|
|
{
|
|
var attr = new McpMetaAttribute("key", 3.14159);
|
|
|
|
Assert.Equal("key", attr.Name);
|
|
|
|
var node = JsonNode.Parse(attr.JsonValue);
|
|
Assert.NotNull(node);
|
|
Assert.Equal(JsonValueKind.Number, node.GetValueKind());
|
|
Assert.Equal(3.14159, node.GetValue<double>());
|
|
}
|
|
|
|
[Fact]
|
|
public void McpMetaAttribute_DoubleConstructor_WithNegativeValue_RoundtripsCorrectly()
|
|
{
|
|
var attr = new McpMetaAttribute("key", -999.999);
|
|
|
|
Assert.Equal("key", attr.Name);
|
|
|
|
var node = JsonNode.Parse(attr.JsonValue);
|
|
Assert.NotNull(node);
|
|
Assert.Equal(JsonValueKind.Number, node.GetValueKind());
|
|
Assert.Equal(-999.999, node.GetValue<double>());
|
|
}
|
|
|
|
[Fact]
|
|
public void McpMetaAttribute_DoubleConstructor_WithZero_RoundtripsCorrectly()
|
|
{
|
|
var attr = new McpMetaAttribute("key", 0.0);
|
|
|
|
Assert.Equal("key", attr.Name);
|
|
Assert.Equal("0", attr.JsonValue);
|
|
|
|
var node = JsonNode.Parse(attr.JsonValue);
|
|
Assert.NotNull(node);
|
|
Assert.Equal(JsonValueKind.Number, node.GetValueKind());
|
|
Assert.Equal(0.0, node.GetValue<double>());
|
|
}
|
|
|
|
[Fact]
|
|
public void McpMetaAttribute_DoubleConstructor_WithIntegerValue_RoundtripsCorrectly()
|
|
{
|
|
var attr = new McpMetaAttribute("key", 42.0);
|
|
|
|
Assert.Equal("key", attr.Name);
|
|
Assert.Equal("42", attr.JsonValue);
|
|
|
|
var node = JsonNode.Parse(attr.JsonValue);
|
|
Assert.NotNull(node);
|
|
Assert.Equal(42.0, node.GetValue<double>());
|
|
}
|
|
|
|
[Fact]
|
|
public void McpMetaAttribute_DoubleConstructor_WithMaxValue_RoundtripsCorrectly()
|
|
{
|
|
var attr = new McpMetaAttribute("key", double.MaxValue);
|
|
|
|
Assert.Equal("key", attr.Name);
|
|
|
|
var node = JsonNode.Parse(attr.JsonValue);
|
|
Assert.NotNull(node);
|
|
Assert.Equal(double.MaxValue, node.GetValue<double>());
|
|
}
|
|
|
|
[Fact]
|
|
public void McpMetaAttribute_DoubleConstructor_WithMinValue_RoundtripsCorrectly()
|
|
{
|
|
var attr = new McpMetaAttribute("key", double.MinValue);
|
|
|
|
Assert.Equal("key", attr.Name);
|
|
|
|
var node = JsonNode.Parse(attr.JsonValue);
|
|
Assert.NotNull(node);
|
|
Assert.Equal(double.MinValue, node.GetValue<double>());
|
|
}
|
|
|
|
[Fact]
|
|
public void McpMetaAttribute_DoubleConstructor_WithVerySmallValue_RoundtripsCorrectly()
|
|
{
|
|
var attr = new McpMetaAttribute("key", 0.000001);
|
|
|
|
Assert.Equal("key", attr.Name);
|
|
|
|
var node = JsonNode.Parse(attr.JsonValue);
|
|
Assert.NotNull(node);
|
|
var value = node.GetValue<double>();
|
|
Assert.True(Math.Abs(0.000001 - value) < 0.0000001);
|
|
}
|
|
|
|
[Fact]
|
|
public void McpMetaAttribute_BoolConstructor_WithTrue_RoundtripsCorrectly()
|
|
{
|
|
var attr = new McpMetaAttribute("key", true);
|
|
|
|
Assert.Equal("key", attr.Name);
|
|
Assert.Equal("true", attr.JsonValue);
|
|
|
|
var node = JsonNode.Parse(attr.JsonValue);
|
|
Assert.NotNull(node);
|
|
Assert.Equal(JsonValueKind.True, node.GetValueKind());
|
|
Assert.True(node.GetValue<bool>());
|
|
}
|
|
|
|
[Fact]
|
|
public void McpMetaAttribute_BoolConstructor_WithFalse_RoundtripsCorrectly()
|
|
{
|
|
var attr = new McpMetaAttribute("key", false);
|
|
|
|
Assert.Equal("key", attr.Name);
|
|
Assert.Equal("false", attr.JsonValue);
|
|
|
|
var node = JsonNode.Parse(attr.JsonValue);
|
|
Assert.NotNull(node);
|
|
Assert.Equal(JsonValueKind.False, node.GetValueKind());
|
|
Assert.False(node.GetValue<bool>());
|
|
}
|
|
|
|
[Fact]
|
|
public void McpMetaAttribute_JsonValueProperty_CanBeOverridden()
|
|
{
|
|
var attr = new McpMetaAttribute("key", "original");
|
|
|
|
Assert.Equal("\"original\"", attr.JsonValue);
|
|
|
|
// Override with custom JSON
|
|
attr.JsonValue = """{"custom": "value", "num": 123}""";
|
|
|
|
var node = JsonNode.Parse(attr.JsonValue);
|
|
Assert.NotNull(node);
|
|
Assert.Equal(JsonValueKind.Object, node.GetValueKind());
|
|
|
|
var obj = node.AsObject();
|
|
Assert.Equal("value", obj["custom"]?.GetValue<string>());
|
|
Assert.Equal(123, obj["num"]?.GetValue<int>());
|
|
}
|
|
|
|
[Fact]
|
|
public void McpMetaAttribute_JsonValueProperty_SupportsComplexTypes()
|
|
{
|
|
var attr = new McpMetaAttribute("key", "placeholder")
|
|
{
|
|
JsonValue = """{"nested": {"deep": "value"}, "array": [1, 2, 3]}"""
|
|
};
|
|
|
|
var node = JsonNode.Parse(attr.JsonValue);
|
|
Assert.NotNull(node);
|
|
|
|
var obj = node.AsObject();
|
|
var nested = obj["nested"]?.AsObject();
|
|
Assert.Equal("value", nested?["deep"]?.GetValue<string>());
|
|
|
|
var array = obj["array"]?.AsArray();
|
|
Assert.Equal(3, array?.Count);
|
|
Assert.Equal(1, array?[0]?.GetValue<int>());
|
|
Assert.Equal(2, array?[1]?.GetValue<int>());
|
|
Assert.Equal(3, array?[2]?.GetValue<int>());
|
|
}
|
|
|
|
[Fact]
|
|
public void McpMetaAttribute_StringConstructor_WithDefaultParameter_UsesNull()
|
|
{
|
|
var attr = new McpMetaAttribute("key");
|
|
|
|
Assert.Equal("key", attr.Name);
|
|
Assert.Equal("null", attr.JsonValue);
|
|
|
|
var node = JsonNode.Parse(attr.JsonValue);
|
|
Assert.Null(node);
|
|
}
|
|
|
|
[Fact]
|
|
public void McpMetaAttribute_Name_CanContainSpecialCharacters()
|
|
{
|
|
var attr = new McpMetaAttribute("my-key_with.special/chars", "value");
|
|
|
|
Assert.Equal("my-key_with.special/chars", attr.Name);
|
|
}
|
|
|
|
[Fact]
|
|
public void McpMetaAttribute_MultipleInstances_AreIndependent()
|
|
{
|
|
var attr1 = new McpMetaAttribute("key1", "value1");
|
|
var attr2 = new McpMetaAttribute("key2", 42.0);
|
|
var attr3 = new McpMetaAttribute("key3", true);
|
|
|
|
Assert.Equal("key1", attr1.Name);
|
|
Assert.Equal("\"value1\"", attr1.JsonValue);
|
|
|
|
Assert.Equal("key2", attr2.Name);
|
|
Assert.Equal("42", attr2.JsonValue);
|
|
|
|
Assert.Equal("key3", attr3.Name);
|
|
Assert.Equal("true", attr3.JsonValue);
|
|
|
|
// Modifying one doesn't affect others
|
|
attr1.JsonValue = "\"modified\"";
|
|
Assert.Equal("\"modified\"", attr1.JsonValue);
|
|
Assert.Equal("42", attr2.JsonValue);
|
|
Assert.Equal("true", attr3.JsonValue);
|
|
}
|
|
|
|
[Fact]
|
|
public void McpServerTool_Create_WithStringMeta_PopulatesToolMeta()
|
|
{
|
|
var method = typeof(TestToolStringMetaClass).GetMethod(nameof(TestToolStringMetaClass.ToolWithStringMeta))!;
|
|
|
|
var tool = McpServerTool.Create(method, target: null);
|
|
|
|
Assert.NotNull(tool.ProtocolTool.Meta);
|
|
Assert.Equal(3, tool.ProtocolTool.Meta.Count);
|
|
Assert.Equal("value1", tool.ProtocolTool.Meta["key1"]?.GetValue<string>());
|
|
Assert.Equal("value2", tool.ProtocolTool.Meta["key2"]?.GetValue<string>());
|
|
Assert.Null(tool.ProtocolTool.Meta["key3"]);
|
|
}
|
|
|
|
[Fact]
|
|
public void McpServerTool_Create_WithDoubleMeta_PopulatesToolMeta()
|
|
{
|
|
var method = typeof(TestToolDoubleMetaClass2).GetMethod(nameof(TestToolDoubleMetaClass2.ToolWithDoubleMeta))!;
|
|
|
|
var tool = McpServerTool.Create(method, target: null);
|
|
|
|
Assert.NotNull(tool.ProtocolTool.Meta);
|
|
Assert.Equal(3, tool.ProtocolTool.Meta.Count);
|
|
Assert.Equal(3.14, tool.ProtocolTool.Meta["pi"]?.GetValue<double>());
|
|
Assert.Equal(0.0, tool.ProtocolTool.Meta["zero"]?.GetValue<double>());
|
|
Assert.Equal(-1.5, tool.ProtocolTool.Meta["negative"]?.GetValue<double>());
|
|
}
|
|
|
|
[Fact]
|
|
public void McpServerTool_Create_WithBoolMeta_PopulatesToolMeta()
|
|
{
|
|
var method = typeof(TestToolBoolMetaClass).GetMethod(nameof(TestToolBoolMetaClass.ToolWithBoolMeta))!;
|
|
|
|
var tool = McpServerTool.Create(method, target: null);
|
|
|
|
Assert.NotNull(tool.ProtocolTool.Meta);
|
|
Assert.Equal(2, tool.ProtocolTool.Meta.Count);
|
|
Assert.True(tool.ProtocolTool.Meta["enabled"]?.GetValue<bool>());
|
|
Assert.False(tool.ProtocolTool.Meta["deprecated"]?.GetValue<bool>());
|
|
}
|
|
|
|
[Fact]
|
|
public void McpServerTool_Create_WithAllConstructorTypes_PopulatesToolMeta()
|
|
{
|
|
var method = typeof(TestToolAllTypesMetaClass).GetMethod(nameof(TestToolAllTypesMetaClass.ToolWithAllTypes))!;
|
|
|
|
var tool = McpServerTool.Create(method, target: null);
|
|
|
|
Assert.NotNull(tool.ProtocolTool.Meta);
|
|
Assert.Equal(4, tool.ProtocolTool.Meta.Count);
|
|
|
|
Assert.Equal("test", tool.ProtocolTool.Meta["stringKey"]?.GetValue<string>());
|
|
Assert.Equal(JsonValueKind.String, tool.ProtocolTool.Meta["stringKey"]?.GetValueKind());
|
|
|
|
Assert.Equal(42.5, tool.ProtocolTool.Meta["doubleKey"]?.GetValue<double>());
|
|
Assert.Equal(JsonValueKind.Number, tool.ProtocolTool.Meta["doubleKey"]?.GetValueKind());
|
|
|
|
Assert.True(tool.ProtocolTool.Meta["boolKey"]?.GetValue<bool>());
|
|
Assert.Equal(JsonValueKind.True, tool.ProtocolTool.Meta["boolKey"]?.GetValueKind());
|
|
|
|
Assert.Null(tool.ProtocolTool.Meta["nullKey"]);
|
|
}
|
|
|
|
[Fact]
|
|
public void McpServerPrompt_Create_WithStringMeta_PopulatesPromptMeta()
|
|
{
|
|
var method = typeof(TestPromptStringMetaClass).GetMethod(nameof(TestPromptStringMetaClass.PromptWithStringMeta))!;
|
|
|
|
var prompt = McpServerPrompt.Create(method, target: null);
|
|
|
|
Assert.NotNull(prompt.ProtocolPrompt.Meta);
|
|
Assert.Equal(2, prompt.ProtocolPrompt.Meta.Count);
|
|
Assert.Equal("system", prompt.ProtocolPrompt.Meta["role"]?.GetValue<string>());
|
|
Assert.Equal("instruction", prompt.ProtocolPrompt.Meta["type"]?.GetValue<string>());
|
|
}
|
|
|
|
[Fact]
|
|
public void McpServerPrompt_Create_WithDoubleMeta_PopulatesPromptMeta()
|
|
{
|
|
var method = typeof(TestPromptDoubleMetaClass).GetMethod(nameof(TestPromptDoubleMetaClass.PromptWithDoubleMeta))!;
|
|
|
|
var prompt = McpServerPrompt.Create(method, target: null);
|
|
|
|
Assert.NotNull(prompt.ProtocolPrompt.Meta);
|
|
Assert.Equal(2, prompt.ProtocolPrompt.Meta.Count);
|
|
Assert.Equal(0.7, prompt.ProtocolPrompt.Meta["temperature"]?.GetValue<double>());
|
|
Assert.Equal(100.0, prompt.ProtocolPrompt.Meta["maxTokens"]?.GetValue<double>());
|
|
}
|
|
|
|
[Fact]
|
|
public void McpServerPrompt_Create_WithBoolMeta_PopulatesPromptMeta()
|
|
{
|
|
var method = typeof(TestPromptBoolMetaClass).GetMethod(nameof(TestPromptBoolMetaClass.PromptWithBoolMeta))!;
|
|
|
|
var prompt = McpServerPrompt.Create(method, target: null);
|
|
|
|
Assert.NotNull(prompt.ProtocolPrompt.Meta);
|
|
Assert.Single(prompt.ProtocolPrompt.Meta);
|
|
Assert.True(prompt.ProtocolPrompt.Meta["stream"]?.GetValue<bool>());
|
|
}
|
|
|
|
[Fact]
|
|
public void McpServerPrompt_Create_WithAllConstructorTypes_PopulatesPromptMeta()
|
|
{
|
|
var method = typeof(TestPromptAllTypesMetaClass).GetMethod(nameof(TestPromptAllTypesMetaClass.PromptWithAllTypes))!;
|
|
|
|
var prompt = McpServerPrompt.Create(method, target: null);
|
|
|
|
Assert.NotNull(prompt.ProtocolPrompt.Meta);
|
|
Assert.Equal(4, prompt.ProtocolPrompt.Meta.Count);
|
|
Assert.Equal("user", prompt.ProtocolPrompt.Meta["role"]?.GetValue<string>());
|
|
Assert.Equal(1.0, prompt.ProtocolPrompt.Meta["version"]?.GetValue<double>());
|
|
Assert.False(prompt.ProtocolPrompt.Meta["experimental"]?.GetValue<bool>());
|
|
Assert.Null(prompt.ProtocolPrompt.Meta["deprecated"]);
|
|
}
|
|
|
|
[Fact]
|
|
public void McpServerResource_Create_WithStringMeta_PopulatesResourceMeta()
|
|
{
|
|
var method = typeof(TestResourceStringMetaClass).GetMethod(nameof(TestResourceStringMetaClass.ResourceWithStringMeta))!;
|
|
|
|
var resource = McpServerResource.Create(method, target: null);
|
|
|
|
Assert.NotNull(resource.ProtocolResourceTemplate?.Meta);
|
|
Assert.Equal(2, resource.ProtocolResourceTemplate.Meta.Count);
|
|
Assert.Equal("text/html", resource.ProtocolResourceTemplate.Meta["contentType"]?.GetValue<string>());
|
|
Assert.Equal("utf-8", resource.ProtocolResourceTemplate.Meta["encoding"]?.GetValue<string>());
|
|
}
|
|
|
|
[Fact]
|
|
public void McpServerResource_Create_WithDoubleMeta_PopulatesResourceMeta()
|
|
{
|
|
var method = typeof(TestResourceDoubleMetaClass).GetMethod(nameof(TestResourceDoubleMetaClass.ResourceWithDoubleMeta))!;
|
|
|
|
var resource = McpServerResource.Create(method, target: null);
|
|
|
|
Assert.NotNull(resource.ProtocolResourceTemplate?.Meta);
|
|
Assert.Equal(2, resource.ProtocolResourceTemplate.Meta.Count);
|
|
Assert.Equal(1.5, resource.ProtocolResourceTemplate.Meta["version"]?.GetValue<double>());
|
|
Assert.Equal(3600.0, resource.ProtocolResourceTemplate.Meta["cacheDuration"]?.GetValue<double>());
|
|
}
|
|
|
|
[Fact]
|
|
public void McpServerResource_Create_WithBoolMeta_PopulatesResourceMeta()
|
|
{
|
|
var method = typeof(TestResourceBoolMetaClass).GetMethod(nameof(TestResourceBoolMetaClass.ResourceWithBoolMeta))!;
|
|
|
|
var resource = McpServerResource.Create(method, target: null);
|
|
|
|
Assert.NotNull(resource.ProtocolResourceTemplate?.Meta);
|
|
Assert.Equal(2, resource.ProtocolResourceTemplate.Meta.Count);
|
|
Assert.True(resource.ProtocolResourceTemplate.Meta["cacheable"]?.GetValue<bool>());
|
|
Assert.False(resource.ProtocolResourceTemplate.Meta["requiresAuth"]?.GetValue<bool>());
|
|
}
|
|
|
|
[Fact]
|
|
public void McpServerResource_Create_WithAllConstructorTypes_PopulatesResourceMeta()
|
|
{
|
|
var method = typeof(TestResourceAllTypesMetaClass).GetMethod(nameof(TestResourceAllTypesMetaClass.ResourceWithAllTypes))!;
|
|
|
|
var resource = McpServerResource.Create(method, target: null);
|
|
|
|
Assert.NotNull(resource.ProtocolResourceTemplate?.Meta);
|
|
Assert.Equal(4, resource.ProtocolResourceTemplate.Meta.Count);
|
|
Assert.Equal("public", resource.ProtocolResourceTemplate.Meta["visibility"]?.GetValue<string>());
|
|
Assert.Equal(2.0, resource.ProtocolResourceTemplate.Meta["apiVersion"]?.GetValue<double>());
|
|
Assert.True(resource.ProtocolResourceTemplate.Meta["available"]?.GetValue<bool>());
|
|
Assert.Null(resource.ProtocolResourceTemplate.Meta["owner"]);
|
|
}
|
|
|
|
[Fact]
|
|
public void McpServerTool_Create_WithJsonValueMeta_PopulatesToolMetaWithComplexTypes()
|
|
{
|
|
var method = typeof(TestToolJsonValueMetaClass).GetMethod(nameof(TestToolJsonValueMetaClass.ToolWithJsonValueMeta))!;
|
|
|
|
var tool = McpServerTool.Create(method, target: null);
|
|
|
|
Assert.NotNull(tool.ProtocolTool.Meta);
|
|
|
|
// Verify integer via JsonValue
|
|
Assert.Equal(42, tool.ProtocolTool.Meta["count"]?.GetValue<int>());
|
|
Assert.Equal(JsonValueKind.Number, tool.ProtocolTool.Meta["count"]?.GetValueKind());
|
|
|
|
// Verify array via JsonValue
|
|
var tags = tool.ProtocolTool.Meta["tags"]?.AsArray();
|
|
Assert.NotNull(tags);
|
|
Assert.Equal(3, tags.Count);
|
|
Assert.Equal("tag1", tags[0]?.GetValue<string>());
|
|
|
|
// Verify object via JsonValue
|
|
var config = tool.ProtocolTool.Meta["config"]?.AsObject();
|
|
Assert.NotNull(config);
|
|
Assert.Equal("high", config["priority"]?.GetValue<string>());
|
|
}
|
|
|
|
[Fact]
|
|
public void McpServerPrompt_Create_WithJsonValueMeta_PopulatesPromptMetaWithComplexTypes()
|
|
{
|
|
var method = typeof(TestPromptJsonValueMetaClass).GetMethod(nameof(TestPromptJsonValueMetaClass.PromptWithJsonValueMeta))!;
|
|
|
|
var prompt = McpServerPrompt.Create(method, target: null);
|
|
|
|
Assert.NotNull(prompt.ProtocolPrompt.Meta);
|
|
|
|
var parameters = prompt.ProtocolPrompt.Meta["parameters"]?.AsObject();
|
|
Assert.NotNull(parameters);
|
|
Assert.Equal("string", parameters["type"]?.GetValue<string>());
|
|
Assert.True(parameters["required"]?.GetValue<bool>());
|
|
}
|
|
|
|
[Fact]
|
|
public void McpServerResource_Create_WithJsonValueMeta_PopulatesResourceMetaWithComplexTypes()
|
|
{
|
|
var method = typeof(TestResourceJsonValueMetaClass).GetMethod(nameof(TestResourceJsonValueMetaClass.ResourceWithJsonValueMeta))!;
|
|
|
|
var resource = McpServerResource.Create(method, target: null);
|
|
|
|
Assert.NotNull(resource.ProtocolResourceTemplate?.Meta);
|
|
|
|
var metadata = resource.ProtocolResourceTemplate.Meta["metadata"]?.AsObject();
|
|
Assert.NotNull(metadata);
|
|
Assert.Equal("document", metadata["type"]?.GetValue<string>());
|
|
|
|
var permissions = resource.ProtocolResourceTemplate.Meta["permissions"]?.AsArray();
|
|
Assert.NotNull(permissions);
|
|
Assert.Equal(2, permissions.Count);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Options Meta Interaction Tests
|
|
|
|
[Fact]
|
|
public void McpServerTool_Create_WithNullOptionsMeta_UsesAttributesOnly()
|
|
{
|
|
var method = typeof(TestToolStringMetaClass).GetMethod(nameof(TestToolStringMetaClass.ToolWithStringMeta))!;
|
|
var options = new McpServerToolCreateOptions { Meta = null };
|
|
|
|
var tool = McpServerTool.Create(method, target: null, options: options);
|
|
|
|
Assert.NotNull(tool.ProtocolTool.Meta);
|
|
Assert.Equal(3, tool.ProtocolTool.Meta.Count);
|
|
Assert.Equal("value1", tool.ProtocolTool.Meta["key1"]?.GetValue<string>());
|
|
Assert.Equal("value2", tool.ProtocolTool.Meta["key2"]?.GetValue<string>());
|
|
Assert.Null(tool.ProtocolTool.Meta["key3"]);
|
|
}
|
|
|
|
[Fact]
|
|
public void McpServerTool_Create_WithEmptyOptionsMeta_UsesAttributesOnly()
|
|
{
|
|
var method = typeof(TestToolStringMetaClass).GetMethod(nameof(TestToolStringMetaClass.ToolWithStringMeta))!;
|
|
var options = new McpServerToolCreateOptions { Meta = new JsonObject() };
|
|
|
|
var tool = McpServerTool.Create(method, target: null, options: options);
|
|
|
|
Assert.NotNull(tool.ProtocolTool.Meta);
|
|
Assert.Equal(3, tool.ProtocolTool.Meta.Count);
|
|
Assert.Equal("value1", tool.ProtocolTool.Meta["key1"]?.GetValue<string>());
|
|
Assert.Equal("value2", tool.ProtocolTool.Meta["key2"]?.GetValue<string>());
|
|
Assert.Null(tool.ProtocolTool.Meta["key3"]);
|
|
}
|
|
|
|
[Fact]
|
|
public void McpServerTool_Create_WithNonConflictingOptionsMeta_MergesBoth()
|
|
{
|
|
var method = typeof(TestToolStringMetaClass).GetMethod(nameof(TestToolStringMetaClass.ToolWithStringMeta))!;
|
|
var options = new McpServerToolCreateOptions
|
|
{
|
|
Meta = new JsonObject
|
|
{
|
|
["newKey1"] = "newValue1",
|
|
["newKey2"] = 42
|
|
}
|
|
};
|
|
|
|
var tool = McpServerTool.Create(method, target: null, options: options);
|
|
|
|
Assert.NotNull(tool.ProtocolTool.Meta);
|
|
Assert.Equal(5, tool.ProtocolTool.Meta.Count);
|
|
|
|
// From attributes
|
|
Assert.Equal("value1", tool.ProtocolTool.Meta["key1"]?.GetValue<string>());
|
|
Assert.Equal("value2", tool.ProtocolTool.Meta["key2"]?.GetValue<string>());
|
|
Assert.Null(tool.ProtocolTool.Meta["key3"]);
|
|
|
|
// From options
|
|
Assert.Equal("newValue1", tool.ProtocolTool.Meta["newKey1"]?.GetValue<string>());
|
|
Assert.Equal(42, tool.ProtocolTool.Meta["newKey2"]?.GetValue<int>());
|
|
}
|
|
|
|
[Fact]
|
|
public void McpServerTool_Create_WithConflictingOptionsMeta_OptionsWin()
|
|
{
|
|
var method = typeof(TestToolStringMetaClass).GetMethod(nameof(TestToolStringMetaClass.ToolWithStringMeta))!;
|
|
var options = new McpServerToolCreateOptions
|
|
{
|
|
Meta = new JsonObject
|
|
{
|
|
["key1"] = "overridden", // Conflicts with attribute
|
|
["newKey"] = "added" // Non-conflicting
|
|
}
|
|
};
|
|
|
|
var tool = McpServerTool.Create(method, target: null, options: options);
|
|
|
|
Assert.NotNull(tool.ProtocolTool.Meta);
|
|
Assert.Equal(4, tool.ProtocolTool.Meta.Count);
|
|
|
|
// Options take precedence
|
|
Assert.Equal("overridden", tool.ProtocolTool.Meta["key1"]?.GetValue<string>());
|
|
|
|
// Attributes that don't conflict
|
|
Assert.Equal("value2", tool.ProtocolTool.Meta["key2"]?.GetValue<string>());
|
|
Assert.Null(tool.ProtocolTool.Meta["key3"]);
|
|
|
|
// From options only
|
|
Assert.Equal("added", tool.ProtocolTool.Meta["newKey"]?.GetValue<string>());
|
|
}
|
|
|
|
[Fact]
|
|
public void McpServerPrompt_Create_WithNullOptionsMeta_UsesAttributesOnly()
|
|
{
|
|
var method = typeof(TestPromptStringMetaClass).GetMethod(nameof(TestPromptStringMetaClass.PromptWithStringMeta))!;
|
|
var options = new McpServerPromptCreateOptions { Meta = null };
|
|
|
|
var prompt = McpServerPrompt.Create(method, target: null, options: options);
|
|
|
|
Assert.NotNull(prompt.ProtocolPrompt.Meta);
|
|
Assert.Equal(2, prompt.ProtocolPrompt.Meta.Count);
|
|
Assert.Equal("system", prompt.ProtocolPrompt.Meta["role"]?.GetValue<string>());
|
|
Assert.Equal("instruction", prompt.ProtocolPrompt.Meta["type"]?.GetValue<string>());
|
|
}
|
|
|
|
[Fact]
|
|
public void McpServerPrompt_Create_WithEmptyOptionsMeta_UsesAttributesOnly()
|
|
{
|
|
var method = typeof(TestPromptStringMetaClass).GetMethod(nameof(TestPromptStringMetaClass.PromptWithStringMeta))!;
|
|
var options = new McpServerPromptCreateOptions { Meta = new JsonObject() };
|
|
|
|
var prompt = McpServerPrompt.Create(method, target: null, options: options);
|
|
|
|
Assert.NotNull(prompt.ProtocolPrompt.Meta);
|
|
Assert.Equal(2, prompt.ProtocolPrompt.Meta.Count);
|
|
Assert.Equal("system", prompt.ProtocolPrompt.Meta["role"]?.GetValue<string>());
|
|
Assert.Equal("instruction", prompt.ProtocolPrompt.Meta["type"]?.GetValue<string>());
|
|
}
|
|
|
|
[Fact]
|
|
public void McpServerPrompt_Create_WithNonConflictingOptionsMeta_MergesBoth()
|
|
{
|
|
var method = typeof(TestPromptStringMetaClass).GetMethod(nameof(TestPromptStringMetaClass.PromptWithStringMeta))!;
|
|
var options = new McpServerPromptCreateOptions
|
|
{
|
|
Meta = new JsonObject
|
|
{
|
|
["temperature"] = 0.7,
|
|
["maxTokens"] = 100.0
|
|
}
|
|
};
|
|
|
|
var prompt = McpServerPrompt.Create(method, target: null, options: options);
|
|
|
|
Assert.NotNull(prompt.ProtocolPrompt.Meta);
|
|
Assert.Equal(4, prompt.ProtocolPrompt.Meta.Count);
|
|
|
|
// From attributes
|
|
Assert.Equal("system", prompt.ProtocolPrompt.Meta["role"]?.GetValue<string>());
|
|
Assert.Equal("instruction", prompt.ProtocolPrompt.Meta["type"]?.GetValue<string>());
|
|
|
|
// From options
|
|
Assert.Equal(0.7, prompt.ProtocolPrompt.Meta["temperature"]?.GetValue<double>());
|
|
Assert.Equal(100.0, prompt.ProtocolPrompt.Meta["maxTokens"]?.GetValue<double>());
|
|
}
|
|
|
|
[Fact]
|
|
public void McpServerPrompt_Create_WithConflictingOptionsMeta_OptionsWin()
|
|
{
|
|
var method = typeof(TestPromptStringMetaClass).GetMethod(nameof(TestPromptStringMetaClass.PromptWithStringMeta))!;
|
|
var options = new McpServerPromptCreateOptions
|
|
{
|
|
Meta = new JsonObject
|
|
{
|
|
["role"] = "user", // Conflicts with attribute
|
|
["priority"] = 5 // Non-conflicting
|
|
}
|
|
};
|
|
|
|
var prompt = McpServerPrompt.Create(method, target: null, options: options);
|
|
|
|
Assert.NotNull(prompt.ProtocolPrompt.Meta);
|
|
Assert.Equal(3, prompt.ProtocolPrompt.Meta.Count);
|
|
|
|
// Options take precedence
|
|
Assert.Equal("user", prompt.ProtocolPrompt.Meta["role"]?.GetValue<string>());
|
|
|
|
// Attributes that don't conflict
|
|
Assert.Equal("instruction", prompt.ProtocolPrompt.Meta["type"]?.GetValue<string>());
|
|
|
|
// From options only
|
|
Assert.Equal(5, prompt.ProtocolPrompt.Meta["priority"]?.GetValue<int>());
|
|
}
|
|
|
|
[Fact]
|
|
public void McpServerResource_Create_WithNullOptionsMeta_UsesAttributesOnly()
|
|
{
|
|
var method = typeof(TestResourceStringMetaClass).GetMethod(nameof(TestResourceStringMetaClass.ResourceWithStringMeta))!;
|
|
var options = new McpServerResourceCreateOptions { Meta = null };
|
|
|
|
var resource = McpServerResource.Create(method, target: null, options: options);
|
|
|
|
Assert.NotNull(resource.ProtocolResourceTemplate?.Meta);
|
|
Assert.Equal(2, resource.ProtocolResourceTemplate.Meta.Count);
|
|
Assert.Equal("text/html", resource.ProtocolResourceTemplate.Meta["contentType"]?.GetValue<string>());
|
|
Assert.Equal("utf-8", resource.ProtocolResourceTemplate.Meta["encoding"]?.GetValue<string>());
|
|
}
|
|
|
|
[Fact]
|
|
public void McpServerResource_Create_WithEmptyOptionsMeta_UsesAttributesOnly()
|
|
{
|
|
var method = typeof(TestResourceStringMetaClass).GetMethod(nameof(TestResourceStringMetaClass.ResourceWithStringMeta))!;
|
|
var options = new McpServerResourceCreateOptions { Meta = new JsonObject() };
|
|
|
|
var resource = McpServerResource.Create(method, target: null, options: options);
|
|
|
|
Assert.NotNull(resource.ProtocolResourceTemplate?.Meta);
|
|
Assert.Equal(2, resource.ProtocolResourceTemplate.Meta.Count);
|
|
Assert.Equal("text/html", resource.ProtocolResourceTemplate.Meta["contentType"]?.GetValue<string>());
|
|
Assert.Equal("utf-8", resource.ProtocolResourceTemplate.Meta["encoding"]?.GetValue<string>());
|
|
}
|
|
|
|
[Fact]
|
|
public void McpServerResource_Create_WithNonConflictingOptionsMeta_MergesBoth()
|
|
{
|
|
var method = typeof(TestResourceStringMetaClass).GetMethod(nameof(TestResourceStringMetaClass.ResourceWithStringMeta))!;
|
|
var options = new McpServerResourceCreateOptions
|
|
{
|
|
Meta = new JsonObject
|
|
{
|
|
["cacheable"] = true,
|
|
["version"] = 2.0
|
|
}
|
|
};
|
|
|
|
var resource = McpServerResource.Create(method, target: null, options: options);
|
|
|
|
Assert.NotNull(resource.ProtocolResourceTemplate?.Meta);
|
|
Assert.Equal(4, resource.ProtocolResourceTemplate.Meta.Count);
|
|
|
|
// From attributes
|
|
Assert.Equal("text/html", resource.ProtocolResourceTemplate.Meta["contentType"]?.GetValue<string>());
|
|
Assert.Equal("utf-8", resource.ProtocolResourceTemplate.Meta["encoding"]?.GetValue<string>());
|
|
|
|
// From options
|
|
Assert.True(resource.ProtocolResourceTemplate.Meta["cacheable"]?.GetValue<bool>());
|
|
Assert.Equal(2.0, resource.ProtocolResourceTemplate.Meta["version"]?.GetValue<double>());
|
|
}
|
|
|
|
[Fact]
|
|
public void McpServerResource_Create_WithConflictingOptionsMeta_OptionsWin()
|
|
{
|
|
var method = typeof(TestResourceStringMetaClass).GetMethod(nameof(TestResourceStringMetaClass.ResourceWithStringMeta))!;
|
|
var options = new McpServerResourceCreateOptions
|
|
{
|
|
Meta = new JsonObject
|
|
{
|
|
["encoding"] = "iso-8859-1", // Conflicts with attribute
|
|
["size"] = 1024 // Non-conflicting
|
|
}
|
|
};
|
|
|
|
var resource = McpServerResource.Create(method, target: null, options: options);
|
|
|
|
Assert.NotNull(resource.ProtocolResourceTemplate?.Meta);
|
|
Assert.Equal(3, resource.ProtocolResourceTemplate.Meta.Count);
|
|
|
|
// Options take precedence
|
|
Assert.Equal("iso-8859-1", resource.ProtocolResourceTemplate.Meta["encoding"]?.GetValue<string>());
|
|
|
|
// Attributes that don't conflict
|
|
Assert.Equal("text/html", resource.ProtocolResourceTemplate.Meta["contentType"]?.GetValue<string>());
|
|
|
|
// From options only
|
|
Assert.Equal(1024, resource.ProtocolResourceTemplate.Meta["size"]?.GetValue<int>());
|
|
}
|
|
|
|
[Fact]
|
|
public void McpServerTool_Create_WithOptionsMetaOnly_NoAttributes_PopulatesMeta()
|
|
{
|
|
var method = typeof(TestToolClass).GetMethod(nameof(TestToolClass.ToolWithoutMeta))!;
|
|
var options = new McpServerToolCreateOptions
|
|
{
|
|
Meta = new JsonObject
|
|
{
|
|
["optionsKey"] = "optionsValue",
|
|
["count"] = 10
|
|
}
|
|
};
|
|
|
|
var tool = McpServerTool.Create(method, target: null, options: options);
|
|
|
|
Assert.NotNull(tool.ProtocolTool.Meta);
|
|
Assert.Equal(2, tool.ProtocolTool.Meta.Count);
|
|
Assert.Equal("optionsValue", tool.ProtocolTool.Meta["optionsKey"]?.GetValue<string>());
|
|
Assert.Equal(10, tool.ProtocolTool.Meta["count"]?.GetValue<int>());
|
|
}
|
|
|
|
[Fact]
|
|
public void McpServerPrompt_Create_WithOptionsMetaOnly_NoAttributes_PopulatesMeta()
|
|
{
|
|
var method = typeof(TestPromptNoMetaClass).GetMethod(nameof(TestPromptNoMetaClass.PromptWithoutMeta))!;
|
|
var options = new McpServerPromptCreateOptions
|
|
{
|
|
Meta = new JsonObject
|
|
{
|
|
["model"] = "gpt-4",
|
|
["temperature"] = 0.5
|
|
}
|
|
};
|
|
|
|
var prompt = McpServerPrompt.Create(method, target: null, options: options);
|
|
|
|
Assert.NotNull(prompt.ProtocolPrompt.Meta);
|
|
Assert.Equal(2, prompt.ProtocolPrompt.Meta.Count);
|
|
Assert.Equal("gpt-4", prompt.ProtocolPrompt.Meta["model"]?.GetValue<string>());
|
|
Assert.Equal(0.5, prompt.ProtocolPrompt.Meta["temperature"]?.GetValue<double>());
|
|
}
|
|
|
|
[Fact]
|
|
public void McpServerResource_Create_WithOptionsMetaOnly_NoAttributes_PopulatesMeta()
|
|
{
|
|
var method = typeof(TestResourceNoMetaClass).GetMethod(nameof(TestResourceNoMetaClass.ResourceWithoutMeta))!;
|
|
var options = new McpServerResourceCreateOptions
|
|
{
|
|
Meta = new JsonObject
|
|
{
|
|
["format"] = "json",
|
|
["compressed"] = false
|
|
}
|
|
};
|
|
|
|
var resource = McpServerResource.Create(method, target: null, options: options);
|
|
|
|
Assert.NotNull(resource.ProtocolResourceTemplate?.Meta);
|
|
Assert.Equal(2, resource.ProtocolResourceTemplate.Meta.Count);
|
|
Assert.Equal("json", resource.ProtocolResourceTemplate.Meta["format"]?.GetValue<string>());
|
|
Assert.False(resource.ProtocolResourceTemplate.Meta["compressed"]?.GetValue<bool>());
|
|
}
|
|
|
|
#endregion
|
|
|
|
[Fact]
|
|
public void McpMetaAttribute_OnTool_PopulatesMeta()
|
|
{
|
|
var method = typeof(TestToolClass).GetMethod(nameof(TestToolClass.ToolWithMeta))!;
|
|
|
|
var tool = McpServerTool.Create(method, target: null);
|
|
|
|
Assert.NotNull(tool.ProtocolTool.Meta);
|
|
Assert.Equal("gpt-4o", tool.ProtocolTool.Meta["model"]?.ToString());
|
|
Assert.Equal("1.0", tool.ProtocolTool.Meta["version"]?.ToString());
|
|
}
|
|
|
|
[Fact]
|
|
public void McpMetaAttribute_OnPrompt_PopulatesMeta()
|
|
{
|
|
var method = typeof(TestPromptClass).GetMethod(nameof(TestPromptClass.PromptWithMeta))!;
|
|
|
|
var prompt = McpServerPrompt.Create(method, target: null);
|
|
|
|
Assert.NotNull(prompt.ProtocolPrompt.Meta);
|
|
Assert.Equal("reasoning", prompt.ProtocolPrompt.Meta["type"]?.ToString());
|
|
Assert.Equal("claude-3", prompt.ProtocolPrompt.Meta["model"]?.ToString());
|
|
}
|
|
|
|
[Fact]
|
|
public void McpMetaAttribute_OnResource_PopulatesMeta()
|
|
{
|
|
var method = typeof(TestResourceClass).GetMethod(nameof(TestResourceClass.ResourceWithMeta))!;
|
|
|
|
var resource = McpServerResource.Create(method, target: null);
|
|
|
|
Assert.NotNull(resource.ProtocolResourceTemplate?.Meta);
|
|
Assert.Equal("text/plain", resource.ProtocolResourceTemplate.Meta["encoding"]?.ToString());
|
|
Assert.Equal("cached", resource.ProtocolResourceTemplate.Meta["caching"]?.ToString());
|
|
}
|
|
|
|
[Fact]
|
|
public void McpMetaAttribute_WithoutAttributes_ReturnsNull()
|
|
{
|
|
var method = typeof(TestToolClass).GetMethod(nameof(TestToolClass.ToolWithoutMeta))!;
|
|
|
|
var tool = McpServerTool.Create(method, target: null);
|
|
|
|
Assert.Null(tool.ProtocolTool.Meta);
|
|
}
|
|
|
|
[Fact]
|
|
public void McpMetaAttribute_SingleAttribute_PopulatesMeta()
|
|
{
|
|
// Arrange
|
|
var method = typeof(TestToolClass).GetMethod(nameof(TestToolClass.ToolWithSingleMeta))!;
|
|
|
|
// Act
|
|
var tool = McpServerTool.Create(method, target: null);
|
|
|
|
// Assert
|
|
Assert.NotNull(tool.ProtocolTool.Meta);
|
|
Assert.Equal("test-value", tool.ProtocolTool.Meta["test-key"]?.ToString());
|
|
Assert.Single(tool.ProtocolTool.Meta);
|
|
}
|
|
|
|
[Fact]
|
|
public void McpMetaAttribute_OptionsMetaTakesPrecedence()
|
|
{
|
|
var method = typeof(TestToolClass).GetMethod(nameof(TestToolClass.ToolWithMeta))!;
|
|
var seedMeta = new JsonObject
|
|
{
|
|
["model"] = "options-model",
|
|
["extra"] = "options-extra"
|
|
};
|
|
var options = new McpServerToolCreateOptions { Meta = seedMeta };
|
|
|
|
var tool = McpServerTool.Create(method, target: null, options: options);
|
|
|
|
Assert.NotNull(tool.ProtocolTool.Meta);
|
|
Assert.Equal("options-model", tool.ProtocolTool.Meta["model"]?.ToString());
|
|
Assert.Equal("1.0", tool.ProtocolTool.Meta["version"]?.ToString());
|
|
Assert.Equal("options-extra", tool.ProtocolTool.Meta["extra"]?.ToString());
|
|
}
|
|
|
|
[Fact]
|
|
public void McpMetaAttribute_OptionsMetaOnly_NoAttributes()
|
|
{
|
|
var method = typeof(TestToolClass).GetMethod(nameof(TestToolClass.ToolWithoutMeta))!;
|
|
var seedMeta = new JsonObject
|
|
{
|
|
["custom"] = "value"
|
|
};
|
|
var options = new McpServerToolCreateOptions { Meta = seedMeta };
|
|
var tool = McpServerTool.Create(method, target: null, options: options);
|
|
|
|
Assert.NotNull(tool.ProtocolTool.Meta);
|
|
Assert.Equal("value", tool.ProtocolTool.Meta["custom"]?.ToString());
|
|
Assert.Single(tool.ProtocolTool.Meta);
|
|
}
|
|
|
|
[Fact]
|
|
public void McpMetaAttribute_PromptOptionsMetaTakesPrecedence()
|
|
{
|
|
var method = typeof(TestPromptClass).GetMethod(nameof(TestPromptClass.PromptWithMeta))!;
|
|
var seedMeta = new JsonObject
|
|
{
|
|
["type"] = "options-type",
|
|
["extra"] = "options-extra"
|
|
};
|
|
var options = new McpServerPromptCreateOptions { Meta = seedMeta };
|
|
|
|
var prompt = McpServerPrompt.Create(method, target: null, options: options);
|
|
|
|
Assert.NotNull(prompt.ProtocolPrompt.Meta);
|
|
Assert.Equal("options-type", prompt.ProtocolPrompt.Meta["type"]?.ToString());
|
|
Assert.Equal("claude-3", prompt.ProtocolPrompt.Meta["model"]?.ToString());
|
|
Assert.Equal("options-extra", prompt.ProtocolPrompt.Meta["extra"]?.ToString());
|
|
}
|
|
|
|
[Fact]
|
|
public void McpMetaAttribute_ResourceOptionsMetaTakesPrecedence()
|
|
{
|
|
var method = typeof(TestResourceClass).GetMethod(nameof(TestResourceClass.ResourceWithMeta))!;
|
|
var seedMeta = new JsonObject
|
|
{
|
|
["encoding"] = "options-encoding",
|
|
["extra"] = "options-extra"
|
|
};
|
|
var options = new McpServerResourceCreateOptions { Meta = seedMeta };
|
|
|
|
var resource = McpServerResource.Create(method, target: null, options: options);
|
|
|
|
Assert.NotNull(resource.ProtocolResourceTemplate?.Meta);
|
|
Assert.Equal("options-encoding", resource.ProtocolResourceTemplate.Meta["encoding"]?.ToString());
|
|
Assert.Equal("cached", resource.ProtocolResourceTemplate.Meta["caching"]?.ToString());
|
|
Assert.Equal("options-extra", resource.ProtocolResourceTemplate.Meta["extra"]?.ToString());
|
|
}
|
|
|
|
[Fact]
|
|
public void McpMetaAttribute_ResourceOptionsMetaOnly_NoAttributes()
|
|
{
|
|
var method = typeof(TestResourceNoMetaClass).GetMethod(nameof(TestResourceNoMetaClass.ResourceWithoutMeta))!;
|
|
var seedMeta = new JsonObject { ["only"] = "resource" };
|
|
var options = new McpServerResourceCreateOptions { Meta = seedMeta };
|
|
|
|
var resource = McpServerResource.Create(method, target: null, options: options);
|
|
|
|
Assert.NotNull(resource.ProtocolResourceTemplate?.Meta);
|
|
Assert.Equal("resource", resource.ProtocolResourceTemplate.Meta["only"]?.ToString());
|
|
Assert.Single(resource.ProtocolResourceTemplate.Meta!);
|
|
}
|
|
|
|
[Fact]
|
|
public void McpMetaAttribute_PromptWithoutMeta_ReturnsNull()
|
|
{
|
|
var method = typeof(TestPromptNoMetaClass).GetMethod(nameof(TestPromptNoMetaClass.PromptWithoutMeta))!;
|
|
var prompt = McpServerPrompt.Create(method, target: null);
|
|
Assert.Null(prompt.ProtocolPrompt.Meta);
|
|
}
|
|
|
|
[Fact]
|
|
public void McpMetaAttribute_DuplicateKeys_IgnoresLaterAttributes()
|
|
{
|
|
var method = typeof(TestToolDuplicateMetaClass).GetMethod(nameof(TestToolDuplicateMetaClass.ToolWithDuplicateMeta))!;
|
|
var tool = McpServerTool.Create(method, target: null);
|
|
Assert.NotNull(tool.ProtocolTool.Meta);
|
|
// "key" first attribute value should remain, second ignored
|
|
Assert.Equal("first", tool.ProtocolTool.Meta["key"]?.ToString());
|
|
// Ensure only two keys (key and other)
|
|
Assert.Equal(2, tool.ProtocolTool.Meta!.Count);
|
|
Assert.Equal("other-value", tool.ProtocolTool.Meta["other"]?.ToString());
|
|
}
|
|
|
|
[Fact]
|
|
public void McpMetaAttribute_DuplicateKeys_WithSeedMeta_SeedTakesPrecedence()
|
|
{
|
|
var method = typeof(TestToolDuplicateMetaClass).GetMethod(nameof(TestToolDuplicateMetaClass.ToolWithDuplicateMeta))!;
|
|
var seedMeta = new JsonObject { ["key"] = "seed" };
|
|
var options = new McpServerToolCreateOptions { Meta = seedMeta };
|
|
var tool = McpServerTool.Create(method, target: null, options: options);
|
|
Assert.NotNull(tool.ProtocolTool.Meta);
|
|
Assert.Equal("seed", tool.ProtocolTool.Meta["key"]?.ToString());
|
|
Assert.Equal("other-value", tool.ProtocolTool.Meta["other"]?.ToString());
|
|
Assert.Equal(2, tool.ProtocolTool.Meta!.Count);
|
|
}
|
|
|
|
[Fact]
|
|
public void McpMetaAttribute_NullValue_SerializedAsNull()
|
|
{
|
|
var method = typeof(TestToolNullMetaClass).GetMethod(nameof(TestToolNullMetaClass.ToolWithNullMeta))!;
|
|
var tool = McpServerTool.Create(method, target: null);
|
|
Assert.NotNull(tool.ProtocolTool.Meta);
|
|
Assert.True(tool.ProtocolTool.Meta.ContainsKey("nullable"));
|
|
Assert.Null(tool.ProtocolTool.Meta["nullable"]);
|
|
}
|
|
|
|
[Fact]
|
|
public void McpMetaAttribute_ClassLevelAttributesIgnored()
|
|
{
|
|
// Since McpMetaAttribute is only valid on methods, class-level attributes are not supported.
|
|
// This test simply validates method-level attributes still function as expected.
|
|
var method = typeof(TestToolMethodMetaOnlyClass).GetMethod(nameof(TestToolMethodMetaOnlyClass.ToolWithMethodMeta))!;
|
|
var tool = McpServerTool.Create(method, target: null);
|
|
Assert.NotNull(tool.ProtocolTool.Meta);
|
|
Assert.Equal("method", tool.ProtocolTool.Meta["methodKey"]?.ToString());
|
|
// Ensure only the method-level key exists
|
|
Assert.Single(tool.ProtocolTool.Meta!);
|
|
}
|
|
|
|
[Fact]
|
|
public void McpMetaAttribute_DelegateOverload_PopulatesMeta()
|
|
{
|
|
// Create tool using delegate overload instead of MethodInfo directly
|
|
var del = new Func<string, string>(TestToolClass.ToolWithMeta);
|
|
var tool = McpServerTool.Create(del);
|
|
Assert.NotNull(tool.ProtocolTool.Meta);
|
|
Assert.Equal("gpt-4o", tool.ProtocolTool.Meta!["model"]?.ToString());
|
|
Assert.Equal("1.0", tool.ProtocolTool.Meta["version"]?.ToString());
|
|
}
|
|
|
|
[Fact]
|
|
public void McpMetaAttribute_ComplexObject_SerializedAsJson()
|
|
{
|
|
var method = typeof(TestToolComplexMetaClass).GetMethod(nameof(TestToolComplexMetaClass.ToolWithComplexMeta))!;
|
|
var tool = McpServerTool.Create(method, target: null);
|
|
Assert.NotNull(tool.ProtocolTool.Meta);
|
|
|
|
var configNode = tool.ProtocolTool.Meta["config"];
|
|
Assert.NotNull(configNode);
|
|
Assert.Equal(JsonValueKind.Object, configNode.GetValueKind());
|
|
|
|
var configObj = configNode.AsObject();
|
|
Assert.Equal("high", configObj["relevance"]?.ToString());
|
|
Assert.Equal("noble", configObj["purpose"]?.ToString());
|
|
}
|
|
|
|
[Fact]
|
|
public void McpMetaAttribute_Array_SerializedAsJson()
|
|
{
|
|
var method = typeof(TestToolArrayMetaClass).GetMethod(nameof(TestToolArrayMetaClass.ToolWithArrayMeta))!;
|
|
var tool = McpServerTool.Create(method, target: null);
|
|
Assert.NotNull(tool.ProtocolTool.Meta);
|
|
|
|
var tagsNode = tool.ProtocolTool.Meta["tags"];
|
|
Assert.NotNull(tagsNode);
|
|
Assert.Equal(JsonValueKind.Array, tagsNode.GetValueKind());
|
|
|
|
var tagsArray = tagsNode.AsArray();
|
|
Assert.Equal(3, tagsArray.Count);
|
|
Assert.Equal("tag1", tagsArray[0]?.ToString());
|
|
Assert.Equal("tag2", tagsArray[1]?.ToString());
|
|
Assert.Equal("tag3", tagsArray[2]?.ToString());
|
|
}
|
|
|
|
[Fact]
|
|
public void McpMetaAttribute_JsonValueOverride_UsesProvidedJson()
|
|
{
|
|
var method = typeof(TestToolJsonValueOverrideClass).GetMethod(nameof(TestToolJsonValueOverrideClass.ToolWithJsonValueOverride))!;
|
|
var tool = McpServerTool.Create(method, target: null);
|
|
Assert.NotNull(tool.ProtocolTool.Meta);
|
|
|
|
var configNode = tool.ProtocolTool.Meta["config"];
|
|
Assert.NotNull(configNode);
|
|
Assert.Equal(JsonValueKind.Object, configNode.GetValueKind());
|
|
|
|
var configObj = configNode.AsObject();
|
|
Assert.Equal("custom", configObj["type"]?.ToString());
|
|
Assert.Equal("123", configObj["value"]?.ToString());
|
|
}
|
|
|
|
[Fact]
|
|
public void McpMetaAttribute_MixedTypes_AllSerializedCorrectly()
|
|
{
|
|
var method = typeof(TestToolMixedTypesClass).GetMethod(nameof(TestToolMixedTypesClass.ToolWithMixedTypes))!;
|
|
var tool = McpServerTool.Create(method, target: null);
|
|
Assert.NotNull(tool.ProtocolTool.Meta);
|
|
|
|
Assert.Equal("text", tool.ProtocolTool.Meta["stringValue"]?.ToString());
|
|
Assert.Equal(JsonValueKind.String, tool.ProtocolTool.Meta["stringValue"]?.GetValueKind());
|
|
|
|
Assert.Equal("42", tool.ProtocolTool.Meta["numberValue"]?.ToString());
|
|
Assert.Equal(JsonValueKind.Number, tool.ProtocolTool.Meta["numberValue"]?.GetValueKind());
|
|
|
|
Assert.Equal("true", tool.ProtocolTool.Meta["boolValue"]?.ToString());
|
|
Assert.Equal(JsonValueKind.True, tool.ProtocolTool.Meta["boolValue"]?.GetValueKind());
|
|
|
|
Assert.Null(tool.ProtocolTool.Meta["nullValue"]);
|
|
|
|
var objNode = tool.ProtocolTool.Meta["objectValue"];
|
|
Assert.NotNull(objNode);
|
|
Assert.Equal(JsonValueKind.Object, objNode.GetValueKind());
|
|
}
|
|
|
|
[Fact]
|
|
public void McpMetaAttribute_DoubleValue_SerializedAsNumber()
|
|
{
|
|
var method = typeof(TestToolDoubleMetaClass).GetMethod(nameof(TestToolDoubleMetaClass.ToolWithDoubleMeta))!;
|
|
var tool = McpServerTool.Create(method, target: null);
|
|
Assert.NotNull(tool.ProtocolTool.Meta);
|
|
|
|
var piNode = tool.ProtocolTool.Meta["pi"];
|
|
Assert.NotNull(piNode);
|
|
Assert.Equal(JsonValueKind.Number, piNode.GetValueKind());
|
|
var piValue = piNode.GetValue<double>();
|
|
Assert.True(Math.Abs(3.14159 - piValue) < 0.00001);
|
|
}
|
|
|
|
[Fact]
|
|
public void McpMetaAttribute_SupportedTypes_SerializedCorrectly()
|
|
{
|
|
var method = typeof(TestToolSupportedTypesClass).GetMethod(nameof(TestToolSupportedTypesClass.ToolWithSupportedTypes))!;
|
|
var tool = McpServerTool.Create(method, target: null);
|
|
Assert.NotNull(tool.ProtocolTool.Meta);
|
|
|
|
// string
|
|
Assert.Equal("hello world", tool.ProtocolTool.Meta["stringValue"]?.ToString());
|
|
Assert.Equal(JsonValueKind.String, tool.ProtocolTool.Meta["stringValue"]?.GetValueKind());
|
|
|
|
// double (positive)
|
|
Assert.Equal(JsonValueKind.Number, tool.ProtocolTool.Meta["doubleValue"]?.GetValueKind());
|
|
var doubleValue = tool.ProtocolTool.Meta["doubleValue"]?.GetValue<double>();
|
|
Assert.NotNull(doubleValue);
|
|
Assert.True(Math.Abs(2.71828 - doubleValue.Value) < 0.00001);
|
|
|
|
// double (negative)
|
|
Assert.Equal(JsonValueKind.Number, tool.ProtocolTool.Meta["negativeDouble"]?.GetValueKind());
|
|
Assert.Equal(-1.5, tool.ProtocolTool.Meta["negativeDouble"]?.GetValue<double>());
|
|
|
|
// double (zero)
|
|
Assert.Equal(JsonValueKind.Number, tool.ProtocolTool.Meta["zeroDouble"]?.GetValueKind());
|
|
Assert.Equal(0.0, tool.ProtocolTool.Meta["zeroDouble"]?.GetValue<double>());
|
|
|
|
// double (integer value)
|
|
Assert.Equal(JsonValueKind.Number, tool.ProtocolTool.Meta["intAsDouble"]?.GetValueKind());
|
|
Assert.Equal(42.0, tool.ProtocolTool.Meta["intAsDouble"]?.GetValue<double>());
|
|
|
|
// bool true
|
|
Assert.Equal("true", tool.ProtocolTool.Meta["boolTrueValue"]?.ToString());
|
|
Assert.Equal(JsonValueKind.True, tool.ProtocolTool.Meta["boolTrueValue"]?.GetValueKind());
|
|
|
|
// bool false
|
|
Assert.Equal("false", tool.ProtocolTool.Meta["boolFalseValue"]?.ToString());
|
|
Assert.Equal(JsonValueKind.False, tool.ProtocolTool.Meta["boolFalseValue"]?.GetValueKind());
|
|
}
|
|
|
|
[Fact]
|
|
public void McpMetaAttribute_StringEdgeCases_SerializedCorrectly()
|
|
{
|
|
var method = typeof(TestToolStringEdgeCasesClass).GetMethod(nameof(TestToolStringEdgeCasesClass.ToolWithStringEdgeCases))!;
|
|
var tool = McpServerTool.Create(method, target: null);
|
|
Assert.NotNull(tool.ProtocolTool.Meta);
|
|
|
|
// Empty string
|
|
Assert.Equal("", tool.ProtocolTool.Meta["emptyString"]?.ToString());
|
|
Assert.Equal(JsonValueKind.String, tool.ProtocolTool.Meta["emptyString"]?.GetValueKind());
|
|
|
|
// String with special characters
|
|
Assert.Equal("Line1\nLine2\tTabbed", tool.ProtocolTool.Meta["specialChars"]?.ToString());
|
|
|
|
// String with quotes
|
|
Assert.Equal("He said \"Hello\"", tool.ProtocolTool.Meta["withQuotes"]?.ToString());
|
|
|
|
// Unicode string
|
|
Assert.Equal("Hello 世界 🌍", tool.ProtocolTool.Meta["unicode"]?.ToString());
|
|
}
|
|
|
|
[Fact]
|
|
public void McpMetaAttribute_DoubleEdgeCases_SerializedCorrectly()
|
|
{
|
|
var method = typeof(TestToolDoubleEdgeCasesClass).GetMethod(nameof(TestToolDoubleEdgeCasesClass.ToolWithDoubleEdgeCases))!;
|
|
var tool = McpServerTool.Create(method, target: null);
|
|
Assert.NotNull(tool.ProtocolTool.Meta);
|
|
|
|
// Zero
|
|
Assert.Equal("0", tool.ProtocolTool.Meta["zero"]?.ToString());
|
|
Assert.Equal(JsonValueKind.Number, tool.ProtocolTool.Meta["zero"]?.GetValueKind());
|
|
|
|
// Negative value
|
|
Assert.Equal(JsonValueKind.Number, tool.ProtocolTool.Meta["negative"]?.GetValueKind());
|
|
Assert.Equal(-999.999, tool.ProtocolTool.Meta["negative"]?.GetValue<double>());
|
|
|
|
// Large positive value
|
|
Assert.Equal(JsonValueKind.Number, tool.ProtocolTool.Meta["largePositive"]?.GetValueKind());
|
|
Assert.Equal(1.7976931348623157E+308, tool.ProtocolTool.Meta["largePositive"]?.GetValue<double>());
|
|
|
|
// Small positive value
|
|
Assert.Equal(JsonValueKind.Number, tool.ProtocolTool.Meta["smallPositive"]?.GetValueKind());
|
|
var smallValue = tool.ProtocolTool.Meta["smallPositive"]?.GetValue<double>();
|
|
Assert.NotNull(smallValue);
|
|
Assert.True(Math.Abs(0.000001 - smallValue.Value) < 0.0000001);
|
|
}
|
|
|
|
[Fact]
|
|
public void McpMetaAttribute_JsonValueForComplexTypes_SerializedCorrectly()
|
|
{
|
|
var method = typeof(TestToolJsonValueComplexClass).GetMethod(nameof(TestToolJsonValueComplexClass.ToolWithComplexTypes))!;
|
|
var tool = McpServerTool.Create(method, target: null);
|
|
Assert.NotNull(tool.ProtocolTool.Meta);
|
|
|
|
// Integer via JsonValue
|
|
Assert.Equal("42", tool.ProtocolTool.Meta["intValue"]?.ToString());
|
|
Assert.Equal(JsonValueKind.Number, tool.ProtocolTool.Meta["intValue"]?.GetValueKind());
|
|
Assert.Equal(42, tool.ProtocolTool.Meta["intValue"]?.GetValue<int>());
|
|
|
|
// Array via JsonValue
|
|
var arrayNode = tool.ProtocolTool.Meta["arrayValue"];
|
|
Assert.NotNull(arrayNode);
|
|
Assert.Equal(JsonValueKind.Array, arrayNode.GetValueKind());
|
|
var array = arrayNode.AsArray();
|
|
Assert.Equal(3, array.Count);
|
|
Assert.Equal("a", array[0]?.ToString());
|
|
Assert.Equal("b", array[1]?.ToString());
|
|
Assert.Equal("c", array[2]?.ToString());
|
|
|
|
// Object via JsonValue
|
|
var objNode = tool.ProtocolTool.Meta["objectValue"];
|
|
Assert.NotNull(objNode);
|
|
Assert.Equal(JsonValueKind.Object, objNode.GetValueKind());
|
|
var obj = objNode.AsObject();
|
|
Assert.Equal("value", obj["key"]?.ToString());
|
|
Assert.Equal("123", obj["num"]?.ToString());
|
|
}
|
|
|
|
private class TestToolClass
|
|
{
|
|
[McpServerTool]
|
|
[McpMeta("model", "gpt-4o")]
|
|
[McpMeta("version", "1.0")]
|
|
public static string ToolWithMeta(string input)
|
|
{
|
|
return input;
|
|
}
|
|
|
|
[McpServerTool]
|
|
public static string ToolWithoutMeta(string input)
|
|
{
|
|
return input;
|
|
}
|
|
|
|
[McpServerTool]
|
|
[McpMeta("test-key", "test-value")]
|
|
public static string ToolWithSingleMeta(string input)
|
|
{
|
|
return input;
|
|
}
|
|
}
|
|
|
|
private class TestPromptClass
|
|
{
|
|
[McpServerPrompt]
|
|
[McpMeta("type", "reasoning")]
|
|
[McpMeta("model", "claude-3")]
|
|
public static string PromptWithMeta(string input)
|
|
{
|
|
return input;
|
|
}
|
|
}
|
|
|
|
private class TestResourceClass
|
|
{
|
|
[McpServerResource(UriTemplate = "resource://test/{id}")]
|
|
[McpMeta("encoding", "text/plain")]
|
|
[McpMeta("caching", "cached")]
|
|
public static string ResourceWithMeta(string id)
|
|
{
|
|
return $"Resource content for {id}";
|
|
}
|
|
}
|
|
|
|
private class TestResourceNoMetaClass
|
|
{
|
|
[McpServerResource(UriTemplate = "resource://test2/{id}")]
|
|
public static string ResourceWithoutMeta(string id) => id;
|
|
}
|
|
|
|
private class TestPromptNoMetaClass
|
|
{
|
|
[McpServerPrompt]
|
|
public static string PromptWithoutMeta(string input) => input;
|
|
}
|
|
|
|
private class TestToolDuplicateMetaClass
|
|
{
|
|
[McpServerTool]
|
|
[McpMeta("key", "first")]
|
|
[McpMeta("key", "second")]
|
|
[McpMeta("other", "other-value")]
|
|
public static string ToolWithDuplicateMeta(string input) => input;
|
|
}
|
|
|
|
private class TestToolNullMetaClass
|
|
{
|
|
[McpServerTool]
|
|
[McpMeta("nullable", null)]
|
|
public static string ToolWithNullMeta(string input) => input;
|
|
}
|
|
|
|
private class TestToolMethodMetaOnlyClass
|
|
{
|
|
[McpServerTool]
|
|
[McpMeta("methodKey", "method")]
|
|
public static string ToolWithMethodMeta(string input) => input;
|
|
}
|
|
|
|
private class TestToolComplexMetaClass
|
|
{
|
|
[McpServerTool]
|
|
[McpMeta("config", JsonValue = """{"relevance": "high", "purpose": "noble"}""")]
|
|
public static string ToolWithComplexMeta(string input) => input;
|
|
}
|
|
|
|
private class TestToolArrayMetaClass
|
|
{
|
|
[McpServerTool]
|
|
[McpMeta("tags", JsonValue = """["tag1", "tag2", "tag3"]""")]
|
|
public static string ToolWithArrayMeta(string input) => input;
|
|
}
|
|
|
|
private class TestToolJsonValueOverrideClass
|
|
{
|
|
[McpServerTool]
|
|
[McpMeta("config", JsonValue = """{"type": "custom", "value": 123}""")]
|
|
public static string ToolWithJsonValueOverride(string input) => input;
|
|
}
|
|
|
|
private class TestToolMixedTypesClass
|
|
{
|
|
[McpServerTool]
|
|
[McpMeta("stringValue", "text")]
|
|
[McpMeta("numberValue", 42.0)]
|
|
[McpMeta("boolValue", true)]
|
|
[McpMeta("nullValue", null)]
|
|
[McpMeta("objectValue", JsonValue = """{"key": "value"}""")]
|
|
public static string ToolWithMixedTypes(string input) => input;
|
|
}
|
|
|
|
private class TestToolDoubleMetaClass
|
|
{
|
|
[McpServerTool]
|
|
[McpMeta("pi", 3.14159)]
|
|
public static string ToolWithDoubleMeta(string input) => input;
|
|
}
|
|
|
|
private class TestToolSupportedTypesClass
|
|
{
|
|
[McpServerTool]
|
|
[McpMeta("stringValue", "hello world")]
|
|
[McpMeta("doubleValue", 2.71828)]
|
|
[McpMeta("negativeDouble", -1.5)]
|
|
[McpMeta("zeroDouble", 0.0)]
|
|
[McpMeta("intAsDouble", 42.0)]
|
|
[McpMeta("boolTrueValue", true)]
|
|
[McpMeta("boolFalseValue", false)]
|
|
public static string ToolWithSupportedTypes(string input) => input;
|
|
}
|
|
|
|
private class TestToolStringEdgeCasesClass
|
|
{
|
|
[McpServerTool]
|
|
[McpMeta("emptyString", "")]
|
|
[McpMeta("specialChars", "Line1\nLine2\tTabbed")]
|
|
[McpMeta("withQuotes", "He said \"Hello\"")]
|
|
[McpMeta("unicode", "Hello 世界 🌍")]
|
|
public static string ToolWithStringEdgeCases(string input) => input;
|
|
}
|
|
|
|
private class TestToolDoubleEdgeCasesClass
|
|
{
|
|
[McpServerTool]
|
|
[McpMeta("zero", 0.0)]
|
|
[McpMeta("negative", -999.999)]
|
|
[McpMeta("largePositive", double.MaxValue)]
|
|
[McpMeta("smallPositive", 0.000001)]
|
|
public static string ToolWithDoubleEdgeCases(string input) => input;
|
|
}
|
|
|
|
private class TestToolJsonValueComplexClass
|
|
{
|
|
[McpServerTool]
|
|
[McpMeta("intValue", JsonValue = "42")]
|
|
[McpMeta("arrayValue", JsonValue = """["a", "b", "c"]""")]
|
|
[McpMeta("objectValue", JsonValue = """{"key": "value", "num": 123}""")]
|
|
public static string ToolWithComplexTypes(string input) => input;
|
|
}
|
|
|
|
// Test classes for Meta Property Population Tests
|
|
private class TestToolStringMetaClass
|
|
{
|
|
[McpServerTool]
|
|
[McpMeta("key1", "value1")]
|
|
[McpMeta("key2", "value2")]
|
|
[McpMeta("key3", null)]
|
|
public static string ToolWithStringMeta(string input) => input;
|
|
}
|
|
|
|
private class TestToolDoubleMetaClass2
|
|
{
|
|
[McpServerTool]
|
|
[McpMeta("pi", 3.14)]
|
|
[McpMeta("zero", 0.0)]
|
|
[McpMeta("negative", -1.5)]
|
|
public static string ToolWithDoubleMeta(string input) => input;
|
|
}
|
|
|
|
private class TestToolBoolMetaClass
|
|
{
|
|
[McpServerTool]
|
|
[McpMeta("enabled", true)]
|
|
[McpMeta("deprecated", false)]
|
|
public static string ToolWithBoolMeta(string input) => input;
|
|
}
|
|
|
|
private class TestToolAllTypesMetaClass
|
|
{
|
|
[McpServerTool]
|
|
[McpMeta("stringKey", "test")]
|
|
[McpMeta("doubleKey", 42.5)]
|
|
[McpMeta("boolKey", true)]
|
|
[McpMeta("nullKey", null)]
|
|
public static string ToolWithAllTypes(string input) => input;
|
|
}
|
|
|
|
private class TestPromptStringMetaClass
|
|
{
|
|
[McpServerPrompt]
|
|
[McpMeta("role", "system")]
|
|
[McpMeta("type", "instruction")]
|
|
public static string PromptWithStringMeta(string input) => input;
|
|
}
|
|
|
|
private class TestPromptDoubleMetaClass
|
|
{
|
|
[McpServerPrompt]
|
|
[McpMeta("temperature", 0.7)]
|
|
[McpMeta("maxTokens", 100.0)]
|
|
public static string PromptWithDoubleMeta(string input) => input;
|
|
}
|
|
|
|
private class TestPromptBoolMetaClass
|
|
{
|
|
[McpServerPrompt]
|
|
[McpMeta("stream", true)]
|
|
public static string PromptWithBoolMeta(string input) => input;
|
|
}
|
|
|
|
private class TestPromptAllTypesMetaClass
|
|
{
|
|
[McpServerPrompt]
|
|
[McpMeta("role", "user")]
|
|
[McpMeta("version", 1.0)]
|
|
[McpMeta("experimental", false)]
|
|
[McpMeta("deprecated", null)]
|
|
public static string PromptWithAllTypes(string input) => input;
|
|
}
|
|
|
|
private class TestResourceStringMetaClass
|
|
{
|
|
[McpServerResource(UriTemplate = "resource://test/{id}")]
|
|
[McpMeta("contentType", "text/html")]
|
|
[McpMeta("encoding", "utf-8")]
|
|
public static string ResourceWithStringMeta(string id) => id;
|
|
}
|
|
|
|
private class TestResourceDoubleMetaClass
|
|
{
|
|
[McpServerResource(UriTemplate = "resource://test/{id}")]
|
|
[McpMeta("version", 1.5)]
|
|
[McpMeta("cacheDuration", 3600.0)]
|
|
public static string ResourceWithDoubleMeta(string id) => id;
|
|
}
|
|
|
|
private class TestResourceBoolMetaClass
|
|
{
|
|
[McpServerResource(UriTemplate = "resource://test/{id}")]
|
|
[McpMeta("cacheable", true)]
|
|
[McpMeta("requiresAuth", false)]
|
|
public static string ResourceWithBoolMeta(string id) => id;
|
|
}
|
|
|
|
private class TestResourceAllTypesMetaClass
|
|
{
|
|
[McpServerResource(UriTemplate = "resource://test/{id}")]
|
|
[McpMeta("visibility", "public")]
|
|
[McpMeta("apiVersion", 2.0)]
|
|
[McpMeta("available", true)]
|
|
[McpMeta("owner", null)]
|
|
public static string ResourceWithAllTypes(string id) => id;
|
|
}
|
|
|
|
private class TestToolJsonValueMetaClass
|
|
{
|
|
[McpServerTool]
|
|
[McpMeta("count", JsonValue = "42")]
|
|
[McpMeta("tags", JsonValue = """["tag1", "tag2", "tag3"]""")]
|
|
[McpMeta("config", JsonValue = """{"priority": "high"}""")]
|
|
public static string ToolWithJsonValueMeta(string input) => input;
|
|
}
|
|
|
|
private class TestPromptJsonValueMetaClass
|
|
{
|
|
[McpServerPrompt]
|
|
[McpMeta("parameters", JsonValue = """{"type": "string", "required": true}""")]
|
|
public static string PromptWithJsonValueMeta(string input) => input;
|
|
}
|
|
|
|
private class TestResourceJsonValueMetaClass
|
|
{
|
|
[McpServerResource(UriTemplate = "resource://test/{id}")]
|
|
[McpMeta("metadata", JsonValue = """{"type": "document"}""")]
|
|
[McpMeta("permissions", JsonValue = """["read", "write"]""")]
|
|
public static string ResourceWithJsonValueMeta(string id) => id;
|
|
}
|
|
}
|