Skip to content

Commit f37de15

Browse files
Add client-server integration tests for Icons and WebsiteUrl
Co-authored-by: MackinnonBuck <10456961+MackinnonBuck@users.noreply.github.com>
1 parent ae081ca commit f37de15

File tree

3 files changed

+160
-0
lines changed

3 files changed

+160
-0
lines changed

tests/ModelContextProtocol.Tests/Configuration/McpServerBuilderExtensionsPromptsTests.cs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,42 @@ public void Register_Prompts_From_Multiple_Sources()
315315
Assert.Contains(services.GetServices<McpServerPrompt>(), t => t.ProtocolPrompt.Name == "Returns42");
316316
}
317317

318+
[Fact]
319+
public async Task Can_Retrieve_Prompt_Icons()
320+
{
321+
// Create a server with a prompt that has icons
322+
var services = new ServiceCollection();
323+
var builder = services.AddMcpServer();
324+
325+
var promptWithIcons = McpServerPrompt.Create([McpServerPrompt(IconSource = "https://example.com/prompt-icon.svg")] () => "prompt content");
326+
builder.WithPrompts([promptWithIcons]);
327+
328+
await using var serviceProvider = services.BuildServiceProvider();
329+
var options = serviceProvider.GetRequiredService<IOptions<McpServerOptions>>().Value;
330+
var loggerFactory = serviceProvider.GetRequiredService<ILoggerFactory>();
331+
332+
var stdinPipe = new Pipe();
333+
var stdoutPipe = new Pipe();
334+
335+
await using var transport = new StreamServerTransport(stdinPipe.Reader.AsStream(), stdoutPipe.Writer.AsStream());
336+
await using var server = McpServer.Create(transport, options, loggerFactory, serviceProvider);
337+
var serverRunTask = server.RunAsync(TestContext.Current.CancellationToken);
338+
339+
await using var client = await McpClient.ConnectAsync(
340+
new StreamClientTransport(stdoutPipe.Reader.AsStream(), stdinPipe.Writer.AsStream()),
341+
new McpClientInfo { Name = "test-client", Version = "1.0.0" },
342+
cancellationToken: TestContext.Current.CancellationToken);
343+
344+
// List prompts and verify icons are present
345+
var prompts = await client.ListPromptsAsync(cancellationToken: TestContext.Current.CancellationToken);
346+
347+
var promptWithIconsResult = prompts.FirstOrDefault();
348+
Assert.NotNull(promptWithIconsResult);
349+
Assert.NotNull(promptWithIconsResult.Icons);
350+
Assert.Single(promptWithIconsResult.Icons);
351+
Assert.Equal("https://example.com/prompt-icon.svg", promptWithIconsResult.Icons[0].Source);
352+
}
353+
318354
[McpServerPromptType]
319355
public sealed class SimplePrompts(ObjectWithId? id = null)
320356
{

tests/ModelContextProtocol.Tests/Configuration/McpServerBuilderExtensionsResourcesTests.cs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,44 @@ public void Register_Resources_From_Multiple_Sources()
338338
Assert.Contains(services.GetServices<McpServerResource>(), t => t.ProtocolResourceTemplate.UriTemplate == "myResources:///returns42/{something}");
339339
}
340340

341+
[Fact]
342+
public async Task Can_Retrieve_Resource_Icons()
343+
{
344+
// Create a server with a resource that has icons
345+
var services = new ServiceCollection();
346+
var builder = services.AddMcpServer();
347+
348+
var resourceWithIcons = McpServerResource.Create(
349+
[McpServerResource(UriTemplate = "resource://test", IconSource = "https://example.com/resource-icon.png")]
350+
() => "resource content");
351+
builder.WithResources([resourceWithIcons]);
352+
353+
await using var serviceProvider = services.BuildServiceProvider();
354+
var options = serviceProvider.GetRequiredService<IOptions<McpServerOptions>>().Value;
355+
var loggerFactory = serviceProvider.GetRequiredService<ILoggerFactory>();
356+
357+
var stdinPipe = new Pipe();
358+
var stdoutPipe = new Pipe();
359+
360+
await using var transport = new StreamServerTransport(stdinPipe.Reader.AsStream(), stdoutPipe.Writer.AsStream());
361+
await using var server = McpServer.Create(transport, options, loggerFactory, serviceProvider);
362+
var serverRunTask = server.RunAsync(TestContext.Current.CancellationToken);
363+
364+
await using var client = await McpClient.ConnectAsync(
365+
new StreamClientTransport(stdoutPipe.Reader.AsStream(), stdinPipe.Writer.AsStream()),
366+
new McpClientInfo { Name = "test-client", Version = "1.0.0" },
367+
cancellationToken: TestContext.Current.CancellationToken);
368+
369+
// List resources and verify icons are present
370+
var resources = await client.ListResourcesAsync(cancellationToken: TestContext.Current.CancellationToken);
371+
372+
var resourceWithIconsResult = resources.FirstOrDefault();
373+
Assert.NotNull(resourceWithIconsResult);
374+
Assert.NotNull(resourceWithIconsResult.Icons);
375+
Assert.Single(resourceWithIconsResult.Icons);
376+
Assert.Equal("https://example.com/resource-icon.png", resourceWithIconsResult.Icons[0].Source);
377+
}
378+
341379
[McpServerResourceType]
342380
public sealed class SimpleResources
343381
{

tests/ModelContextProtocol.Tests/Configuration/McpServerBuilderExtensionsToolsTests.cs

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -727,6 +727,92 @@ await client.SendNotificationAsync(
727727
await Assert.ThrowsAnyAsync<OperationCanceledException>(async () => await invokeTask);
728728
}
729729

730+
[Fact]
731+
public async Task Can_Retrieve_Tool_Icons()
732+
{
733+
// Create a server with a tool that has icons
734+
var services = new ServiceCollection();
735+
var builder = services.AddMcpServer();
736+
737+
var toolWithIcons = McpServerTool.Create([McpServerTool(IconSource = "https://example.com/tool-icon.png")] () => "result");
738+
builder.WithTools([toolWithIcons]);
739+
740+
await using var serviceProvider = services.BuildServiceProvider();
741+
var options = serviceProvider.GetRequiredService<IOptions<McpServerOptions>>().Value;
742+
var loggerFactory = serviceProvider.GetRequiredService<ILoggerFactory>();
743+
744+
var stdinPipe = new Pipe();
745+
var stdoutPipe = new Pipe();
746+
747+
await using var transport = new StreamServerTransport(stdinPipe.Reader.AsStream(), stdoutPipe.Writer.AsStream());
748+
await using var server = McpServer.Create(transport, options, loggerFactory, serviceProvider);
749+
var serverRunTask = server.RunAsync(TestContext.Current.CancellationToken);
750+
751+
await using var client = await McpClient.ConnectAsync(
752+
new StreamClientTransport(stdoutPipe.Reader.AsStream(), stdinPipe.Writer.AsStream()),
753+
new McpClientInfo { Name = "test-client", Version = "1.0.0" },
754+
cancellationToken: TestContext.Current.CancellationToken);
755+
756+
// List tools and verify icons are present
757+
var tools = await client.ListToolsAsync(cancellationToken: TestContext.Current.CancellationToken);
758+
759+
var toolWithIconsResult = tools.FirstOrDefault();
760+
Assert.NotNull(toolWithIconsResult);
761+
Assert.NotNull(toolWithIconsResult.Icons);
762+
Assert.Single(toolWithIconsResult.Icons);
763+
Assert.Equal("https://example.com/tool-icon.png", toolWithIconsResult.Icons[0].Source);
764+
}
765+
766+
[Fact]
767+
public async Task Can_Retrieve_Implementation_Icons_And_WebsiteUrl()
768+
{
769+
// Create a server with implementation icons and website URL
770+
var services = new ServiceCollection();
771+
var builder = services.AddMcpServer(options =>
772+
{
773+
options.ServerInfo = new Implementation
774+
{
775+
Name = "test-server",
776+
Version = "1.0.0",
777+
Icons = new List<Icon>
778+
{
779+
new() { Source = "https://example.com/server-icon.png", MimeType = "image/png", Sizes = new List<string> { "64x64" } }
780+
},
781+
WebsiteUrl = "https://example.com/docs"
782+
};
783+
});
784+
785+
await using var serviceProvider = services.BuildServiceProvider();
786+
var options = serviceProvider.GetRequiredService<IOptions<McpServerOptions>>().Value;
787+
var loggerFactory = serviceProvider.GetRequiredService<ILoggerFactory>();
788+
789+
var stdinPipe = new Pipe();
790+
var stdoutPipe = new Pipe();
791+
792+
await using var transport = new StreamServerTransport(stdinPipe.Reader.AsStream(), stdoutPipe.Writer.AsStream());
793+
await using var server = McpServer.Create(transport, options, loggerFactory, serviceProvider);
794+
var serverRunTask = server.RunAsync(TestContext.Current.CancellationToken);
795+
796+
await using var client = await McpClient.ConnectAsync(
797+
new StreamClientTransport(stdoutPipe.Reader.AsStream(), stdinPipe.Writer.AsStream()),
798+
new McpClientInfo { Name = "test-client", Version = "1.0.0" },
799+
cancellationToken: TestContext.Current.CancellationToken);
800+
801+
// Verify server info contains icons and website URL
802+
var serverInfo = client.ServerInfo;
803+
Assert.NotNull(serverInfo);
804+
Assert.Equal("test-server", serverInfo.Name);
805+
Assert.Equal("1.0.0", serverInfo.Version);
806+
Assert.NotNull(serverInfo.Icons);
807+
Assert.Single(serverInfo.Icons);
808+
Assert.Equal("https://example.com/server-icon.png", serverInfo.Icons[0].Source);
809+
Assert.Equal("image/png", serverInfo.Icons[0].MimeType);
810+
Assert.NotNull(serverInfo.Icons[0].Sizes);
811+
Assert.Single(serverInfo.Icons[0].Sizes);
812+
Assert.Equal("64x64", serverInfo.Icons[0].Sizes[0]);
813+
Assert.Equal("https://example.com/docs", serverInfo.WebsiteUrl);
814+
}
815+
730816
[McpServerToolType]
731817
public sealed class EchoTool(ObjectWithId objectFromDI)
732818
{

0 commit comments

Comments
 (0)