Skip to content

Commit 494cfaa

Browse files
Merge pull request #104 from koic/add-ruby-weather-server
Add Ruby weather server example
2 parents c01abe0 + ff32b50 commit 494cfaa

File tree

4 files changed

+138
-0
lines changed

4 files changed

+138
-0
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ dist/
1010
wheels/
1111
*.egg-info
1212

13+
# Bundler-generated files
14+
Gemfile.lock
15+
1316
# Virtual environments
1417
.venv
1518

weather-server-ruby/Gemfile

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# frozen_string_literal: true
2+
3+
source "https://rubygems.org"
4+
5+
gem "mcp"

weather-server-ruby/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# A Simple MCP Weather Server written in Ruby
2+
3+
See the [Quickstart](https://modelcontextprotocol.io/quickstart) tutorial for more information.

weather-server-ruby/weather.rb

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
# frozen_string_literal: true
2+
3+
require "json"
4+
require "mcp"
5+
require "net/http"
6+
require "uri"
7+
8+
NWS_API_BASE = "https://api.weather.gov"
9+
USER_AGENT = "weather-app/1.0"
10+
11+
module HelperMethods
12+
def make_nws_request(url)
13+
uri = URI(url)
14+
request = Net::HTTP::Get.new(uri)
15+
request["User-Agent"] = USER_AGENT
16+
request["Accept"] = "application/geo+json"
17+
18+
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
19+
http.request(request)
20+
end
21+
22+
raise "HTTP #{response.code}: #{response.message}" unless response.is_a?(Net::HTTPSuccess)
23+
24+
JSON.parse(response.body)
25+
end
26+
27+
def format_alert(feature)
28+
properties = feature["properties"]
29+
30+
<<~ALERT
31+
Event: #{properties["event"] || "Unknown"}
32+
Area: #{properties["areaDesc"] || "Unknown"}
33+
Severity: #{properties["severity"] || "Unknown"}
34+
Description: #{properties["description"] || "No description available"}
35+
Instructions: #{properties["instruction"] || "No specific instructions provided"}
36+
ALERT
37+
end
38+
end
39+
40+
class GetAlerts < MCP::Tool
41+
extend HelperMethods
42+
43+
tool_name "get_alerts"
44+
description "Get weather alerts for a US state"
45+
input_schema(
46+
properties: {
47+
state: {
48+
type: "string",
49+
description: "Two-letter US state code (e.g. CA, NY)"
50+
}
51+
},
52+
required: ["state"]
53+
)
54+
55+
def self.call(state:)
56+
url = "#{NWS_API_BASE}/alerts/active/area/#{state.upcase}"
57+
data = make_nws_request(url)
58+
59+
if data["features"].empty?
60+
return MCP::Tool::Response.new([{
61+
type: "text",
62+
text: "No active alerts for this state."
63+
}])
64+
end
65+
66+
alerts = data["features"].map { |feature| format_alert(feature) }
67+
MCP::Tool::Response.new([{
68+
type: "text",
69+
text: alerts.join("\n---\n")
70+
}])
71+
end
72+
end
73+
74+
class GetForecast < MCP::Tool
75+
extend HelperMethods
76+
77+
tool_name "get_forecast"
78+
description "Get weather forecast for a location"
79+
input_schema(
80+
properties: {
81+
latitude: {
82+
type: "number",
83+
description: "Latitude of the location"
84+
},
85+
longitude: {
86+
type: "number",
87+
description: "Longitude of the location"
88+
}
89+
},
90+
required: ["latitude", "longitude"]
91+
)
92+
93+
def self.call(latitude:, longitude:)
94+
# First get the forecast grid endpoint.
95+
points_url = "#{NWS_API_BASE}/points/#{latitude},#{longitude}"
96+
points_data = make_nws_request(points_url)
97+
98+
# Get the forecast URL from the points response.
99+
forecast_url = points_data["properties"]["forecast"]
100+
forecast_data = make_nws_request(forecast_url)
101+
102+
# Format the periods into a readable forecast.
103+
periods = forecast_data["properties"]["periods"]
104+
forecasts = periods.first(5).map do |period|
105+
<<~FORECAST
106+
#{period["name"]}:
107+
Temperature: #{period["temperature"]}°#{period["temperatureUnit"]}
108+
Wind: #{period["windSpeed"]} #{period["windDirection"]}
109+
Forecast: #{period["detailedForecast"]}
110+
FORECAST
111+
end
112+
113+
MCP::Tool::Response.new([{
114+
type: "text",
115+
text: forecasts.join("\n---\n")
116+
}])
117+
end
118+
end
119+
120+
server = MCP::Server.new(
121+
name: "weather",
122+
version: "1.0.0",
123+
tools: [GetAlerts, GetForecast]
124+
)
125+
126+
transport = MCP::Server::Transports::StdioTransport.new(server)
127+
transport.open

0 commit comments

Comments
 (0)