Add Description property to Implementation type per MCP spec (#966)
* Initial plan * Add Description property to Implementation type Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com> * Add test to validate client Description from server perspective 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
4b241e7ddc
commit
00bb5b2678
3 changed files with 46 additions and 0 deletions
|
|
@ -37,6 +37,22 @@ public sealed class Implementation : IBaseMetadata
|
||||||
[JsonPropertyName("version")]
|
[JsonPropertyName("version")]
|
||||||
public required string Version { get; set; }
|
public required string Version { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets an optional description of the implementation.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// <para>
|
||||||
|
/// This description helps users and developers understand what the implementation provides
|
||||||
|
/// and its purpose. It should clearly explain the functionality and capabilities offered.
|
||||||
|
/// </para>
|
||||||
|
/// <para>
|
||||||
|
/// The description is typically used in documentation, UI displays, and for providing context
|
||||||
|
/// to users about the server or client they are interacting with.
|
||||||
|
/// </para>
|
||||||
|
/// </remarks>
|
||||||
|
[JsonPropertyName("description")]
|
||||||
|
public string? Description { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets an optional list of icons for this implementation.
|
/// Gets or sets an optional list of icons for this implementation.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@ public class McpClientTests : ClientServerTestBase
|
||||||
{
|
{
|
||||||
Name = "test-server",
|
Name = "test-server",
|
||||||
Version = "1.0.0",
|
Version = "1.0.0",
|
||||||
|
Description = "A test server for unit testing",
|
||||||
WebsiteUrl = "https://example.com",
|
WebsiteUrl = "https://example.com",
|
||||||
Icons =
|
Icons =
|
||||||
[
|
[
|
||||||
|
|
@ -52,6 +53,7 @@ public class McpClientTests : ClientServerTestBase
|
||||||
var serverInfo = client.ServerInfo;
|
var serverInfo = client.ServerInfo;
|
||||||
Assert.Equal("test-server", serverInfo.Name);
|
Assert.Equal("test-server", serverInfo.Name);
|
||||||
Assert.Equal("1.0.0", serverInfo.Version);
|
Assert.Equal("1.0.0", serverInfo.Version);
|
||||||
|
Assert.Equal("A test server for unit testing", serverInfo.Description);
|
||||||
Assert.Equal("https://example.com", serverInfo.WebsiteUrl);
|
Assert.Equal("https://example.com", serverInfo.WebsiteUrl);
|
||||||
Assert.NotNull(serverInfo.Icons);
|
Assert.NotNull(serverInfo.Icons);
|
||||||
Assert.Equal(2, serverInfo.Icons.Count);
|
Assert.Equal(2, serverInfo.Icons.Count);
|
||||||
|
|
@ -69,6 +71,29 @@ public class McpClientTests : ClientServerTestBase
|
||||||
Assert.Equal("dark", icon1.Theme);
|
Assert.Equal("dark", icon1.Theme);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task ServerCanReadClientInfo()
|
||||||
|
{
|
||||||
|
var clientOptions = new McpClientOptions
|
||||||
|
{
|
||||||
|
ClientInfo = new Implementation
|
||||||
|
{
|
||||||
|
Name = "test-client",
|
||||||
|
Version = "2.0.0",
|
||||||
|
Description = "A test client for validating client-server communication"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
await using McpClient client = await CreateMcpClientForServer(clientOptions);
|
||||||
|
|
||||||
|
// Verify the server received the client info with description
|
||||||
|
var clientInfo = Server.ClientInfo;
|
||||||
|
Assert.NotNull(clientInfo);
|
||||||
|
Assert.Equal("test-client", clientInfo.Name);
|
||||||
|
Assert.Equal("2.0.0", clientInfo.Version);
|
||||||
|
Assert.Equal("A test client for validating client-server communication", clientInfo.Description);
|
||||||
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[InlineData(null, 10)]
|
[InlineData(null, 10)]
|
||||||
[InlineData(0.7f, 50)]
|
[InlineData(0.7f, 50)]
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ public static class ImplementationTests
|
||||||
Name = "test-server",
|
Name = "test-server",
|
||||||
Title = "Test MCP Server",
|
Title = "Test MCP Server",
|
||||||
Version = "1.0.0",
|
Version = "1.0.0",
|
||||||
|
Description = "A test MCP server implementation for demonstration purposes",
|
||||||
Icons =
|
Icons =
|
||||||
[
|
[
|
||||||
new() { Source = "https://example.com/icon.png", MimeType = "image/png", Sizes = ["48x48"] },
|
new() { Source = "https://example.com/icon.png", MimeType = "image/png", Sizes = ["48x48"] },
|
||||||
|
|
@ -33,6 +34,7 @@ public static class ImplementationTests
|
||||||
Assert.Equal(original.Name, deserialized.Name);
|
Assert.Equal(original.Name, deserialized.Name);
|
||||||
Assert.Equal(original.Title, deserialized.Title);
|
Assert.Equal(original.Title, deserialized.Title);
|
||||||
Assert.Equal(original.Version, deserialized.Version);
|
Assert.Equal(original.Version, deserialized.Version);
|
||||||
|
Assert.Equal(original.Description, deserialized.Description);
|
||||||
Assert.Equal(original.WebsiteUrl, deserialized.WebsiteUrl);
|
Assert.Equal(original.WebsiteUrl, deserialized.WebsiteUrl);
|
||||||
Assert.NotNull(deserialized.Icons);
|
Assert.NotNull(deserialized.Icons);
|
||||||
Assert.Equal(original.Icons.Count, deserialized.Icons.Count);
|
Assert.Equal(original.Icons.Count, deserialized.Icons.Count);
|
||||||
|
|
@ -66,6 +68,7 @@ public static class ImplementationTests
|
||||||
Assert.Equal(original.Name, deserialized.Name);
|
Assert.Equal(original.Name, deserialized.Name);
|
||||||
Assert.Equal(original.Title, deserialized.Title);
|
Assert.Equal(original.Title, deserialized.Title);
|
||||||
Assert.Equal(original.Version, deserialized.Version);
|
Assert.Equal(original.Version, deserialized.Version);
|
||||||
|
Assert.Equal(original.Description, deserialized.Description);
|
||||||
Assert.Equal(original.Icons, deserialized.Icons);
|
Assert.Equal(original.Icons, deserialized.Icons);
|
||||||
Assert.Equal(original.WebsiteUrl, deserialized.WebsiteUrl);
|
Assert.Equal(original.WebsiteUrl, deserialized.WebsiteUrl);
|
||||||
}
|
}
|
||||||
|
|
@ -78,6 +81,7 @@ public static class ImplementationTests
|
||||||
Name = "test-server",
|
Name = "test-server",
|
||||||
Title = "Test Server",
|
Title = "Test Server",
|
||||||
Version = "1.0.0",
|
Version = "1.0.0",
|
||||||
|
Description = "Test description",
|
||||||
Icons = [new() { Source = "https://example.com/icon.png" }],
|
Icons = [new() { Source = "https://example.com/icon.png" }],
|
||||||
WebsiteUrl = "https://example.com"
|
WebsiteUrl = "https://example.com"
|
||||||
};
|
};
|
||||||
|
|
@ -87,6 +91,7 @@ public static class ImplementationTests
|
||||||
Assert.Contains("\"name\":", json);
|
Assert.Contains("\"name\":", json);
|
||||||
Assert.Contains("\"title\":", json);
|
Assert.Contains("\"title\":", json);
|
||||||
Assert.Contains("\"version\":", json);
|
Assert.Contains("\"version\":", json);
|
||||||
|
Assert.Contains("\"description\":", json);
|
||||||
Assert.Contains("\"icons\":", json);
|
Assert.Contains("\"icons\":", json);
|
||||||
Assert.Contains("\"websiteUrl\":", json);
|
Assert.Contains("\"websiteUrl\":", json);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue