using Microsoft.Extensions.DependencyInjection; using ModelContextProtocol.Client; using ModelContextProtocol.Extensions.Apps; using ModelContextProtocol.Protocol; using ModelContextProtocol.Server; using System.IO.Pipelines; Pipe clientToServerPipe = new(), serverToClientPipe = new(); var services = new ServiceCollection(); services.AddMcpServer() .WithStreamServerTransport(clientToServerPipe.Reader.AsStream(), serverToClientPipe.Writer.AsStream()) .WithTools() .WithMcpApps(); await using var serviceProvider = services.BuildServiceProvider(); var server = serviceProvider.GetRequiredService(); _ = server.RunAsync(); // Connect a client using a stream-based transport over the same in-memory pipe. await using McpClient client = await McpClient.CreateAsync( new StreamClientTransport(clientToServerPipe.Writer.AsStream(), serverToClientPipe.Reader.AsStream())); // List all tools. var tools = await client.ListToolsAsync(); var echo = tools.FirstOrDefault(t => t.Name == "Echo"); if (echo is null) { throw new Exception("Expected the Echo tool."); } var ui = echo.ProtocolTool.Meta?["ui"]?.AsObject(); if (ui?["resourceUri"]?.GetValue() != "ui://aot/echo") { throw new Exception($"Unexpected app UI metadata: {ui}"); } var result = await echo.InvokeAsync(new() { ["arg"] = "Hello World" }); if (result is null || !result.ToString()!.Contains("Echo: Hello World")) { throw new Exception($"Unexpected result: {result}"); } Console.WriteLine("Success!"); [McpServerToolType] internal sealed class AotTools { [McpServerTool(Name = "Echo")] [McpAppUi(ResourceUri = "ui://aot/echo")] public static string Echo(string arg) => $"Echo: {arg}"; }