open_gemdocs 0.2.4 → 0.3.1
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
- checksums.yaml.gz.sig +0 -0
- data/.rubocop.yml +37 -0
- data/CHANGELOG.md +4 -0
- data/CLAUDE.md +136 -0
- data/README.md +53 -2
- data/checksums/open_gemdocs-0.3.1.gem.sha512 +1 -0
- data/exe/document-bundle +8 -0
- data/exe/open-gem-docs +11 -11
- data/exe/open-gem-docs-mcp +52 -0
- data/exe/open-gem-docs-mcp-stdio +76 -0
- data/lib/open_gemdocs/browser.rb +12 -14
- data/lib/open_gemdocs/mcp/handlers.rb +92 -0
- data/lib/open_gemdocs/mcp/server.rb +77 -0
- data/lib/open_gemdocs/mcp/tools.rb +471 -0
- data/lib/open_gemdocs/version.rb +1 -1
- data/lib/open_gemdocs/yard.rb +21 -7
- data/lib/open_gemdocs/yard_json_formatter.rb +225 -0
- data/lib/open_gemdocs.rb +11 -3
- data.tar.gz.sig +1 -3
- metadata +29 -2
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9bbe6e98bfab5caa95c6324956c9a45c44460d78851aeec0187d2a2718a0009a
|
4
|
+
data.tar.gz: 5f63e28eb06fc99aa6302784266315f9db0c7564a97319a12db88ad6b1faf917
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f8ac2030c49a4a20960eaee3d183ffb00794678db396897f14c969088355c734fa57d9ea62613946553a7400dfcbd344613eddeb74734acf0bdad35964f0e474
|
7
|
+
data.tar.gz: bc42203b67b70b9839844febce219fa5d7b9732c609120eeac8f39d32b86de423794ace83d1c208a069eff4df9ca14f5958d57ce3a36a611e1c6d61cabb7a66b
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data/.rubocop.yml
CHANGED
@@ -1,8 +1,45 @@
|
|
1
1
|
AllCops:
|
2
2
|
TargetRubyVersion: 3.1
|
3
|
+
NewCops: enable
|
4
|
+
SuggestExtensions: false
|
3
5
|
|
4
6
|
Style/StringLiterals:
|
5
7
|
EnforcedStyle: double_quotes
|
6
8
|
|
7
9
|
Style/StringLiteralsInInterpolation:
|
8
10
|
EnforcedStyle: double_quotes
|
11
|
+
|
12
|
+
Style/Documentation:
|
13
|
+
Enabled: false
|
14
|
+
|
15
|
+
Metrics/MethodLength:
|
16
|
+
Max: 30
|
17
|
+
Exclude:
|
18
|
+
- 'lib/open_gemdocs/mcp/tools.rb'
|
19
|
+
|
20
|
+
Metrics/ClassLength:
|
21
|
+
Max: 350
|
22
|
+
|
23
|
+
Metrics/BlockLength:
|
24
|
+
Exclude:
|
25
|
+
- 'spec/**/*'
|
26
|
+
- '*.gemspec'
|
27
|
+
|
28
|
+
Metrics/AbcSize:
|
29
|
+
Max: 35
|
30
|
+
|
31
|
+
Metrics/CyclomaticComplexity:
|
32
|
+
Max: 15
|
33
|
+
|
34
|
+
Metrics/PerceivedComplexity:
|
35
|
+
Max: 15
|
36
|
+
|
37
|
+
Layout/LineLength:
|
38
|
+
Max: 200
|
39
|
+
|
40
|
+
Naming/AccessorMethodName:
|
41
|
+
Exclude:
|
42
|
+
- 'lib/open_gemdocs/mcp/tools.rb'
|
43
|
+
|
44
|
+
Style/MultilineBlockChain:
|
45
|
+
Enabled: false
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,9 @@
|
|
1
1
|
## [Unreleased]
|
2
2
|
|
3
|
+
## [0.3.0] - 2025-04-27
|
4
|
+
### Added
|
5
|
+
- Added a MCP server that can serve local yard documentation for all installed gems. This allows AI agents to access gem documentation without needing to run a local server manually.
|
6
|
+
|
3
7
|
## [0.2.1] - 2025-04-26
|
4
8
|
### Changed
|
5
9
|
- Fixed a bug where the `--local` option was not working correctly when a specific gem was specified. The command now correctly serves the documentation for the specified gem from the local server.
|
data/CLAUDE.md
ADDED
@@ -0,0 +1,136 @@
|
|
1
|
+
# CLAUDE.md
|
2
|
+
|
3
|
+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
4
|
+
|
5
|
+
## Repository Overview
|
6
|
+
|
7
|
+
Open_gemdocs is a Ruby gem that provides a command-line tool for opening Ruby gem documentation. It supports both local documentation (via Yard server) and online documentation (via gemdocs.org).
|
8
|
+
|
9
|
+
## Common Commands
|
10
|
+
|
11
|
+
### Development Setup
|
12
|
+
```bash
|
13
|
+
# Install dependencies
|
14
|
+
bundle install
|
15
|
+
|
16
|
+
# Setup development environment
|
17
|
+
bin/setup
|
18
|
+
|
19
|
+
# Open IRB console with gem loaded
|
20
|
+
bin/console
|
21
|
+
```
|
22
|
+
|
23
|
+
### Testing
|
24
|
+
```bash
|
25
|
+
# Run all tests
|
26
|
+
bundle exec rspec
|
27
|
+
|
28
|
+
# Run specific test file
|
29
|
+
bundle exec rspec spec/open_gemdocs_spec.rb
|
30
|
+
|
31
|
+
# Run tests via Rake
|
32
|
+
bundle exec rake spec
|
33
|
+
```
|
34
|
+
|
35
|
+
### Linting & Code Quality
|
36
|
+
```bash
|
37
|
+
# Run RuboCop for code linting
|
38
|
+
bundle exec rubocop
|
39
|
+
|
40
|
+
# Auto-fix RuboCop violations
|
41
|
+
bundle exec rubocop -a
|
42
|
+
|
43
|
+
# Run all checks (tests + linting)
|
44
|
+
bundle exec rake
|
45
|
+
```
|
46
|
+
|
47
|
+
### Building & Installation
|
48
|
+
```bash
|
49
|
+
# Build the gem
|
50
|
+
gem build open_gemdocs.gemspec
|
51
|
+
|
52
|
+
# Install locally for testing
|
53
|
+
gem install ./open_gemdocs-*.gem
|
54
|
+
|
55
|
+
# Build via Rake
|
56
|
+
bundle exec rake build
|
57
|
+
|
58
|
+
# Release new version (requires gem push permissions)
|
59
|
+
bundle exec rake release
|
60
|
+
```
|
61
|
+
|
62
|
+
### Local Testing of CLI
|
63
|
+
```bash
|
64
|
+
# Test the main executable
|
65
|
+
bundle exec exe/open-gem-docs rails
|
66
|
+
|
67
|
+
# Test with local documentation
|
68
|
+
bundle exec exe/open-gem-docs --local rails
|
69
|
+
|
70
|
+
# Test the local-only wrapper
|
71
|
+
bundle exec exe/open-local-docs rails
|
72
|
+
```
|
73
|
+
|
74
|
+
### MCP Server
|
75
|
+
```bash
|
76
|
+
# Start MCP server on default port (6789)
|
77
|
+
bundle exec exe/open-gem-docs-mcp
|
78
|
+
|
79
|
+
# Start MCP server on custom port
|
80
|
+
bundle exec exe/open-gem-docs-mcp --port 8080
|
81
|
+
|
82
|
+
# Start MCP server in stdio mode (for Claude Desktop integration)
|
83
|
+
bundle exec exe/open-gem-docs-mcp-stdio
|
84
|
+
|
85
|
+
# View MCP server help and available tools
|
86
|
+
bundle exec exe/open-gem-docs-mcp --help
|
87
|
+
```
|
88
|
+
|
89
|
+
## Architecture
|
90
|
+
|
91
|
+
The gem follows a simple, focused architecture with core documentation components and MCP server integration:
|
92
|
+
|
93
|
+
### Core Module Structure
|
94
|
+
- **`lib/open_gemdocs.rb`**: Main module that orchestrates between Browser and Yard classes based on user options
|
95
|
+
- **`lib/open_gemdocs/browser.rb`**: Handles opening online documentation from gemdocs.org, includes Gemfile.lock parsing for version detection
|
96
|
+
- **`lib/open_gemdocs/yard.rb`**: Manages local Yard server lifecycle (starting, stopping, checking status) and opens local documentation
|
97
|
+
|
98
|
+
### MCP (Model Context Protocol) Integration
|
99
|
+
The gem includes MCP server capabilities for AI assistant integration:
|
100
|
+
|
101
|
+
- **`lib/open_gemdocs/mcp/server.rb`**: MCP server implementation supporting both TCP and stdio modes
|
102
|
+
- **`lib/open_gemdocs/mcp/handlers.rb`**: JSON-RPC request handling for MCP protocol
|
103
|
+
- **`lib/open_gemdocs/mcp/tools.rb`**: MCP tool implementations providing programmatic access to gem documentation
|
104
|
+
|
105
|
+
Available MCP tools:
|
106
|
+
- `search_gems`: Search for installed Ruby gems by name
|
107
|
+
- `get_gem_info`: Get detailed metadata about a specific gem
|
108
|
+
- `start_yard_server`: Start the Yard documentation server
|
109
|
+
- `stop_yard_server`: Stop the Yard documentation server
|
110
|
+
- `get_yard_server_status`: Check if Yard server is running and where
|
111
|
+
- `get_gem_documentation_url`: Get the local documentation URL for a gem
|
112
|
+
- `fetch_gem_docs`: Fetch documentation content from Yard server
|
113
|
+
|
114
|
+
### Key Implementation Details
|
115
|
+
|
116
|
+
1. **Version Detection**: The Browser class automatically detects gem versions from Gemfile.lock when no version is specified
|
117
|
+
2. **Server Management**: The Yard class manages a background Yard server process, checking if it's running and starting it if needed
|
118
|
+
3. **Platform Dependency**: Uses macOS `open` command - platform-specific implementation would be needed for Linux/Windows support
|
119
|
+
4. **Error Handling**: Custom `OpenGemdocs::Error` class for consistent error reporting
|
120
|
+
|
121
|
+
### CLI Entry Points
|
122
|
+
- **`exe/open-gem-docs`**: Full-featured CLI with option parsing (--local, --version, etc.)
|
123
|
+
- **`exe/open-local-docs`**: Convenience wrapper that always uses local documentation
|
124
|
+
- **`exe/open-gem-docs-mcp`**: MCP server for TCP connections (default port 6789)
|
125
|
+
- **`exe/open-gem-docs-mcp-stdio`**: MCP server for stdio mode (Claude Desktop integration)
|
126
|
+
|
127
|
+
## Important Considerations
|
128
|
+
|
129
|
+
- The gem is signed with a certificate in `certs/mrinterweb.pem` - ensure this is present when building releases
|
130
|
+
- Requires Ruby >= 3.1.0
|
131
|
+
- The test suite needs expansion - currently only has placeholder tests
|
132
|
+
- When modifying CLI behavior, update all relevant executables if needed
|
133
|
+
- The Yard server runs on port 8808 by default
|
134
|
+
- MCP server runs on port 6789 by default (configurable via --port)
|
135
|
+
- MCP stdio mode is designed for Claude Desktop integration via the MCP protocol
|
136
|
+
- The MCP server automatically manages the Yard server lifecycle as needed
|
data/README.md
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
# OpenGemdocs
|
2
2
|
|
3
|
-
This
|
3
|
+
This gem makes accessing ruby gem documentation easy for users with a CLI tool and AI agents with a MCP server.
|
4
|
+
|
5
|
+
There are two documentation sources this gem supports.
|
4
6
|
|
5
7
|
1. local gems served with the yard gem via `yard server --gems` or `yard server --gemfile` accessible at http://localhost:8808.
|
6
8
|
2. [https://gemdocs.org](https://gemdocs.org) - a good ruby gem documentation host
|
@@ -24,7 +26,7 @@ If bundler is not being used to manage dependencies, install the gem by executin
|
|
24
26
|
gem install open_gemdocs
|
25
27
|
```
|
26
28
|
|
27
|
-
## Usage
|
29
|
+
## CLI Usage
|
28
30
|
|
29
31
|
Currently, this only works on Macs because of the `open` command. It opens the documentation for a gem in your default web browser.
|
30
32
|
|
@@ -69,6 +71,55 @@ Example using the `open-local-docs` command:
|
|
69
71
|
open-local-docs rspec
|
70
72
|
```
|
71
73
|
|
74
|
+
## MCP Server
|
75
|
+
|
76
|
+
The gem includes an MCP (Model Context Protocol) server that allows AI assistants to programmatically access Ruby gem documentation. The MCP server manages a local Yard documentation server and provides tools for searching and retrieving gem documentation.
|
77
|
+
|
78
|
+
### Starting the MCP Server
|
79
|
+
|
80
|
+
```bash
|
81
|
+
open-gem-docs-mcp
|
82
|
+
```
|
83
|
+
|
84
|
+
By default, the server runs on port 6789. You can specify a different port:
|
85
|
+
|
86
|
+
```bash
|
87
|
+
open-gem-docs-mcp --port 8080
|
88
|
+
```
|
89
|
+
|
90
|
+
### Available MCP Tools
|
91
|
+
|
92
|
+
The MCP server provides the following tools:
|
93
|
+
|
94
|
+
- **search_gems** - Search for installed Ruby gems by name
|
95
|
+
- **get_gem_info** - Get detailed information about a specific gem
|
96
|
+
- **start_yard_server** - Start the Yard documentation server
|
97
|
+
- **stop_yard_server** - Stop the Yard documentation server
|
98
|
+
- **get_yard_server_status** - Check if the Yard server is running
|
99
|
+
- **get_gem_documentation_url** - Get the local documentation URL for a gem
|
100
|
+
- **fetch_gem_docs** - Fetch documentation content from the Yard server
|
101
|
+
|
102
|
+
### Using with Claude Code
|
103
|
+
|
104
|
+
```
|
105
|
+
claude mcp add open-gem-docs -- open-gem-docs-mcp-stdio
|
106
|
+
```
|
107
|
+
|
108
|
+
### Using with Claude Desktop
|
109
|
+
|
110
|
+
To use the MCP server with Claude Desktop, add the following to your Claude Desktop configuration:
|
111
|
+
|
112
|
+
```json
|
113
|
+
{
|
114
|
+
"mcpServers": {
|
115
|
+
"open_gemdocs": {
|
116
|
+
"command": "open-gem-docs-mcp",
|
117
|
+
"args": ["--port", "6789"]
|
118
|
+
}
|
119
|
+
}
|
120
|
+
}
|
121
|
+
```
|
122
|
+
|
72
123
|
## Development
|
73
124
|
|
74
125
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
@@ -0,0 +1 @@
|
|
1
|
+
32e9cdcb7c3c463dbff38e38fb53e0a51eb2cf8e80250420e40129d32911b9fce015ef3cc0266f1773f0cf39ff644a16c662068860c43d4f0d210688df4dd8f8
|
data/exe/document-bundle
ADDED
data/exe/open-gem-docs
CHANGED
@@ -1,34 +1,34 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
8
|
-
require_relative File.join(
|
4
|
+
require "uri"
|
5
|
+
require "net/http"
|
6
|
+
require "json"
|
7
|
+
require "optparse"
|
8
|
+
require_relative File.join("..", "lib", "open_gemdocs")
|
9
9
|
|
10
10
|
options = {}
|
11
11
|
|
12
12
|
OptionParser.new do |opts|
|
13
|
-
opts.banner =
|
13
|
+
opts.banner = "Usage: open-gem-docs [options] <gem_name>"
|
14
14
|
|
15
|
-
opts.on(
|
15
|
+
opts.on("--local", "Use local documentation") do
|
16
16
|
options[:local] = true
|
17
17
|
end
|
18
|
-
opts.on(
|
18
|
+
opts.on("-v", "--version VERSION", "Specify the version") do |version|
|
19
19
|
options[:version] = version
|
20
20
|
end
|
21
21
|
|
22
|
-
opts.on(
|
22
|
+
opts.on("--latest", "Use the latest version") do
|
23
23
|
options[:latest] = true
|
24
24
|
end
|
25
25
|
|
26
|
-
opts.on(
|
26
|
+
opts.on("-h", "--help", "Display this help message") do
|
27
27
|
puts opts
|
28
28
|
exit
|
29
29
|
end
|
30
30
|
|
31
|
-
opts.on(
|
31
|
+
opts.on("-s", "--stop", "stops the yard server") do
|
32
32
|
OpenGemdocs::Yard.stop_server
|
33
33
|
exit
|
34
34
|
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "optparse"
|
5
|
+
require_relative "../lib/open_gemdocs/version"
|
6
|
+
require_relative "../lib/open_gemdocs/mcp/server"
|
7
|
+
require_relative "../lib/open_gemdocs/mcp/handlers"
|
8
|
+
require_relative "../lib/open_gemdocs/mcp/tools"
|
9
|
+
|
10
|
+
options = { port: 6789 }
|
11
|
+
|
12
|
+
OptionParser.new do |opts|
|
13
|
+
opts.banner = "Usage: open-gem-docs-mcp [options]"
|
14
|
+
|
15
|
+
opts.on("-p", "--port PORT", Integer, "Port to run MCP server on (default: 6789)") do |p|
|
16
|
+
options[:port] = p
|
17
|
+
end
|
18
|
+
|
19
|
+
opts.on("-v", "--version", "Show version") do
|
20
|
+
puts "open_gemdocs MCP server v#{OpenGemdocs::VERSION}"
|
21
|
+
exit
|
22
|
+
end
|
23
|
+
|
24
|
+
opts.on("-h", "--help", "Show this help message") do
|
25
|
+
puts opts
|
26
|
+
puts
|
27
|
+
puts "This MCP server provides tools for accessing Ruby gem documentation."
|
28
|
+
puts "It integrates with the Yard documentation server to provide local docs."
|
29
|
+
puts
|
30
|
+
puts "Available MCP tools:"
|
31
|
+
puts " - search_gems: Search for installed Ruby gems"
|
32
|
+
puts " - get_gem_info: Get detailed information about a gem"
|
33
|
+
puts " - start_yard_server: Start the Yard documentation server"
|
34
|
+
puts " - stop_yard_server: Stop the Yard documentation server"
|
35
|
+
puts " - get_yard_server_status: Check Yard server status"
|
36
|
+
puts " - get_gem_documentation_url: Get the documentation URL for a gem"
|
37
|
+
puts " - fetch_gem_docs: Fetch documentation content from Yard server"
|
38
|
+
exit
|
39
|
+
end
|
40
|
+
end.parse!
|
41
|
+
|
42
|
+
begin
|
43
|
+
server = OpenGemdocs::MCP::Server.new(port: options[:port])
|
44
|
+
server.start
|
45
|
+
rescue Interrupt
|
46
|
+
puts "\nShutting down..."
|
47
|
+
exit 0
|
48
|
+
rescue StandardError => e
|
49
|
+
warn "Error: #{e.message}"
|
50
|
+
warn e.backtrace if ENV["DEBUG"]
|
51
|
+
exit 1
|
52
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "json"
|
5
|
+
require_relative "../lib/open_gemdocs/version"
|
6
|
+
require_relative "../lib/open_gemdocs/mcp/handlers"
|
7
|
+
require_relative "../lib/open_gemdocs/mcp/tools"
|
8
|
+
|
9
|
+
# MCP stdio server for Claude Desktop
|
10
|
+
class MCPStdioServer
|
11
|
+
def initialize
|
12
|
+
@handlers = OpenGemdocs::MCP::Handlers.new
|
13
|
+
STDERR.puts "open_gemdocs MCP server v#{OpenGemdocs::VERSION} (stdio mode)"
|
14
|
+
end
|
15
|
+
|
16
|
+
def run
|
17
|
+
STDERR.puts "MCP server started in stdio mode"
|
18
|
+
|
19
|
+
loop do
|
20
|
+
begin
|
21
|
+
# Read line from stdin
|
22
|
+
line = STDIN.gets
|
23
|
+
break if line.nil? # EOF
|
24
|
+
|
25
|
+
next if line.strip.empty?
|
26
|
+
|
27
|
+
# Parse JSON-RPC request
|
28
|
+
request = JSON.parse(line.strip)
|
29
|
+
|
30
|
+
# Handle the request
|
31
|
+
response = @handlers.handle(request)
|
32
|
+
|
33
|
+
# Write response to stdout if there is one
|
34
|
+
if response
|
35
|
+
STDOUT.puts JSON.generate(response)
|
36
|
+
STDOUT.flush
|
37
|
+
end
|
38
|
+
rescue JSON::ParserError => e
|
39
|
+
error_response = {
|
40
|
+
jsonrpc: "2.0",
|
41
|
+
error: {
|
42
|
+
code: -32700,
|
43
|
+
message: "Parse error",
|
44
|
+
data: e.message
|
45
|
+
}
|
46
|
+
}
|
47
|
+
STDOUT.puts JSON.generate(error_response)
|
48
|
+
STDOUT.flush
|
49
|
+
rescue StandardError => e
|
50
|
+
STDERR.puts "Error: #{e.message}"
|
51
|
+
STDERR.puts e.backtrace if ENV["DEBUG"]
|
52
|
+
|
53
|
+
error_response = {
|
54
|
+
jsonrpc: "2.0",
|
55
|
+
error: {
|
56
|
+
code: -32603,
|
57
|
+
message: "Internal error",
|
58
|
+
data: e.message
|
59
|
+
}
|
60
|
+
}
|
61
|
+
STDOUT.puts JSON.generate(error_response)
|
62
|
+
STDOUT.flush
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
STDERR.puts "MCP server shutting down"
|
67
|
+
rescue Interrupt
|
68
|
+
STDERR.puts "\nShutting down MCP server..."
|
69
|
+
OpenGemdocs::Yard.stop_server
|
70
|
+
exit 0
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# Run the server
|
75
|
+
server = MCPStdioServer.new
|
76
|
+
server.run
|
data/lib/open_gemdocs/browser.rb
CHANGED
@@ -6,7 +6,7 @@ module OpenGemdocs
|
|
6
6
|
|
7
7
|
def initialize(gem_name:, version: nil, use_latest: false)
|
8
8
|
@gem_name = gem_name
|
9
|
-
raise ArgumentError,
|
9
|
+
raise ArgumentError, "Gem name is required" if gem_name.nil? || gem_name.empty?
|
10
10
|
|
11
11
|
@version = version
|
12
12
|
@use_latest = use_latest
|
@@ -15,7 +15,7 @@ module OpenGemdocs
|
|
15
15
|
def resolve_version
|
16
16
|
return version if version
|
17
17
|
|
18
|
-
if !use_latest && File.exist?(
|
18
|
+
if !use_latest && File.exist?("Gemfile.lock")
|
19
19
|
@version = check_bundle_version
|
20
20
|
if @version
|
21
21
|
puts "Using version from Gemfile.lock: #{version}"
|
@@ -25,27 +25,27 @@ module OpenGemdocs
|
|
25
25
|
|
26
26
|
@use_latest = true
|
27
27
|
|
28
|
-
puts
|
28
|
+
puts "No version specified, using latest version"
|
29
29
|
end
|
30
30
|
|
31
31
|
def open_browser
|
32
32
|
resolve_version
|
33
|
-
raise Error,
|
33
|
+
raise Error, "No version URL found" unless version_url
|
34
34
|
|
35
|
-
version_str = version ? "@v#{version}" :
|
36
|
-
latest_str = use_latest ?
|
35
|
+
version_str = version ? "@v#{version}" : ""
|
36
|
+
latest_str = use_latest ? " (latest)" : ""
|
37
37
|
puts "Fetching gem documentation for #{gem_name}#{version_str}#{latest_str}..."
|
38
38
|
# open is a macOS command to open a URL in the default browser
|
39
|
-
raise Error,
|
39
|
+
raise Error, "Could not resolve URL" if version_url.nil?
|
40
40
|
|
41
|
-
`open "#{version_url.sub(
|
41
|
+
`open "#{version_url.sub("production.", "")}"`
|
42
42
|
end
|
43
43
|
|
44
44
|
def version_url
|
45
45
|
if use_latest
|
46
|
-
version_data.last[
|
46
|
+
version_data.last["url"]
|
47
47
|
else
|
48
|
-
version_data.detect { |row| row[
|
48
|
+
version_data.detect { |row| row["version"] == version }&.fetch("url")
|
49
49
|
end
|
50
50
|
end
|
51
51
|
|
@@ -57,11 +57,9 @@ module OpenGemdocs
|
|
57
57
|
@version_data ||= begin
|
58
58
|
uri = URI("https://gemdocs.org/gems/#{ARGV[0]}/versions.json")
|
59
59
|
res = Net::HTTP.get_response(uri)
|
60
|
-
unless res.is_a?(Net::HTTPSuccess)
|
61
|
-
raise Error, "HTTP request failed to uri: #{uri} -- #{res.code} #{res.message}"
|
62
|
-
end
|
60
|
+
raise Error, "HTTP request failed to uri: #{uri} -- #{res.code} #{res.message}" unless res.is_a?(Net::HTTPSuccess)
|
63
61
|
|
64
|
-
JSON.parse(res.body)[
|
62
|
+
JSON.parse(res.body)["versions"]
|
65
63
|
end
|
66
64
|
end
|
67
65
|
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "tools"
|
4
|
+
|
5
|
+
module OpenGemdocs
|
6
|
+
module MCP
|
7
|
+
class Handlers
|
8
|
+
def initialize
|
9
|
+
@tools = Tools.new
|
10
|
+
end
|
11
|
+
|
12
|
+
def handle(request)
|
13
|
+
method = request["method"]
|
14
|
+
id = request["id"]
|
15
|
+
|
16
|
+
case method
|
17
|
+
when "initialize"
|
18
|
+
handle_initialize(id)
|
19
|
+
when "initialized"
|
20
|
+
# Client notification, no response needed
|
21
|
+
nil
|
22
|
+
when "tools/list"
|
23
|
+
handle_tools_list(id)
|
24
|
+
when "tools/call"
|
25
|
+
handle_tool_call(id, request["params"])
|
26
|
+
when "ping"
|
27
|
+
{ "jsonrpc" => "2.0", "id" => id, "result" => {} }
|
28
|
+
else
|
29
|
+
error_response(id, -32_601, "Method not found: #{method}")
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def handle_initialize(id)
|
36
|
+
{
|
37
|
+
"jsonrpc" => "2.0",
|
38
|
+
"id" => id,
|
39
|
+
"result" => {
|
40
|
+
"protocolVersion" => "2024-11-05",
|
41
|
+
"capabilities" => {
|
42
|
+
"tools" => {},
|
43
|
+
"resources" => {}
|
44
|
+
},
|
45
|
+
"serverInfo" => {
|
46
|
+
"name" => "open_gemdocs_mcp",
|
47
|
+
"version" => OpenGemdocs::VERSION
|
48
|
+
}
|
49
|
+
}
|
50
|
+
}
|
51
|
+
end
|
52
|
+
|
53
|
+
def handle_tools_list(id)
|
54
|
+
{
|
55
|
+
"jsonrpc" => "2.0",
|
56
|
+
"id" => id,
|
57
|
+
"result" => {
|
58
|
+
"tools" => @tools.list
|
59
|
+
}
|
60
|
+
}
|
61
|
+
end
|
62
|
+
|
63
|
+
def handle_tool_call(id, params)
|
64
|
+
tool_name = params["name"]
|
65
|
+
arguments = params["arguments"] || {}
|
66
|
+
|
67
|
+
begin
|
68
|
+
result = @tools.call(tool_name, arguments)
|
69
|
+
|
70
|
+
{
|
71
|
+
"jsonrpc" => "2.0",
|
72
|
+
"id" => id,
|
73
|
+
"result" => result
|
74
|
+
}
|
75
|
+
rescue StandardError => e
|
76
|
+
error_response(id, -32_603, "Tool execution error: #{e.message}")
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def error_response(id, code, message)
|
81
|
+
{
|
82
|
+
"jsonrpc" => "2.0",
|
83
|
+
"id" => id,
|
84
|
+
"error" => {
|
85
|
+
"code" => code,
|
86
|
+
"message" => message
|
87
|
+
}
|
88
|
+
}
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|