rubygems_mcp 0.1.3 → 0.2.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 263030b634fd9d87f2a5d3d4ff68574e017438ec57a7caff2ebc0b5729dfccb2
4
- data.tar.gz: 8c9e6142f7c8c7cbb6695c5265c2a7655eb7606872963ec0db3bf5ffb9a7d140
3
+ metadata.gz: 792f4e1e9055f0daca5acf09de1b71cdaa64a203808f9f71463d5cb7d67544e1
4
+ data.tar.gz: cc8a4b2af63e9b96534aae1aee6aeeb572fee2fd602d1d648d29b50c391fb9e5
5
5
  SHA512:
6
- metadata.gz: 0f6bc852cf223da1499bf87063b2f92acbc562d40b4bd7d7fdfd8a4af38bf79064616fb8c0275b50e1e1e148a390cf92fcbdd0547cd3d45ca96d7ccf6966c1ec
7
- data.tar.gz: 3ae00927439ed56b949e3d2a3ffa3830d87e3ee89d34d6e62adad8af51e7df54a33f2af870ee4b657b80300d335528b7627c8a2d986375a9a8aab7a81ce79516
6
+ metadata.gz: 5383415d5d7963b119273f486dca440c5af64e490065abfeaab9e3f9d21e03297cf3f0931252909f8fa2ba9d7e777c11101dcf483840ad70a9f1a6a3a96db816
7
+ data.tar.gz: ba60b3179ad4956457c4cd22e758e3a93a4f9ce4347697c899459003fc4002555077d8d56c0af525c7f0f8d74010fe5148c1ae4e6fb88d2b611e4f2177d28481
data/CHANGELOG.md CHANGED
@@ -1,5 +1,30 @@
1
1
  # CHANGELOG
2
2
 
3
+ ## Unreleased
4
+
5
+ ## 0.2.0 (2026-09-08)
6
+
7
+ - BREAKING: Require Ruby 3.4
8
+ - BREAKING: Raise `fast-mcp` to `>= 1.6` and `nokogiri` to `~> 1.19`
9
+ - BREAKING: `search_gems` paginates with `limit` and `offset` on the first search page
10
+ - BREAKING: Raise when an MCP version tool receives an invalid sort order
11
+ - Fetch gem changelogs only over HTTPS from GitHub, GitLab, RubyGems, and ruby-lang.org hosts
12
+ - Include the changelog source host on fetch results
13
+ - Read latest gem versions from gem info and keep rows whose dates fail to parse
14
+ - Skip caching empty Ruby changelogs after a GitHub fetch failure
15
+ - Stop reading HTTP bodies whose Content-Length exceeds 5MB
16
+ - Cap the in-memory response cache
17
+ - Paginate and cache the Ruby versions list on first fetch
18
+ - Apply the HTTP size limit to GitHub Ruby changelogs
19
+ - Limit latest-version lookups to 20 gem names
20
+
21
+ ## 0.1.4 (2025-11-26)
22
+
23
+ - Add `get_news_releases` tool to fetch all new gem releases from RubyGems.org with pagination (fetches from `/news?page=N`)
24
+ - Add `get_popular_releases` tool to fetch popular new gem releases from RubyGems.org with pagination (fetches from `/releases/popular?page=N`)
25
+ - Add pagination support for `search_gems` tool via `page` parameter (converts page to offset automatically)
26
+ - Remove old patch code: unused monkey patches for fast-mcp `send_error`
27
+
3
28
  ## 0.1.3 (2025-11-21)
4
29
 
5
30
  - Add Ruby roadmap tools: `get_ruby_roadmap` and `get_ruby_version_roadmap_details` for accessing Ruby version planning information from bugs.ruby-lang.org
@@ -53,4 +78,3 @@
53
78
  - Comprehensive test suite with RSpec, VCR cassettes, and WebMock
54
79
  - Requires Ruby 3.1 or higher
55
80
  - All dependencies use latest compatible versions with pessimistic versioning for security
56
-
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # rubygems_mcp
2
2
 
3
- [![Gem Version](https://badge.fury.io/rb/rubygems_mcp.svg?v=0.1.3)](https://badge.fury.io/rb/rubygems_mcp) [![Test Status](https://github.com/amkisko/rubygems_mcp.rb/actions/workflows/test.yml/badge.svg)](https://github.com/amkisko/rubygems_mcp.rb/actions/workflows/test.yml) [![codecov](https://codecov.io/gh/amkisko/rubygems_mcp.rb/graph/badge.svg?token=APQ6AK7EC9)](https://codecov.io/gh/amkisko/rubygems_mcp.rb)
3
+ [![Gem Version](https://badge.fury.io/rb/rubygems_mcp.svg?v=0.2.0)](https://badge.fury.io/rb/rubygems_mcp) [![Test Status](https://github.com/amkisko/rubygems_mcp.rb/actions/workflows/test.yml/badge.svg)](https://github.com/amkisko/rubygems_mcp.rb/actions/workflows/test.yml) [![codecov](https://codecov.io/gh/amkisko/rubygems_mcp.rb/graph/badge.svg?token=APQ6AK7EC9)](https://app.codecov.io/github/amkisko/rubygems_mcp.rb) [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=amkisko_rubygems_mcp.rb&metric=alert_status)](https://sonarcloud.io/project/overview?id=amkisko_rubygems_mcp.rb)
4
4
 
5
5
  Ruby gem providing RubyGems and Ruby version information via MCP (Model Context Protocol) server tools. Integrates with MCP-compatible clients like Cursor IDE, Claude Desktop, and other MCP-enabled tools.
6
6
 
@@ -14,7 +14,7 @@ Sponsored by [Kisko Labs](https://www.kiskolabs.com).
14
14
 
15
15
  ## Requirements
16
16
 
17
- - **Ruby 3.1 or higher** (Ruby 3.0 and earlier are not supported)
17
+ - **Ruby 3.4 or higher**
18
18
 
19
19
  ## Quick Start
20
20
 
@@ -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": "rubygems_mcp"
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": "rubygems_mcp"
56
+ "command": "gem",
57
+ "args": ["exec", "rubygems_mcp"],
58
+ "env": {
59
+ "RUBY_VERSION": "3.4.7"
60
+ }
51
61
  }
52
62
  }
53
63
  }
@@ -93,7 +103,7 @@ The server will start and communicate via STDIN/STDOUT using the MCP protocol.
93
103
 
94
104
  - **RubyGems API Client**: Full-featured client for RubyGems REST API with comprehensive endpoint coverage
95
105
  - **Ruby Version Information**: Fetch Ruby release information, changelogs, and maintenance status from ruby-lang.org
96
- - **MCP Server Integration**: Ready-to-use MCP server with 19 tools and 4 resources, compatible with Cursor IDE, Claude Desktop, and other MCP-enabled tools
106
+ - **MCP Server Integration**: Ready-to-use MCP server with 18 tools and 4 resources, compatible with Cursor IDE, Claude Desktop, and other MCP-enabled tools
97
107
  - **Pagination & Sorting**: Support for large result sets with customizable pagination and sorting options
98
108
  - **Caching**: In-memory caching with configurable TTL for improved performance
99
109
  - **Error Handling**: Graceful error handling with custom exceptions and response size limits
@@ -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
 
@@ -274,7 +286,7 @@ The MCP server provides the following tools:
274
286
  - Parameters: `gem_name` (string), `version` (optional string, uses latest if not provided)
275
287
 
276
288
  13. **search_gems** - Search for gems by name on RubyGems
277
- - Parameters: `query` (string)
289
+ - Parameters: `query` (string), `limit` (optional integer), `offset` (optional integer)
278
290
 
279
291
  14. **get_ruby_roadmap** - Get Ruby roadmap information from bugs.ruby-lang.org showing planned versions and their issues
280
292
  - Parameters: none
@@ -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:
@@ -307,10 +327,7 @@ The MCP server provides the following resources:
307
327
 
308
328
  ## Error Handling
309
329
 
310
- The client handles errors gracefully:
311
- - Returns empty arrays for failed requests
312
- - Returns empty hashes for failed gem info requests
313
- - Handles network errors and JSON parsing errors
330
+ HTTP failures raise `NotFoundError`, `ServerError`, or `APIError`. Unreadable JSON or HTML raises `CorruptedDataError`. Bodies over 5MB raise `ResponseSizeExceededError`. Invalid input, including more than 20 names on `get_latest_versions`, raises `ValidationError`.
314
331
 
315
332
  ## Development
316
333
 
@@ -352,6 +369,18 @@ For more information, see [CONTRIBUTING.md](CONTRIBUTING.md).
352
369
 
353
370
  If you discover a security vulnerability, please report it responsibly. See [SECURITY.md](SECURITY.md) for details.
354
371
 
372
+ ## Links
373
+
374
+ - [GitHub](https://github.com/amkisko/rubygems_mcp.rb)
375
+ - [GitLab](https://gitlab.com/amkisko/rubygems_mcp.rb)
376
+ - [RubyGems](https://rubygems.org/gems/rubygems_mcp)
377
+ - [libraries.io](https://libraries.io/rubygems/rubygems_mcp)
378
+ - [Deps.dev](https://deps.dev/rubygems/rubygems_mcp)
379
+ - [SonarCloud](https://sonarcloud.io/project/overview?id=amkisko_rubygems_mcp.rb)
380
+ - [Snyk](https://snyk.io/test/github/amkisko/rubygems_mcp.rb)
381
+ - [Codecov](https://app.codecov.io/github/amkisko/rubygems_mcp.rb)
382
+ - [OpenSSF Scorecard](https://scorecard.dev/viewer/?uri=github.com/amkisko/rubygems_mcp.rb)
383
+
355
384
  ## License
356
385
 
357
386
  The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubygemsMcp
4
+ class Cache
5
+ MAX_ENTRIES = 256
6
+
7
+ def initialize(max_entries: MAX_ENTRIES)
8
+ @cache = {}
9
+ @mutex = Mutex.new
10
+ @inflight = {}
11
+ @max_entries = max_entries
12
+ end
13
+
14
+ def get(key)
15
+ @mutex.synchronize { read_unlocked(key) }
16
+ end
17
+
18
+ def set(key, value, ttl_seconds)
19
+ @mutex.synchronize { write_unlocked(key, value, ttl_seconds) }
20
+ end
21
+
22
+ def fetch(key, ttl_seconds)
23
+ cached = get(key)
24
+ return cached unless cached.nil?
25
+
26
+ lock = @mutex.synchronize { @inflight[key] ||= Mutex.new }
27
+ lock.synchronize do
28
+ cached = get(key)
29
+ return cached unless cached.nil?
30
+
31
+ value = yield
32
+ set(key, value, ttl_seconds)
33
+ value
34
+ ensure
35
+ @mutex.synchronize { @inflight.delete(key) if @inflight[key].equal?(lock) }
36
+ end
37
+ end
38
+
39
+ def clear
40
+ @mutex.synchronize do
41
+ @cache.clear
42
+ @inflight.clear
43
+ end
44
+ end
45
+
46
+ def size
47
+ @mutex.synchronize { @cache.size }
48
+ end
49
+
50
+ private
51
+
52
+ def read_unlocked(key)
53
+ entry = @cache[key]
54
+ return nil unless entry
55
+
56
+ if entry[:expires_at] < Time.now
57
+ @cache.delete(key)
58
+ return nil
59
+ end
60
+
61
+ entry[:value]
62
+ end
63
+
64
+ def write_unlocked(key, value, ttl_seconds)
65
+ evict_unlocked if @cache.size >= @max_entries && !@cache.key?(key)
66
+ @cache.delete(key)
67
+ @cache[key] = {value: value, expires_at: Time.now + ttl_seconds}
68
+ end
69
+
70
+ def evict_unlocked
71
+ now = Time.now
72
+ @cache.delete_if { |_key, entry| entry[:expires_at] < now }
73
+ @cache.shift while @cache.size >= @max_entries
74
+ end
75
+ end
76
+ end