-
Notifications
You must be signed in to change notification settings - Fork 725
Expand file tree
/
Copy pathMcpServerToolExternalDescriptionTests.cs
More file actions
149 lines (113 loc) · 5.88 KB
/
Copy pathMcpServerToolExternalDescriptionTests.cs
File metadata and controls
149 lines (113 loc) · 5.88 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
using ModelContextProtocol.Server;
using System.ComponentModel;
using System.Reflection;
using System.Resources;
namespace ModelContextProtocol.Tests.Server;
/// <summary>
/// Tests for the external description source feature on <see cref="McpServerToolAttribute"/>
/// (issue https://github.com/modelcontextprotocol/csharp-sdk/issues/1516).
/// </summary>
public class McpServerToolExternalDescriptionTests
{
[Fact]
public void ExternalDescription_StaticProperty_IsResolved()
{
MethodInfo method = typeof(McpServerToolExternalDescriptionTests)
.GetMethod(nameof(FromProperty), BindingFlags.NonPublic | BindingFlags.Static)!;
McpServerTool tool = McpServerTool.Create(method);
Assert.Equal("Resolved from static property.", tool.ProtocolTool.Description);
}
[Fact]
public void ExternalDescription_StaticField_IsResolved()
{
MethodInfo method = typeof(McpServerToolExternalDescriptionTests)
.GetMethod(nameof(FromField), BindingFlags.NonPublic | BindingFlags.Static)!;
McpServerTool tool = McpServerTool.Create(method);
Assert.Equal("Resolved from static field.", tool.ProtocolTool.Description);
}
[Fact]
public void ExternalDescription_StaticMethod_IsResolved()
{
MethodInfo method = typeof(McpServerToolExternalDescriptionTests)
.GetMethod(nameof(FromMethod), BindingFlags.NonPublic | BindingFlags.Static)!;
McpServerTool tool = McpServerTool.Create(method);
Assert.Equal("Resolved from static method.", tool.ProtocolTool.Description);
}
[Fact]
public void ExternalDescription_TakesPrecedenceOverDescriptionAttribute()
{
MethodInfo method = typeof(McpServerToolExternalDescriptionTests)
.GetMethod(nameof(OverridesDescriptionAttribute), BindingFlags.NonPublic | BindingFlags.Static)!;
McpServerTool tool = McpServerTool.Create(method);
Assert.Equal("Resolved from static property.", tool.ProtocolTool.Description);
}
[Fact]
public void ExternalDescription_MissingResource_FallsBackToDescriptionAttribute()
{
MethodInfo method = typeof(McpServerToolExternalDescriptionTests)
.GetMethod(nameof(MissingFallsBack), BindingFlags.NonPublic | BindingFlags.Static)!;
McpServerTool tool = McpServerTool.Create(method);
Assert.Equal("Fallback description.", tool.ProtocolTool.Description);
}
[Fact]
public void ExternalDescription_NameWithoutType_NoEffect()
{
MethodInfo method = typeof(McpServerToolExternalDescriptionTests)
.GetMethod(nameof(NameOnly), BindingFlags.NonPublic | BindingFlags.Static)!;
McpServerTool tool = McpServerTool.Create(method);
Assert.Equal("Plain description.", tool.ProtocolTool.Description);
}
[Fact]
public void ExternalDescription_ResourceManager_IsResolved()
{
MethodInfo method = typeof(McpServerToolExternalDescriptionTests)
.GetMethod(nameof(FromResourceManager), BindingFlags.NonPublic | BindingFlags.Static)!;
McpServerTool tool = McpServerTool.Create(method);
Assert.Equal("From resource manager.", tool.ProtocolTool.Description);
}
// ---- Inline "resource" type used by the resolver tests. ----
private static class ToolDescriptions
{
public static string PropertyDescription => "Resolved from static property.";
public static readonly string FieldDescription = "Resolved from static field.";
public static string MethodDescription() => "Resolved from static method.";
}
/// <summary>
/// Minimal in-memory <see cref="ResourceManager"/> used to verify the fallback path that resolves
/// descriptions through a static <c>ResourceManager</c> property.
/// </summary>
private sealed class InMemoryResourceManager : ResourceManager
{
private readonly Dictionary<string, string> _strings;
public InMemoryResourceManager(Dictionary<string, string> strings)
{
_strings = strings;
}
public override string? GetString(string name) => _strings.TryGetValue(name, out string? value) ? value : null;
public override string? GetString(string name, System.Globalization.CultureInfo? culture) => GetString(name);
}
private static class ResourceManagerHost
{
public static ResourceManager ResourceManager { get; } = new InMemoryResourceManager(new()
{
["WelcomeMessage"] = "From resource manager.",
});
}
[McpServerTool(DescriptionResourceType = typeof(ToolDescriptions), DescriptionResourceName = nameof(ToolDescriptions.PropertyDescription))]
private static string FromProperty() => "ok";
[McpServerTool(DescriptionResourceType = typeof(ToolDescriptions), DescriptionResourceName = nameof(ToolDescriptions.FieldDescription))]
private static string FromField() => "ok";
[McpServerTool(DescriptionResourceType = typeof(ToolDescriptions), DescriptionResourceName = nameof(ToolDescriptions.MethodDescription))]
private static string FromMethod() => "ok";
[McpServerTool(DescriptionResourceType = typeof(ToolDescriptions), DescriptionResourceName = nameof(ToolDescriptions.PropertyDescription))]
[Description("Compiled-in description that should be overridden.")]
private static string OverridesDescriptionAttribute() => "ok";
[McpServerTool(DescriptionResourceType = typeof(ToolDescriptions), DescriptionResourceName = "DoesNotExist")]
[Description("Fallback description.")]
private static string MissingFallsBack() => "ok";
[McpServerTool(DescriptionResourceName = nameof(ToolDescriptions.PropertyDescription))]
[Description("Plain description.")]
private static string NameOnly() => "ok";
[McpServerTool(DescriptionResourceType = typeof(ResourceManagerHost), DescriptionResourceName = "WelcomeMessage")]
private static string FromResourceManager() => "ok";
}