rubygems_mcp 0.1.3 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +7 -0
- data/README.md +22 -2
- data/lib/rubygems_mcp/client.rb +153 -1
- data/lib/rubygems_mcp/server.rb +88 -62
- data/lib/rubygems_mcp/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a1d6300f5e71b96d4ef7df1909e03c52555440cf794bc8afb46f5b1e6f75310e
|
|
4
|
+
data.tar.gz: 1727f6cbf963a35862eec6557da0d7008ea6fac4714614d2305aca1aec93a24c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b4e6bf57c3302cac5c5c74e99b0060e12b192befec7d7007c36e81d41dd45f2892f12eb73e315a7502c29686ef38abbd0f652012ee9e310ca38eb96729590182
|
|
7
|
+
data.tar.gz: a756f8c5da8e2a7d36e4c9e1c07427a102e9ca97fae9ba895ff41ecfa37c4449d14c26e6991b656b74686cfa36ad9bfcfa42145136f9cd2ab72fb40d505ad614
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# CHANGELOG
|
|
2
2
|
|
|
3
|
+
## 0.1.4 (2025-11-26)
|
|
4
|
+
|
|
5
|
+
- Add `get_news_releases` tool to fetch all new gem releases from RubyGems.org with pagination (fetches from `/news?page=N`)
|
|
6
|
+
- Add `get_popular_releases` tool to fetch popular new gem releases from RubyGems.org with pagination (fetches from `/releases/popular?page=N`)
|
|
7
|
+
- Add pagination support for `search_gems` tool via `page` parameter (converts page to offset automatically)
|
|
8
|
+
- Remove old patch code: unused monkey patches for fast-mcp `send_error`
|
|
9
|
+
|
|
3
10
|
## 0.1.3 (2025-11-21)
|
|
4
11
|
|
|
5
12
|
- Add Ruby roadmap tools: `get_ruby_roadmap` and `get_ruby_version_roadmap_details` for accessing Ruby version planning information from bugs.ruby-lang.org
|
data/README.md
CHANGED
|
@@ -30,12 +30,18 @@ For Cursor IDE, create or update `.cursor/mcp.json` in your project:
|
|
|
30
30
|
{
|
|
31
31
|
"mcpServers": {
|
|
32
32
|
"rubygems": {
|
|
33
|
-
"command": "
|
|
33
|
+
"command": "gem",
|
|
34
|
+
"args": ["exec", "rubygems_mcp"],
|
|
35
|
+
"env": {
|
|
36
|
+
"RUBY_VERSION": "3.4.7"
|
|
37
|
+
}
|
|
34
38
|
}
|
|
35
39
|
}
|
|
36
40
|
}
|
|
37
41
|
```
|
|
38
42
|
|
|
43
|
+
**Note**: Using `gem exec` ensures the correct Ruby version is used. If you're using a Ruby version manager like [mise](https://mise.jdx.dev/) or [rbenv](https://github.com/rbenv/rbenv), set the `RUBY_VERSION` environment variable to match your desired Ruby version. The `gem exec` command will automatically use the correct Ruby version based on your version manager configuration.
|
|
44
|
+
|
|
39
45
|
### Claude Desktop Configuration
|
|
40
46
|
|
|
41
47
|
For Claude Desktop, edit the MCP configuration file:
|
|
@@ -47,7 +53,11 @@ For Claude Desktop, edit the MCP configuration file:
|
|
|
47
53
|
{
|
|
48
54
|
"mcpServers": {
|
|
49
55
|
"rubygems": {
|
|
50
|
-
"command": "
|
|
56
|
+
"command": "gem",
|
|
57
|
+
"args": ["exec", "rubygems_mcp"],
|
|
58
|
+
"env": {
|
|
59
|
+
"RUBY_VERSION": "3.4.7"
|
|
60
|
+
}
|
|
51
61
|
}
|
|
52
62
|
}
|
|
53
63
|
}
|
|
@@ -214,6 +224,8 @@ recently_updated = client.get_recently_updated_gems(limit: 10)
|
|
|
214
224
|
|
|
215
225
|
- `get_latest_gems(limit: 30)` - Get latest gems - most recently added gems to RubyGems.org
|
|
216
226
|
- `get_recently_updated_gems(limit: 30)` - Get recently updated gems - most recently updated gem versions
|
|
227
|
+
- `get_news_releases(page: 1)` - Get news releases - all new gem releases from RubyGems.org with pagination (fetches from `/news?page=N`)
|
|
228
|
+
- `get_popular_releases(page: 1)` - Get popular releases - popular new gem releases from RubyGems.org with pagination (fetches from `/releases/popular?page=N`)
|
|
217
229
|
|
|
218
230
|
## MCP Server Integration
|
|
219
231
|
|
|
@@ -285,6 +297,14 @@ The MCP server provides the following tools:
|
|
|
285
297
|
16. **get_ruby_version_github_changelog** - Get GitHub release changelog for a Ruby version from the ruby/ruby repository
|
|
286
298
|
- Parameters: `version` (string, e.g., "3.4.7", "3.4.0")
|
|
287
299
|
|
|
300
|
+
17. **get_news_releases** - Get news releases - all new gem releases from RubyGems.org with pagination
|
|
301
|
+
- Parameters: `page` (optional integer, default: 1) - Page number (1-based)
|
|
302
|
+
- Fetches from: `https://rubygems.org/news?page=N`
|
|
303
|
+
|
|
304
|
+
18. **get_popular_releases** - Get popular releases - popular new gem releases from RubyGems.org with pagination
|
|
305
|
+
- Parameters: `page` (optional integer, default: 1) - Page number (1-based)
|
|
306
|
+
- Fetches from: `https://rubygems.org/releases/popular?page=N`
|
|
307
|
+
|
|
288
308
|
## MCP Resources
|
|
289
309
|
|
|
290
310
|
The MCP server provides the following resources:
|
data/lib/rubygems_mcp/client.rb
CHANGED
|
@@ -23,6 +23,7 @@ module RubygemsMcp
|
|
|
23
23
|
|
|
24
24
|
RUBYGEMS_API_BASE = "https://rubygems.org/api/v1"
|
|
25
25
|
RUBYGEMS_API_V2_BASE = "https://rubygems.org/api/v2"
|
|
26
|
+
RUBYGEMS_BASE = "https://rubygems.org"
|
|
26
27
|
RUBY_RELEASES_URL = "https://www.ruby-lang.org/en/downloads/releases/"
|
|
27
28
|
RUBY_BRANCHES_URL = "https://www.ruby-lang.org/en/downloads/branches/"
|
|
28
29
|
RUBY_ROADMAP_URL = "https://bugs.ruby-lang.org/projects/ruby-master/roadmap"
|
|
@@ -1061,9 +1062,17 @@ module RubygemsMcp
|
|
|
1061
1062
|
# @param query [String] Search query
|
|
1062
1063
|
# @param limit [Integer, nil] Maximum number of results to return (nil = all)
|
|
1063
1064
|
# @param offset [Integer] Number of results to skip (for pagination)
|
|
1065
|
+
# @param page [Integer, nil] Page number (1-based). If provided, overrides offset (page 1 = offset 0, page 2 = offset 30, etc.)
|
|
1064
1066
|
# @return [Array<Hash>] Array of hashes with gem information
|
|
1065
|
-
def search_gems(query, limit: nil, offset: 0)
|
|
1067
|
+
def search_gems(query, limit: nil, offset: 0, page: nil)
|
|
1066
1068
|
raise ValidationError, "Search query cannot be empty" if query.nil? || query.strip.empty?
|
|
1069
|
+
|
|
1070
|
+
# Convert page to offset if provided (assuming 30 items per page, which is RubyGems default)
|
|
1071
|
+
if page
|
|
1072
|
+
raise ValidationError, "Page must be positive" if page < 1
|
|
1073
|
+
offset = (page - 1) * 30
|
|
1074
|
+
end
|
|
1075
|
+
|
|
1067
1076
|
validate_pagination_params(limit: limit, offset: offset)
|
|
1068
1077
|
# Don't cache search results as they can change frequently
|
|
1069
1078
|
uri = URI("#{RUBYGEMS_API_BASE}/search.json")
|
|
@@ -1089,6 +1098,149 @@ module RubygemsMcp
|
|
|
1089
1098
|
results
|
|
1090
1099
|
end
|
|
1091
1100
|
|
|
1101
|
+
# Get news releases (all new gem releases) with pagination
|
|
1102
|
+
#
|
|
1103
|
+
# @param page [Integer] Page number (1-based, default: 1)
|
|
1104
|
+
# @return [Array<Hash>] Array of hashes with gem release information
|
|
1105
|
+
def get_news_releases(page: 1)
|
|
1106
|
+
raise ValidationError, "Page must be positive" if page < 1
|
|
1107
|
+
cache_key = "news_releases:#{page}"
|
|
1108
|
+
|
|
1109
|
+
if @cache_enabled
|
|
1110
|
+
cached = self.class.cache.get(cache_key)
|
|
1111
|
+
return cached if cached
|
|
1112
|
+
end
|
|
1113
|
+
|
|
1114
|
+
uri = URI("#{RUBYGEMS_BASE}/news")
|
|
1115
|
+
uri.query = URI.encode_www_form(page: page) if page > 1
|
|
1116
|
+
|
|
1117
|
+
response = make_request(uri, parse_html: true)
|
|
1118
|
+
return [] unless response
|
|
1119
|
+
|
|
1120
|
+
releases = []
|
|
1121
|
+
# RubyGems news page structure: each gem release is in a list item or similar structure
|
|
1122
|
+
# Look for gem links and extract information
|
|
1123
|
+
response.css("a[href^='/gems/']").each do |link|
|
|
1124
|
+
gem_name = link["href"].match(%r{/gems/([^/]+)})&.[](1)
|
|
1125
|
+
next unless gem_name
|
|
1126
|
+
|
|
1127
|
+
# Find the parent container to extract version and date
|
|
1128
|
+
container = link.ancestors.find { |e| e.name == "li" || e.name == "div" || e.name == "article" }
|
|
1129
|
+
next unless container
|
|
1130
|
+
|
|
1131
|
+
# Extract version from link text or nearby text
|
|
1132
|
+
version_match = link.text.match(/v?(\d+\.\d+\.\d+)/)
|
|
1133
|
+
version = version_match ? version_match[1] : nil
|
|
1134
|
+
|
|
1135
|
+
# Extract date (look for date patterns in nearby text)
|
|
1136
|
+
date_text = container.text
|
|
1137
|
+
date_match = date_text.match(/(\w+ \d{1,2}, \d{4})|(\d{4}-\d{2}-\d{2})/)
|
|
1138
|
+
release_date = if date_match
|
|
1139
|
+
begin
|
|
1140
|
+
Date.parse(date_match[0]).iso8601
|
|
1141
|
+
rescue Date::Error
|
|
1142
|
+
nil
|
|
1143
|
+
end
|
|
1144
|
+
end
|
|
1145
|
+
|
|
1146
|
+
# Extract downloads count if available
|
|
1147
|
+
downloads_match = container.text.match(/([\d,]+)\s*Downloads?/i)
|
|
1148
|
+
downloads = downloads_match ? downloads_match[1].delete(",").to_i : nil
|
|
1149
|
+
|
|
1150
|
+
# Extract description/info
|
|
1151
|
+
info_elem = container.css("p, .info, .description").first
|
|
1152
|
+
info = info_elem&.text&.strip
|
|
1153
|
+
|
|
1154
|
+
# Avoid duplicates
|
|
1155
|
+
next if releases.any? { |r| r[:name] == gem_name && r[:version] == version }
|
|
1156
|
+
|
|
1157
|
+
releases << {
|
|
1158
|
+
name: gem_name,
|
|
1159
|
+
version: version,
|
|
1160
|
+
release_date: release_date,
|
|
1161
|
+
downloads: downloads,
|
|
1162
|
+
info: info,
|
|
1163
|
+
gem_url: "#{RUBYGEMS_BASE}/gems/#{gem_name}"
|
|
1164
|
+
}
|
|
1165
|
+
end
|
|
1166
|
+
|
|
1167
|
+
# Cache for 15 minutes (news changes frequently)
|
|
1168
|
+
self.class.cache.set(cache_key, releases, 900) if @cache_enabled
|
|
1169
|
+
|
|
1170
|
+
releases
|
|
1171
|
+
end
|
|
1172
|
+
|
|
1173
|
+
# Get popular releases (popular new gem releases) with pagination
|
|
1174
|
+
#
|
|
1175
|
+
# @param page [Integer] Page number (1-based, default: 1)
|
|
1176
|
+
# @return [Array<Hash>] Array of hashes with popular gem release information
|
|
1177
|
+
def get_popular_releases(page: 1)
|
|
1178
|
+
raise ValidationError, "Page must be positive" if page < 1
|
|
1179
|
+
cache_key = "popular_releases:#{page}"
|
|
1180
|
+
|
|
1181
|
+
if @cache_enabled
|
|
1182
|
+
cached = self.class.cache.get(cache_key)
|
|
1183
|
+
return cached if cached
|
|
1184
|
+
end
|
|
1185
|
+
|
|
1186
|
+
uri = URI("#{RUBYGEMS_BASE}/releases/popular")
|
|
1187
|
+
uri.query = URI.encode_www_form(page: page) if page > 1
|
|
1188
|
+
|
|
1189
|
+
response = make_request(uri, parse_html: true)
|
|
1190
|
+
return [] unless response
|
|
1191
|
+
|
|
1192
|
+
releases = []
|
|
1193
|
+
# RubyGems popular releases page structure: similar to news page
|
|
1194
|
+
response.css("a[href^='/gems/']").each do |link|
|
|
1195
|
+
gem_name = link["href"].match(%r{/gems/([^/]+)})&.[](1)
|
|
1196
|
+
next unless gem_name
|
|
1197
|
+
|
|
1198
|
+
# Find the parent container to extract version and date
|
|
1199
|
+
container = link.ancestors.find { |e| e.name == "li" || e.name == "div" || e.name == "article" }
|
|
1200
|
+
next unless container
|
|
1201
|
+
|
|
1202
|
+
# Extract version from link text or nearby text
|
|
1203
|
+
version_match = link.text.match(/v?(\d+\.\d+\.\d+)/)
|
|
1204
|
+
version = version_match ? version_match[1] : nil
|
|
1205
|
+
|
|
1206
|
+
# Extract date (look for date patterns in nearby text)
|
|
1207
|
+
date_text = container.text
|
|
1208
|
+
date_match = date_text.match(/(\w+ \d{1,2}, \d{4})|(\d{4}-\d{2}-\d{2})/)
|
|
1209
|
+
release_date = if date_match
|
|
1210
|
+
begin
|
|
1211
|
+
Date.parse(date_match[0]).iso8601
|
|
1212
|
+
rescue Date::Error
|
|
1213
|
+
nil
|
|
1214
|
+
end
|
|
1215
|
+
end
|
|
1216
|
+
|
|
1217
|
+
# Extract downloads count if available
|
|
1218
|
+
downloads_match = container.text.match(/([\d,]+)\s*Downloads?/i)
|
|
1219
|
+
downloads = downloads_match ? downloads_match[1].delete(",").to_i : nil
|
|
1220
|
+
|
|
1221
|
+
# Extract description/info
|
|
1222
|
+
info_elem = container.css("p, .info, .description").first
|
|
1223
|
+
info = info_elem&.text&.strip
|
|
1224
|
+
|
|
1225
|
+
# Avoid duplicates
|
|
1226
|
+
next if releases.any? { |r| r[:name] == gem_name && r[:version] == version }
|
|
1227
|
+
|
|
1228
|
+
releases << {
|
|
1229
|
+
name: gem_name,
|
|
1230
|
+
version: version,
|
|
1231
|
+
release_date: release_date,
|
|
1232
|
+
downloads: downloads,
|
|
1233
|
+
info: info,
|
|
1234
|
+
gem_url: "#{RUBYGEMS_BASE}/gems/#{gem_name}"
|
|
1235
|
+
}
|
|
1236
|
+
end
|
|
1237
|
+
|
|
1238
|
+
# Cache for 15 minutes (popular releases change frequently)
|
|
1239
|
+
self.class.cache.set(cache_key, releases, 900) if @cache_enabled
|
|
1240
|
+
|
|
1241
|
+
releases
|
|
1242
|
+
end
|
|
1243
|
+
|
|
1092
1244
|
# Validate gem name
|
|
1093
1245
|
#
|
|
1094
1246
|
# @param gem_name [String] Gem name to validate
|
data/lib/rubygems_mcp/server.rb
CHANGED
|
@@ -10,39 +10,6 @@ require "securerandom"
|
|
|
10
10
|
# Alias MCP to FastMcp for compatibility
|
|
11
11
|
FastMcp = MCP unless defined?(FastMcp)
|
|
12
12
|
|
|
13
|
-
# Monkey-patch fast-mcp to ensure error responses always have a valid id
|
|
14
|
-
# JSON-RPC 2.0 allows id: null for notifications, but MCP clients (Cursor/Inspector)
|
|
15
|
-
# use strict Zod validation that requires id to be a string or number
|
|
16
|
-
module MCP
|
|
17
|
-
module Transports
|
|
18
|
-
class StdioTransport
|
|
19
|
-
if method_defined?(:send_error)
|
|
20
|
-
alias_method :original_send_error, :send_error
|
|
21
|
-
|
|
22
|
-
def send_error(code, message, id = nil)
|
|
23
|
-
# Use placeholder id if nil to satisfy strict MCP client validation
|
|
24
|
-
# JSON-RPC 2.0 allows null for notifications, but MCP clients require valid id
|
|
25
|
-
id = "error_#{SecureRandom.hex(8)}" if id.nil?
|
|
26
|
-
original_send_error(code, message, id)
|
|
27
|
-
end
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
class Server
|
|
33
|
-
if method_defined?(:send_error)
|
|
34
|
-
alias_method :original_send_error, :send_error
|
|
35
|
-
|
|
36
|
-
def send_error(code, message, id = nil)
|
|
37
|
-
# Use placeholder id if nil to satisfy strict MCP client validation
|
|
38
|
-
# JSON-RPC 2.0 allows null for notifications, but MCP clients require valid id
|
|
39
|
-
id = "error_#{SecureRandom.hex(8)}" if id.nil?
|
|
40
|
-
original_send_error(code, message, id)
|
|
41
|
-
end
|
|
42
|
-
end
|
|
43
|
-
end
|
|
44
|
-
end
|
|
45
|
-
|
|
46
13
|
module RubygemsMcp
|
|
47
14
|
# MCP Server for RubyGems integration
|
|
48
15
|
#
|
|
@@ -134,6 +101,8 @@ module RubygemsMcp
|
|
|
134
101
|
server.register_tool(GetRubyVersionRoadmapDetailsTool)
|
|
135
102
|
server.register_tool(GetRubyVersionGithubChangelogTool)
|
|
136
103
|
server.register_tool(GetGemVersionInfoTool)
|
|
104
|
+
server.register_tool(GetNewsReleasesTool)
|
|
105
|
+
server.register_tool(GetPopularReleasesTool)
|
|
137
106
|
end
|
|
138
107
|
|
|
139
108
|
def self.register_resources(server)
|
|
@@ -381,10 +350,41 @@ module RubygemsMcp
|
|
|
381
350
|
|
|
382
351
|
arguments do
|
|
383
352
|
required(:query).filled(:string).description("Search query (e.g., 'rails')")
|
|
353
|
+
optional(:page).filled(:integer).description("Page number (1-based). If provided, overrides offset")
|
|
354
|
+
optional(:limit).filled(:integer).description("Maximum number of results to return")
|
|
355
|
+
optional(:offset).filled(:integer).description("Number of results to skip (for pagination)")
|
|
356
|
+
end
|
|
357
|
+
|
|
358
|
+
def call(query:, page: nil, limit: nil, offset: 0)
|
|
359
|
+
get_client.search_gems(query, page: page, limit: limit, offset: offset)
|
|
360
|
+
end
|
|
361
|
+
end
|
|
362
|
+
|
|
363
|
+
# Get news releases (all new gem releases)
|
|
364
|
+
class GetNewsReleasesTool < BaseTool
|
|
365
|
+
tool_name "get_news_releases"
|
|
366
|
+
description "Get news releases - all new gem releases from RubyGems.org with pagination"
|
|
367
|
+
|
|
368
|
+
arguments do
|
|
369
|
+
optional(:page).filled(:integer).description("Page number (1-based, default: 1)")
|
|
384
370
|
end
|
|
385
371
|
|
|
386
|
-
def call(
|
|
387
|
-
get_client.
|
|
372
|
+
def call(page: 1)
|
|
373
|
+
get_client.get_news_releases(page: page)
|
|
374
|
+
end
|
|
375
|
+
end
|
|
376
|
+
|
|
377
|
+
# Get popular releases (popular new gem releases)
|
|
378
|
+
class GetPopularReleasesTool < BaseTool
|
|
379
|
+
tool_name "get_popular_releases"
|
|
380
|
+
description "Get popular releases - popular new gem releases from RubyGems.org with pagination"
|
|
381
|
+
|
|
382
|
+
arguments do
|
|
383
|
+
optional(:page).filled(:integer).description("Page number (1-based, default: 1)")
|
|
384
|
+
end
|
|
385
|
+
|
|
386
|
+
def call(page: 1)
|
|
387
|
+
get_client.get_popular_releases(page: page)
|
|
388
388
|
end
|
|
389
389
|
end
|
|
390
390
|
|
|
@@ -430,39 +430,50 @@ module RubygemsMcp
|
|
|
430
430
|
end
|
|
431
431
|
end
|
|
432
432
|
|
|
433
|
-
# Resource: Popular Ruby gems list
|
|
433
|
+
# Resource: Popular Ruby gems list with real-time data
|
|
434
434
|
class PopularGemsResource < FastMcp::Resource
|
|
435
435
|
uri "rubygems://popular"
|
|
436
436
|
resource_name "Popular Ruby Gems"
|
|
437
|
-
description "
|
|
437
|
+
description "Popular new gem releases from RubyGems.org with their versions, download counts, and metadata"
|
|
438
438
|
mime_type "application/json"
|
|
439
439
|
|
|
440
440
|
def content
|
|
441
441
|
client = Client.new
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
if latest
|
|
452
|
-
result = latest.dup
|
|
453
|
-
result[:name] = gem_name
|
|
454
|
-
result
|
|
455
|
-
else
|
|
456
|
-
{name: gem_name, version: nil, release_date: nil}
|
|
457
|
-
end
|
|
458
|
-
rescue ResponseSizeExceededError, CorruptedDataError => e
|
|
459
|
-
# Skip gems that exceed size limit or have corrupted data
|
|
460
|
-
{name: gem_name, version: nil, release_date: nil, error: e.message}
|
|
442
|
+
# Get popular releases from the first 3 pages (up to ~30 gems)
|
|
443
|
+
all_releases = []
|
|
444
|
+
(1..3).each do |page|
|
|
445
|
+
releases = client.get_popular_releases(page: page)
|
|
446
|
+
break if releases.empty?
|
|
447
|
+
all_releases.concat(releases)
|
|
448
|
+
rescue
|
|
449
|
+
# If a page fails, continue with what we have
|
|
450
|
+
break
|
|
461
451
|
end
|
|
462
452
|
|
|
463
|
-
#
|
|
464
|
-
gems_data =
|
|
465
|
-
|
|
453
|
+
# Limit to top 20 most popular by downloads
|
|
454
|
+
gems_data = all_releases
|
|
455
|
+
.select { |g| g[:downloads] && g[:downloads] > 0 }
|
|
456
|
+
.sort_by { |g| g[:downloads] || 0 }
|
|
457
|
+
.last(20).reverse
|
|
458
|
+
.map do |release|
|
|
459
|
+
{
|
|
460
|
+
name: release[:name],
|
|
461
|
+
version: release[:version],
|
|
462
|
+
release_date: release[:release_date],
|
|
463
|
+
downloads: release[:downloads],
|
|
464
|
+
info: release[:info],
|
|
465
|
+
gem_url: release[:gem_url]
|
|
466
|
+
}
|
|
467
|
+
end
|
|
468
|
+
|
|
469
|
+
result = {
|
|
470
|
+
updated_at: Time.now.iso8601,
|
|
471
|
+
total_gems: gems_data.length,
|
|
472
|
+
source: "rubygems.org/releases/popular",
|
|
473
|
+
gems: gems_data
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
JSON.pretty_generate(result)
|
|
466
477
|
end
|
|
467
478
|
end
|
|
468
479
|
|
|
@@ -528,17 +539,32 @@ module RubygemsMcp
|
|
|
528
539
|
end
|
|
529
540
|
end
|
|
530
541
|
|
|
531
|
-
# Resource: Latest Ruby version
|
|
542
|
+
# Resource: Latest Ruby version with additional context
|
|
532
543
|
class LatestRubyVersionResource < FastMcp::Resource
|
|
533
544
|
uri "rubygems://ruby/latest"
|
|
534
545
|
resource_name "Latest Ruby Version"
|
|
535
|
-
description "The latest stable Ruby version with release date"
|
|
546
|
+
description "The latest stable Ruby version with release date, maintenance status, and compatibility information"
|
|
536
547
|
mime_type "application/json"
|
|
537
548
|
|
|
538
549
|
def content
|
|
539
550
|
client = Client.new
|
|
540
551
|
latest = client.get_latest_ruby_version
|
|
541
|
-
|
|
552
|
+
maintenance_status = client.get_ruby_maintenance_status
|
|
553
|
+
|
|
554
|
+
# Find maintenance info for the latest version
|
|
555
|
+
latest_major_minor = latest[:version]&.match(/^(\d+\.\d+)/)&.[](1)
|
|
556
|
+
maintenance_info = maintenance_status.find { |m| m[:version] == latest_major_minor } if latest_major_minor
|
|
557
|
+
|
|
558
|
+
result = {
|
|
559
|
+
version: latest[:version],
|
|
560
|
+
release_date: latest[:release_date],
|
|
561
|
+
maintenance_status: maintenance_info&.dig(:status),
|
|
562
|
+
normal_maintenance_until: maintenance_info&.dig(:normal_maintenance_until),
|
|
563
|
+
eol: maintenance_info&.dig(:eol),
|
|
564
|
+
updated_at: Time.now.iso8601
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
JSON.pretty_generate(result)
|
|
542
568
|
end
|
|
543
569
|
end
|
|
544
570
|
end
|
data/lib/rubygems_mcp/version.rb
CHANGED