Merge pull request #104 from koic/add-ruby-weather-server

Add Ruby weather server example
This commit is contained in:
Jonathan Hefner 2026-03-11 17:58:10 -05:00 • committed by GitHub
commit 494cfaa301
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 138 additions and 0 deletions

3
.gitignore vendored
View file

@ -10,6 +10,9 @@ dist/
wheels/
*.egg-info
# Bundler-generated files
Gemfile.lock
# Virtual environments
.venv

View file

@ -0,0 +1,5 @@
# frozen_string_literal: true
source "https://rubygems.org"
gem "mcp"

View file

@ -0,0 +1,3 @@
# A Simple MCP Weather Server written in Ruby
See the [Quickstart](https://modelcontextprotocol.io/quickstart) tutorial for more information.

View file

@ -0,0 +1,127 @@
# frozen_string_literal: true
require "json"
require "mcp"
require "net/http"
require "uri"
NWS_API_BASE = "https://api.weather.gov"
USER_AGENT = "weather-app/1.0"
module HelperMethods
def make_nws_request(url)
uri = URI(url)
request = Net::HTTP::Get.new(uri)
request["User-Agent"] = USER_AGENT
request["Accept"] = "application/geo+json"
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(request)
end
raise "HTTP #{response.code}: #{response.message}" unless response.is_a?(Net::HTTPSuccess)
JSON.parse(response.body)
end
def format_alert(feature)
properties = feature["properties"]
<<~ALERT
Event: #{properties["event"] || "Unknown"}
Area: #{properties["areaDesc"] || "Unknown"}
Severity: #{properties["severity"] || "Unknown"}
Description: #{properties["description"] || "No description available"}
Instructions: #{properties["instruction"] || "No specific instructions provided"}
ALERT
end
end
class GetAlerts < MCP::Tool
extend HelperMethods
tool_name "get_alerts"
description "Get weather alerts for a US state"
input_schema(
properties: {
state: {
type: "string",
description: "Two-letter US state code (e.g. CA, NY)"
}
},
required: ["state"]
)
def self.call(state:)
url = "#{NWS_API_BASE}/alerts/active/area/#{state.upcase}"
data = make_nws_request(url)
if data["features"].empty?
return MCP::Tool::Response.new([{
type: "text",
text: "No active alerts for this state."
}])
end
alerts = data["features"].map { |feature| format_alert(feature) }
MCP::Tool::Response.new([{
type: "text",
text: alerts.join("\n---\n")
}])
end
end
class GetForecast < MCP::Tool
extend HelperMethods
tool_name "get_forecast"
description "Get weather forecast for a location"
input_schema(
properties: {
latitude: {
type: "number",
description: "Latitude of the location"
},
longitude: {
type: "number",
description: "Longitude of the location"
}
},
required: ["latitude", "longitude"]
)
def self.call(latitude:, longitude:)
# First get the forecast grid endpoint.
points_url = "#{NWS_API_BASE}/points/#{latitude},#{longitude}"
points_data = make_nws_request(points_url)
# Get the forecast URL from the points response.
forecast_url = points_data["properties"]["forecast"]
forecast_data = make_nws_request(forecast_url)
# Format the periods into a readable forecast.
periods = forecast_data["properties"]["periods"]
forecasts = periods.first(5).map do |period|
<<~FORECAST
#{period["name"]}:
Temperature: #{period["temperature"]}°#{period["temperatureUnit"]}
Wind: #{period["windSpeed"]} #{period["windDirection"]}
Forecast: #{period["detailedForecast"]}
FORECAST
end
MCP::Tool::Response.new([{
type: "text",
text: forecasts.join("\n---\n")
}])
end
end
server = MCP::Server.new(
name: "weather",
version: "1.0.0",
tools: [GetAlerts, GetForecast]
)
transport = MCP::Server::Transports::StdioTransport.new(server)
transport.open