|
|
@ -0,0 +1,73 @@
|
|
|
|
|
|
|
|
using System;
|
|
|
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
|
|
using System.Linq;
|
|
|
|
|
|
|
|
using System.Text;
|
|
|
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
using System.Text.Json;
|
|
|
|
|
|
|
|
using System.Net.Http;
|
|
|
|
|
|
|
|
using System.Net.Http.Json;
|
|
|
|
|
|
|
|
using System.Globalization;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace McpStudy.Core;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
[McpServerToolType]
|
|
|
|
|
|
|
|
public sealed class WeatherTools
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
[McpServerTool, Description("Get weather alerts for a US state.")]
|
|
|
|
|
|
|
|
public static async Task<string> GetAlerts(
|
|
|
|
|
|
|
|
HttpClient client,
|
|
|
|
|
|
|
|
[Description("The US state to get alerts for. Use the 2 letter abbreviation for the state (e.g. NY).")] string state)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
using var jsonDocument = await ReadJsonDocumentAsync(client,$"/alerts/active/area/{state}");
|
|
|
|
|
|
|
|
var jsonElement = jsonDocument.RootElement;
|
|
|
|
|
|
|
|
var alerts = jsonElement.GetProperty("features").EnumerateArray();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!alerts.Any())
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
return "No active alerts for this state.";
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return string.Join("\n--\n", alerts.Select(alert =>
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
JsonElement properties = alert.GetProperty("properties");
|
|
|
|
|
|
|
|
return $"""
|
|
|
|
|
|
|
|
Event: {properties.GetProperty("event").GetString()}
|
|
|
|
|
|
|
|
Area: {properties.GetProperty("areaDesc").GetString()}
|
|
|
|
|
|
|
|
Severity: {properties.GetProperty("severity").GetString()}
|
|
|
|
|
|
|
|
Description: {properties.GetProperty("description").GetString()}
|
|
|
|
|
|
|
|
Instruction: {properties.GetProperty("instruction").GetString()}
|
|
|
|
|
|
|
|
""";
|
|
|
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
[McpServerTool, Description("Get weather forecast for a location.")]
|
|
|
|
|
|
|
|
public static async Task<string> GetForecast(
|
|
|
|
|
|
|
|
HttpClient client,
|
|
|
|
|
|
|
|
[Description("Latitude of the location.")] double latitude,
|
|
|
|
|
|
|
|
[Description("Longitude of the location.")] double longitude)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
var pointUrl = string.Create(CultureInfo.InvariantCulture, $"/points/{latitude},{longitude}");
|
|
|
|
|
|
|
|
using var jsonDocument = await ReadJsonDocumentAsync(client,pointUrl);
|
|
|
|
|
|
|
|
var forecastUrl = jsonDocument.RootElement.GetProperty("properties").GetProperty("forecast").GetString()
|
|
|
|
|
|
|
|
?? throw new Exception($"No forecast URL provided by {client.BaseAddress}points/{latitude},{longitude}");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
using var forecastDocument = await ReadJsonDocumentAsync(client,forecastUrl);
|
|
|
|
|
|
|
|
var periods = forecastDocument.RootElement.GetProperty("properties").GetProperty("periods").EnumerateArray();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return string.Join("\n---\n", periods.Select(period => $"""
|
|
|
|
|
|
|
|
{period.GetProperty("name").GetString()}
|
|
|
|
|
|
|
|
Temperature: {period.GetProperty("temperature").GetInt32()}°F
|
|
|
|
|
|
|
|
Wind: {period.GetProperty("windSpeed").GetString()} {period.GetProperty("windDirection").GetString()}
|
|
|
|
|
|
|
|
Forecast: {period.GetProperty("detailedForecast").GetString()}
|
|
|
|
|
|
|
|
"""));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static async Task<JsonDocument> ReadJsonDocumentAsync(HttpClient client, string requestUri)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
using var response = await client.GetAsync(requestUri);
|
|
|
|
|
|
|
|
response.EnsureSuccessStatusCode();
|
|
|
|
|
|
|
|
return await JsonDocument.ParseAsync(await response.Content.ReadAsStreamAsync());
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|