diff --git a/samples/AspNetCoreSseServer/Program.cs b/samples/AspNetCoreSseServer/Program.cs index f24b6a17..e7a83323 100644 --- a/samples/AspNetCoreSseServer/Program.cs +++ b/samples/AspNetCoreSseServer/Program.cs @@ -7,7 +7,8 @@ builder.Services.AddMcpServer() .WithHttpTransport() .WithTools() - .WithTools(); + .WithTools() + .WithTools(); builder.Services.AddOpenTelemetry() .WithTracing(b => b.AddSource("*") @@ -18,7 +19,7 @@ .AddHttpClientInstrumentation()) .WithLogging() .UseOtlpExporter(); - +builder.Services.AddHttpClient(); var app = builder.Build(); app.MapMcp(); diff --git a/samples/AspNetCoreSseServer/Tools/WeatherTools.cs b/samples/AspNetCoreSseServer/Tools/WeatherTools.cs new file mode 100644 index 00000000..6f2201e1 --- /dev/null +++ b/samples/AspNetCoreSseServer/Tools/WeatherTools.cs @@ -0,0 +1,55 @@ +using Microsoft.AspNetCore.Hosting.Server; +using Microsoft.Extensions.AI; +using Microsoft.Extensions.Configuration; +using ModelContextProtocol.Server; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Net.Http; +using System.Text.Json.Nodes; + +namespace TestServerWithHosting.Tools; + +[McpServerToolType] +public sealed class WeatherTools +{ + private readonly IHttpClientFactory _httpClientFactory; + + public WeatherTools(IHttpClientFactory httpClientFactory) + { + _httpClientFactory = httpClientFactory; + } + [McpServerTool(Name = "get_current_weather"), Description("returns the current weather given a town or region name")] + public async Task Get_Weather(IMcpServer mcpServer, [Description("The location (town or region) name")] string location) + { + try + { + var client = _httpClientFactory.CreateClient(); + var request = new HttpRequestMessage(HttpMethod.Get, $"https://nominatim.openstreetmap.org/search?format=json&q={location}"); + request.Headers.Add("User-Agent", "Test-MCP-Server"); + var ret = await client.SendAsync(request); + if (!ret.IsSuccessStatusCode) + { + return $"there was an error getting coordinates from location StatusCode: {ret.StatusCode} message: {await ret.Content.ReadAsStringAsync()}"; + } + var response = ret.Content.ReadAsStreamAsync(); + var locationInfo = JsonNode.Parse(await response) as JsonArray ?? new JsonArray(); + if (locationInfo == null || locationInfo.Count == 0) + { + return $"could not parse no result {response} into an json array or no results were found for location {location}"; + } + request = new HttpRequestMessage(HttpMethod.Get, $"https://api.open-meteo.com/v1/forecast?latitude={locationInfo.First()?["lat"]}&longitude={locationInfo.First()?["lon"]}9¤t_weather=true"); + request.Headers.Add("User-Agent", "Test-MCP-Server"); + ret = await client.SendAsync(request); + if (!ret.IsSuccessStatusCode) + { + return $"error getting coordinates from location StatusCode: {ret.StatusCode} message: {await ret.Content.ReadAsStringAsync()}"; + } + return await ret.Content.ReadAsStringAsync(); + } + catch (Exception ex) + { + return $"general error: {ex.ToString()}"; + } + } +} \ No newline at end of file diff --git a/samples/QuickstartClient/Program.cs b/samples/QuickstartClient/Program.cs index e3ee4fe8..8e633e3d 100644 --- a/samples/QuickstartClient/Program.cs +++ b/samples/QuickstartClient/Program.cs @@ -3,6 +3,9 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Hosting; using ModelContextProtocol.Client; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.Intrinsics.X86; +using System.Text; var builder = Host.CreateApplicationBuilder(args); @@ -11,15 +14,22 @@ .AddUserSecrets(); var (command, arguments) = GetCommandAndArguments(args); - -var clientTransport = new StdioClientTransport(new() +IClientTransport? clientTransport = null; +if (command == "http") { - Name = "Demo Server", - Command = command, - Arguments = arguments, -}); - -await using var mcpClient = await McpClientFactory.CreateAsync(clientTransport); + // make sure AspNetCoreSseServer is running + clientTransport = new SseClientTransport(new SseClientTransportOptions { Endpoint = new Uri("https://localhost:7133"), UseStreamableHttp = true }); +} +else +{ + clientTransport = new StdioClientTransport(new() + { + Name = "Demo Server", + Command = command, + Arguments = arguments, + }); +} +await using var mcpClient = await McpClientFactory.CreateAsync(clientTransport!); var tools = await mcpClient.ListToolsAsync(); foreach (var tool in tools) @@ -43,7 +53,7 @@ Console.ForegroundColor = ConsoleColor.Green; Console.WriteLine("MCP Client Started!"); Console.ResetColor(); - +var messages = new List(); PromptForInput(); while(Console.ReadLine() is string query && !"exit".Equals(query, StringComparison.OrdinalIgnoreCase)) { @@ -52,14 +62,18 @@ PromptForInput(); continue; } - - await foreach (var message in anthropicClient.GetStreamingResponseAsync(query, options)) + messages.Add(new ChatMessage(ChatRole.User, query)); + var sb = new StringBuilder(); + await foreach (var message in anthropicClient.GetStreamingResponseAsync(messages, options)) { Console.Write(message); + sb.AppendLine(message.ToString()); } + messages.Add(new ChatMessage(ChatRole.Assistant, sb.ToString())); Console.WriteLine(); PromptForInput(); + } static void PromptForInput() @@ -89,6 +103,8 @@ static void PromptForInput() [var script] when script.EndsWith(".py") => ("python", args), [var script] when script.EndsWith(".js") => ("node", args), [var script] when Directory.Exists(script) || (File.Exists(script) && script.EndsWith(".csproj")) => ("dotnet", ["run", "--project", script, "--no-build"]), + [var script] when script.Equals("http", StringComparison.OrdinalIgnoreCase) => ("http", args), _ => ("dotnet", ["run", "--project", "../../../../QuickstartWeatherServer", "--no-build"]) }; -} \ No newline at end of file +} + diff --git a/samples/QuickstartClient/Properties/launchSettings.json b/samples/QuickstartClient/Properties/launchSettings.json new file mode 100644 index 00000000..83f36695 --- /dev/null +++ b/samples/QuickstartClient/Properties/launchSettings.json @@ -0,0 +1,8 @@ +{ + "profiles": { + "QuickstartClient": { + "commandName": "Project", + "commandLineArgs": "http" + } + } +} \ No newline at end of file