rubygems_mcp 0.1.0

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.
@@ -0,0 +1,444 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "fast_mcp"
5
+ require "rubygems_mcp"
6
+ require "logger"
7
+ require "stringio"
8
+ require "securerandom"
9
+
10
+ # Alias MCP to FastMcp for compatibility
11
+ FastMcp = MCP unless defined?(FastMcp)
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
+ alias_method :original_send_error, :send_error
20
+
21
+ def send_error(code, message, id = nil)
22
+ # Use placeholder id if nil to satisfy strict MCP client validation
23
+ # JSON-RPC 2.0 allows null for notifications, but MCP clients require valid id
24
+ id = "error_#{SecureRandom.hex(8)}" if id.nil?
25
+ original_send_error(code, message, id)
26
+ end
27
+ end
28
+ end
29
+
30
+ class Server
31
+ alias_method :original_send_error, :send_error
32
+
33
+ def send_error(code, message, id = nil)
34
+ # Use placeholder id if nil to satisfy strict MCP client validation
35
+ # JSON-RPC 2.0 allows null for notifications, but MCP clients require valid id
36
+ id = "error_#{SecureRandom.hex(8)}" if id.nil?
37
+ original_send_error(code, message, id)
38
+ end
39
+ end
40
+ end
41
+
42
+ module RubygemsMcp
43
+ # MCP Server for RubyGems integration
44
+ #
45
+ # This server provides MCP tools for interacting with RubyGems and Ruby version information
46
+ # Usage: bundle exec rubygems_mcp
47
+ class Server
48
+ # Simple null logger that suppresses all output
49
+ # Must implement the same interface as MCP::Logger
50
+ class NullLogger
51
+ attr_accessor :transport, :client_initialized
52
+
53
+ def initialize
54
+ @transport = nil
55
+ @client_initialized = false
56
+ @level = nil
57
+ end
58
+
59
+ attr_writer :level
60
+
61
+ attr_reader :level
62
+
63
+ def debug(*)
64
+ end
65
+
66
+ def info(*)
67
+ end
68
+
69
+ def warn(*)
70
+ end
71
+
72
+ def error(*)
73
+ end
74
+
75
+ def fatal(*)
76
+ end
77
+
78
+ def unknown(*)
79
+ end
80
+
81
+ def client_initialized?
82
+ @client_initialized
83
+ end
84
+
85
+ def set_client_initialized(value = true)
86
+ @client_initialized = value
87
+ end
88
+
89
+ def stdio_transport?
90
+ @transport == :stdio
91
+ end
92
+
93
+ def rack_transport?
94
+ @transport == :rack
95
+ end
96
+ end
97
+
98
+ def self.start
99
+ # Create server with null logger to prevent any output
100
+ server = FastMcp::Server.new(
101
+ name: "rubygems",
102
+ version: RubygemsMcp::VERSION,
103
+ logger: NullLogger.new
104
+ )
105
+
106
+ # Register all tools
107
+ register_tools(server)
108
+
109
+ # Register all resources
110
+ register_resources(server)
111
+
112
+ # Start the server (blocks and speaks MCP over STDIN/STDOUT)
113
+ server.start
114
+ end
115
+
116
+ def self.register_tools(server)
117
+ server.register_tool(GetLatestVersionsTool)
118
+ server.register_tool(GetGemVersionsTool)
119
+ server.register_tool(GetLatestRubyVersionTool)
120
+ server.register_tool(GetRubyVersionsTool)
121
+ server.register_tool(GetRubyVersionChangelogTool)
122
+ server.register_tool(GetGemInfoTool)
123
+ server.register_tool(GetGemReverseDependenciesTool)
124
+ server.register_tool(GetGemVersionDownloadsTool)
125
+ server.register_tool(GetLatestGemsTool)
126
+ server.register_tool(GetRecentlyUpdatedGemsTool)
127
+ server.register_tool(GetGemChangelogTool)
128
+ server.register_tool(SearchGemsTool)
129
+ end
130
+
131
+ def self.register_resources(server)
132
+ server.register_resource(PopularGemsResource)
133
+ server.register_resource(RubyVersionCompatibilityResource)
134
+ server.register_resource(RubyMaintenanceStatusResource)
135
+ server.register_resource(LatestRubyVersionResource)
136
+ end
137
+
138
+ # Base tool class with common error handling
139
+ #
140
+ # Exceptions raised in tool #call methods are automatically caught by fast-mcp
141
+ # and converted to MCP error results with the request ID preserved.
142
+ # fast-mcp uses send_error_result(message, id) which sends a result with
143
+ # isError: true, not a JSON-RPC error response.
144
+ class BaseTool < FastMcp::Tool
145
+ protected
146
+
147
+ def get_client
148
+ Client.new
149
+ end
150
+ end
151
+
152
+ # Get latest versions for a list of gems with release dates
153
+ class GetLatestVersionsTool < BaseTool
154
+ description "Get latest versions for a list of gems with release dates and licenses. Supports GraphQL-like field selection."
155
+
156
+ arguments do
157
+ required(:gem_names).filled(:array, min_size?: 1).description("Array of gem names (e.g., ['rails', 'nokogiri', 'rack'])")
158
+ optional(:fields).filled(:array).description("GraphQL-like field selection. Available: name, version, release_date, license, built_at, prerelease, platform, ruby_version, rubygems_version, downloads_count, sha, spec_sha, requirements, metadata")
159
+ end
160
+
161
+ def call(gem_names:, fields: nil)
162
+ get_client.get_latest_versions(gem_names, fields: fields)
163
+ end
164
+ end
165
+
166
+ # Get all versions for a single gem
167
+ class GetGemVersionsTool < BaseTool
168
+ description "Get all versions for a single gem with release dates and licenses, sorted by version descending. Supports GraphQL-like field selection."
169
+
170
+ arguments do
171
+ required(:gem_name).filled(:string).description("Gem name (e.g., 'rails')")
172
+ optional(:limit).filled(:integer).description("Maximum number of versions to return (for pagination)")
173
+ optional(:offset).filled(:integer).description("Number of versions to skip (for pagination)")
174
+ optional(:sort).filled(:string).description("Sort order: version_desc, version_asc, date_desc, or date_asc (default: version_desc)")
175
+ optional(:fields).filled(:array).description("GraphQL-like field selection. Available: version, release_date, license, built_at, prerelease, platform, ruby_version, rubygems_version, downloads_count, sha, spec_sha, requirements, metadata")
176
+ end
177
+
178
+ def call(gem_name:, limit: nil, offset: 0, sort: "version_desc", fields: nil)
179
+ valid_sorts = %w[version_desc version_asc date_desc date_asc]
180
+ sort_value = sort.to_s
181
+ sort_sym = if valid_sorts.include?(sort_value)
182
+ sort_value.to_sym
183
+ else
184
+ :version_desc
185
+ end
186
+ get_client.get_gem_versions(gem_name, limit: limit, offset: offset, sort: sort_sym, fields: fields)
187
+ end
188
+ end
189
+
190
+ # Get latest Ruby version with release date
191
+ class GetLatestRubyVersionTool < BaseTool
192
+ description "Get latest Ruby version with release date"
193
+
194
+ arguments do
195
+ # No arguments required
196
+ end
197
+
198
+ def call
199
+ get_client.get_latest_ruby_version
200
+ end
201
+ end
202
+
203
+ # Get all Ruby versions with release dates
204
+ class GetRubyVersionsTool < BaseTool
205
+ description "Get all Ruby versions with release dates, download URLs, and release notes URLs, sorted by version descending"
206
+
207
+ arguments do
208
+ optional(:limit).filled(:integer).description("Maximum number of versions to return (for pagination)")
209
+ optional(:offset).filled(:integer).description("Number of versions to skip (for pagination)")
210
+ optional(:sort).filled(:string).description("Sort order: version_desc, version_asc, date_desc, or date_asc (default: version_desc)")
211
+ end
212
+
213
+ def call(limit: nil, offset: 0, sort: "version_desc")
214
+ valid_sorts = %w[version_desc version_asc date_desc date_asc]
215
+ sort_value = sort.to_s
216
+ sort_sym = if valid_sorts.include?(sort_value)
217
+ sort_value.to_sym
218
+ else
219
+ :version_desc
220
+ end
221
+ get_client.get_ruby_versions(limit: limit, offset: offset, sort: sort_sym)
222
+ end
223
+ end
224
+
225
+ # Get changelog summary for a Ruby version
226
+ class GetRubyVersionChangelogTool < BaseTool
227
+ description "Get changelog summary for a specific Ruby version by fetching and parsing the release notes"
228
+
229
+ arguments do
230
+ required(:version).filled(:string).description("Ruby version (e.g., '3.4.7')")
231
+ end
232
+
233
+ def call(version:)
234
+ get_client.get_ruby_version_changelog(version)
235
+ end
236
+ end
237
+
238
+ # Get gem information (summary, homepage, etc.)
239
+ class GetGemInfoTool < BaseTool
240
+ description "Get detailed information about a gem (summary, homepage, source code, documentation, licenses, authors, dependencies, downloads). Supports GraphQL-like field selection."
241
+
242
+ arguments do
243
+ required(:gem_name).filled(:string).description("Gem name (e.g., 'rails')")
244
+ optional(:fields).filled(:array).description("GraphQL-like field selection. Available: name, version, summary, description, homepage, source_code, documentation, licenses, authors, info, downloads, version_downloads, yanked, dependencies, changelog_uri, funding_uri, platform, sha, spec_sha, metadata")
245
+ end
246
+
247
+ def call(gem_name:, fields: nil)
248
+ get_client.get_gem_info(gem_name, fields: fields)
249
+ end
250
+ end
251
+
252
+ # Get reverse dependencies (gems that depend on this gem)
253
+ class GetGemReverseDependenciesTool < BaseTool
254
+ description "Get reverse dependencies - list of gems that depend on the specified gem"
255
+
256
+ arguments do
257
+ required(:gem_name).filled(:string).description("Gem name (e.g., 'rails')")
258
+ end
259
+
260
+ def call(gem_name:)
261
+ get_client.get_gem_reverse_dependencies(gem_name)
262
+ end
263
+ end
264
+
265
+ # Get download statistics for a gem version
266
+ class GetGemVersionDownloadsTool < BaseTool
267
+ description "Get download statistics for a specific gem version"
268
+
269
+ arguments do
270
+ required(:gem_name).filled(:string).description("Gem name (e.g., 'rails')")
271
+ required(:version).filled(:string).description("Gem version (e.g., '7.1.0')")
272
+ end
273
+
274
+ def call(gem_name:, version:)
275
+ get_client.get_gem_version_downloads(gem_name, version)
276
+ end
277
+ end
278
+
279
+ # Get latest gems (most recently added)
280
+ class GetLatestGemsTool < BaseTool
281
+ description "Get latest gems - most recently added gems to RubyGems.org"
282
+
283
+ arguments do
284
+ optional(:limit).filled(:integer).description("Maximum number of gems to return (default: 30, max: 50)")
285
+ end
286
+
287
+ def call(limit: 30)
288
+ get_client.get_latest_gems(limit: limit)
289
+ end
290
+ end
291
+
292
+ # Get recently updated gems
293
+ class GetRecentlyUpdatedGemsTool < BaseTool
294
+ description "Get recently updated gems - most recently updated gem versions"
295
+
296
+ arguments do
297
+ optional(:limit).filled(:integer).description("Maximum number of gems to return (default: 30, max: 50)")
298
+ end
299
+
300
+ def call(limit: 30)
301
+ get_client.get_recently_updated_gems(limit: limit)
302
+ end
303
+ end
304
+
305
+ # Get changelog summary for a gem
306
+ class GetGemChangelogTool < BaseTool
307
+ description "Get changelog summary for a gem by fetching and parsing the changelog from its changelog_uri"
308
+
309
+ arguments do
310
+ required(:gem_name).filled(:string).description("Gem name (e.g., 'rails')")
311
+ optional(:version).filled(:string).description("Gem version (optional, uses latest if not provided)")
312
+ end
313
+
314
+ def call(gem_name:, version: nil)
315
+ get_client.get_gem_changelog(gem_name, version: version)
316
+ end
317
+ end
318
+
319
+ # Search for gems by name
320
+ class SearchGemsTool < BaseTool
321
+ description "Search for gems by name on RubyGems"
322
+
323
+ arguments do
324
+ required(:query).filled(:string).description("Search query (e.g., 'rails')")
325
+ end
326
+
327
+ def call(query:)
328
+ get_client.search_gems(query)
329
+ end
330
+ end
331
+
332
+ # Resource: Popular Ruby gems list
333
+ class PopularGemsResource < MCP::Resource
334
+ uri "rubygems://popular"
335
+ resource_name "Popular Ruby Gems"
336
+ description "A curated list of popular Ruby gems with their latest versions"
337
+ mime_type "application/json"
338
+
339
+ def default_content
340
+ client = Client.new
341
+ popular_gems = %w[
342
+ rails nokogiri bundler rake rspec devise puma sidekiq
343
+ pg mysql2 redis json webrick sinatra haml sass
344
+ jekyll octokit faraday httparty rest-client
345
+ ]
346
+
347
+ gems_data = popular_gems.map do |gem_name|
348
+ versions = client.get_gem_versions(gem_name, limit: 1, fields: ["name", "version", "release_date"])
349
+ latest = versions.first
350
+ if latest
351
+ result = latest.dup
352
+ result[:name] = gem_name
353
+ result
354
+ else
355
+ {name: gem_name, version: nil, release_date: nil}
356
+ end
357
+ rescue Client::ResponseSizeExceededError, Client::CorruptedDataError => e
358
+ # Skip gems that exceed size limit or have corrupted data
359
+ {name: gem_name, version: nil, release_date: nil, error: e.message}
360
+ end
361
+
362
+ # Filter out gems that weren't found (nil versions)
363
+ gems_data = gems_data.reject { |g| g[:version].nil? }
364
+ JSON.pretty_generate(gems_data)
365
+ end
366
+ end
367
+
368
+ # Resource: Ruby version compatibility information
369
+ class RubyVersionCompatibilityResource < MCP::Resource
370
+ uri "rubygems://ruby/compatibility"
371
+ resource_name "Ruby Version Compatibility"
372
+ description "Information about Ruby version compatibility and release dates"
373
+ mime_type "application/json"
374
+
375
+ def default_content
376
+ client = Client.new
377
+ ruby_versions = client.get_ruby_versions(limit: 20, sort: :version_desc)
378
+ latest = client.get_latest_ruby_version
379
+ maintenance_status = client.get_ruby_maintenance_status
380
+
381
+ # Create a map of version to maintenance status for quick lookup
382
+ maintenance_status.each_with_object({}) do |status, map|
383
+ map[status[:version]] = status
384
+ end
385
+
386
+ data = {
387
+ latest: latest,
388
+ recent_versions: ruby_versions,
389
+ maintenance_status: maintenance_status.first(10), # Most recent 10 versions
390
+ compatibility_notes: {
391
+ "3.4.x" => "Latest stable series. Normal maintenance. Supports all modern gems.",
392
+ "3.3.x" => "Stable series. Normal maintenance until 2027. Well-supported by most gems.",
393
+ "3.2.x" => "Security maintenance only. EOL expected 2026-03-31.",
394
+ "3.1.x" => "End of life (EOL: 2025-03-26). No longer supported.",
395
+ "3.0.x" => "End of life (EOL: 2024-04-23). No longer supported.",
396
+ "2.7.x" => "End of life. No longer supported."
397
+ }
398
+ }
399
+
400
+ JSON.pretty_generate(data)
401
+ end
402
+ end
403
+
404
+ # Resource: Ruby maintenance status for all versions
405
+ class RubyMaintenanceStatusResource < MCP::Resource
406
+ uri "rubygems://ruby/maintenance"
407
+ resource_name "Ruby Maintenance Status"
408
+ description "Detailed maintenance status for all Ruby versions including EOL dates and maintenance phases"
409
+ mime_type "application/json"
410
+
411
+ def default_content
412
+ client = Client.new
413
+ maintenance_status = client.get_ruby_maintenance_status
414
+
415
+ data = {
416
+ updated_at: Time.now.iso8601,
417
+ versions: maintenance_status,
418
+ summary: {
419
+ preview: maintenance_status.count { |v| v[:status] == "preview" },
420
+ normal_maintenance: maintenance_status.count { |v| v[:status] == "normal maintenance" },
421
+ security_maintenance: maintenance_status.count { |v| v[:status] == "security maintenance" },
422
+ eol: maintenance_status.count { |v| v[:status] == "eol" }
423
+ }
424
+ }
425
+
426
+ JSON.pretty_generate(data)
427
+ end
428
+ end
429
+
430
+ # Resource: Latest Ruby version
431
+ class LatestRubyVersionResource < MCP::Resource
432
+ uri "rubygems://ruby/latest"
433
+ resource_name "Latest Ruby Version"
434
+ description "The latest stable Ruby version with release date"
435
+ mime_type "application/json"
436
+
437
+ def default_content
438
+ client = Client.new
439
+ latest = client.get_latest_ruby_version
440
+ JSON.pretty_generate(latest)
441
+ end
442
+ end
443
+ end
444
+ end
@@ -0,0 +1,3 @@
1
+ module RubygemsMcp
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,31 @@
1
+ require "uri"
2
+ require "net/http"
3
+ require "json"
4
+ require "date"
5
+
6
+ require_relative "rubygems_mcp/version"
7
+ require_relative "rubygems_mcp/client"
8
+ # Server is loaded on-demand when running the executable
9
+ # require_relative "rubygems_mcp/server"
10
+
11
+ module RubygemsMcp
12
+ # Main module for RubyGems MCP integration
13
+ #
14
+ # This gem provides:
15
+ # - RubygemsMcp::Client - API client for RubyGems and Ruby version information
16
+ #
17
+ # @example Basic usage
18
+ # require "rubygems_mcp"
19
+ #
20
+ # # Create client
21
+ # client = RubygemsMcp::Client.new
22
+ #
23
+ # # Get latest versions for multiple gems
24
+ # versions = client.get_latest_versions(["rails", "nokogiri", "rack"])
25
+ #
26
+ # # Get all versions for a gem
27
+ # versions = client.get_gem_versions("rails")
28
+ #
29
+ # # Get latest Ruby version
30
+ # ruby_version = client.get_latest_ruby_version
31
+ end
@@ -0,0 +1,199 @@
1
+ module RubygemsMcp
2
+ VERSION: String
3
+
4
+ class Client
5
+ MAX_RESPONSE_SIZE: Integer
6
+
7
+ class ResponseSizeExceededError < StandardError
8
+ def initialize: (Integer size, Integer max_size) -> void
9
+ attr_reader size: Integer
10
+ attr_reader max_size: Integer
11
+ end
12
+
13
+ class CorruptedDataError < StandardError
14
+ def initialize: (String message, ?original_error: Exception?, ?response_size: Integer?) -> void
15
+ attr_reader original_error: Exception?
16
+ attr_reader response_size: Integer?
17
+ end
18
+
19
+ class Cache
20
+ def initialize: () -> void
21
+ def get: (String key) -> untyped?
22
+ def set: (String key, untyped value, Integer ttl_seconds) -> void
23
+ def clear: () -> void
24
+ end
25
+
26
+ def self.cache: () -> Cache
27
+
28
+ def initialize: (?cache_enabled: bool) -> void
29
+ def build_http_client: (URI uri) -> Net::HTTP
30
+ def validate_and_parse_json: (String body, URI uri) -> (Hash[untyped, untyped] | Array[untyped])
31
+ def validate_and_parse_html: (String body, URI uri) -> Nokogiri::HTML::Document
32
+
33
+ # Get latest versions for multiple gems
34
+ def get_latest_versions: (
35
+ Array[String] gem_names,
36
+ ?fields: Array[String]?
37
+ ) -> Array[Hash[Symbol, untyped]]
38
+
39
+ # Get all versions for a gem with pagination, sorting, and field selection
40
+ def get_gem_versions: (
41
+ String gem_name,
42
+ ?limit: Integer?,
43
+ ?offset: Integer,
44
+ ?sort: (:version_desc | :version_asc | :date_desc | :date_asc),
45
+ ?fields: Array[String]?
46
+ ) -> Array[Hash[Symbol, untyped]]
47
+
48
+ # Get latest Ruby version
49
+ def get_latest_ruby_version: () -> Hash[Symbol, (String | nil)]
50
+
51
+ # Get Ruby maintenance status
52
+ def get_ruby_maintenance_status: () -> Array[Hash[Symbol, (String | nil)]]
53
+
54
+ # Get all Ruby versions with download and release notes URLs
55
+ def get_ruby_versions: (
56
+ ?limit: Integer?,
57
+ ?offset: Integer,
58
+ ?sort: (:version_desc | :version_asc | :date_desc | :date_asc)
59
+ ) -> Array[Hash[Symbol, (String | nil)]]
60
+
61
+ # Get changelog for a Ruby version
62
+ def get_ruby_version_changelog: (String version) -> Hash[Symbol, (String | nil)]
63
+
64
+ # Get reverse dependencies (gems that depend on this gem)
65
+ def get_gem_reverse_dependencies: (String gem_name) -> Array[String]
66
+
67
+ # Get download statistics for a gem version
68
+ def get_gem_version_downloads: (
69
+ String gem_name,
70
+ String version
71
+ ) -> Hash[Symbol, (String | Integer | nil)]
72
+
73
+ # Get latest gems (most recently added)
74
+ def get_latest_gems: (?limit: Integer) -> Array[Hash[Symbol, untyped]]
75
+
76
+ # Get recently updated gems
77
+ def get_recently_updated_gems: (?limit: Integer) -> Array[Hash[Symbol, untyped]]
78
+
79
+ # Get changelog for a gem
80
+ def get_gem_changelog: (
81
+ String gem_name,
82
+ ?version: String?
83
+ ) -> Hash[Symbol, (String | nil)]
84
+
85
+ # Get gem information with field selection
86
+ def get_gem_info: (
87
+ String gem_name,
88
+ ?fields: Array[String]?
89
+ ) -> Hash[Symbol, untyped]
90
+
91
+ # Search for gems with pagination
92
+ def search_gems: (
93
+ String query,
94
+ ?limit: Integer?,
95
+ ?offset: Integer
96
+ ) -> Array[Hash[Symbol, untyped]]
97
+ end
98
+
99
+ class Server
100
+ class NullLogger
101
+ def initialize: () -> void
102
+ end
103
+
104
+ class BaseTool
105
+ end
106
+
107
+ class GetLatestVersionsTool < BaseTool
108
+ def call: (Array[String] gem_names, ?Array[String]? fields) -> Array[Hash[Symbol, untyped]]
109
+ end
110
+
111
+ class GetGemVersionsTool < BaseTool
112
+ def call: (
113
+ String gem_name,
114
+ ?Integer? limit,
115
+ ?Integer offset,
116
+ ?String sort,
117
+ ?Array[String]? fields
118
+ ) -> Array[Hash[Symbol, untyped]]
119
+ end
120
+
121
+ class GetLatestRubyVersionTool < BaseTool
122
+ def call: () -> Hash[Symbol, (String | nil)]
123
+ end
124
+
125
+ class GetRubyVersionsTool < BaseTool
126
+ def call: (
127
+ ?Integer? limit,
128
+ ?Integer offset,
129
+ ?String sort
130
+ ) -> Array[Hash[Symbol, (String | nil)]]
131
+ end
132
+
133
+ class GetRubyVersionChangelogTool < BaseTool
134
+ def call: (String version) -> Hash[Symbol, (String | nil)]
135
+ end
136
+
137
+ class GetGemInfoTool < BaseTool
138
+ def call: (String gem_name, ?Array[String]? fields) -> Hash[Symbol, untyped]
139
+ end
140
+
141
+ class GetGemReverseDependenciesTool < BaseTool
142
+ def call: (String gem_name) -> Array[String]
143
+ end
144
+
145
+ class GetGemVersionDownloadsTool < BaseTool
146
+ def call: (String gem_name, String version) -> Hash[Symbol, (String | Integer | nil)]
147
+ end
148
+
149
+ class GetLatestGemsTool < BaseTool
150
+ def call: (?Integer limit) -> Array[Hash[Symbol, untyped]]
151
+ end
152
+
153
+ class GetRecentlyUpdatedGemsTool < BaseTool
154
+ def call: (?Integer limit) -> Array[Hash[Symbol, untyped]]
155
+ end
156
+
157
+ class GetGemChangelogTool < BaseTool
158
+ def call: (String gem_name, ?String? version) -> Hash[Symbol, (String | nil)]
159
+ end
160
+
161
+ class SearchGemsTool < BaseTool
162
+ def call: (String query) -> Array[Hash[Symbol, untyped]]
163
+ end
164
+
165
+ class PopularGemsResource
166
+ def self.uri: () -> String
167
+ def self.resource_name: () -> String
168
+ def uri: () -> String
169
+ def content: () -> String
170
+ end
171
+
172
+ class RubyVersionCompatibilityResource
173
+ def self.uri: () -> String
174
+ def self.resource_name: () -> String
175
+ def uri: () -> String
176
+ def content: () -> String
177
+ end
178
+
179
+ class RubyMaintenanceStatusResource
180
+ def self.uri: () -> String
181
+ def self.resource_name: () -> String
182
+ def uri: () -> String
183
+ def content: () -> String
184
+ end
185
+
186
+ class LatestRubyVersionResource
187
+ def self.uri: () -> String
188
+ def self.resource_name: () -> String
189
+ def uri: () -> String
190
+ def content: () -> String
191
+ end
192
+
193
+ def self.start: () -> void
194
+ def self.register_tools: (untyped server) -> void
195
+ def self.register_resources: (untyped server) -> void
196
+ end
197
+ end
198
+
199
+