rails-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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: ba176e0f681ca2aded9b387f58c157431daba9643297cc455ddfba82757bd4cd
4
+ data.tar.gz: 23b82ff6a767507ffbe990ea84a0632a5d8528b0d53ad34ff68942068f306a80
5
+ SHA512:
6
+ metadata.gz: 49aebae4786a931d12b49da05884261f2aa20d81412056aa234833709749f69296b37e3ef116c0326666b3f69395a0a3d64ee00b0accac4b98ddde357c2b43c6
7
+ data.tar.gz: f5f1cc5fdbb077df43b792ffbe2e4b515563da28ea97f60dd7d94eeb3391fc5690b18fb55f5732fd093f323f68d898906126db7284e309ff33b0826b1e74c88b
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
data/README.md ADDED
@@ -0,0 +1,175 @@
1
+ # rails-mcp
2
+
3
+ > **Setting this up?** Point your coding agent (Cursor, Claude Code, etc.) at [`llms.txt`](./llms.txt) and ask it to self-configure rails-mcp in your project.
4
+
5
+ A Ruby gem that provides AI assistants with ruby code execution capabilities within the context of existing running application server. Think of it giving AI assistant lighting-speed access to ruby console without the need to write script, reload or restart.
6
+
7
+ Works with Rails, Sinatra, Hanami, Roda, and any other Rack-based framework. The code is executed in your application's context for debugging and investigation.
8
+
9
+ <img src="docs/assets/screen.gif" alt="rails console mcp in cursor" width="400"/>
10
+
11
+ <a href="https://youtu.be/lhhOGq6l42s?si=gE4jfwow2aqAtvvk">YouTube Link</a>
12
+
13
+ ## Used at
14
+
15
+ <a href="https://www.apollo.io/"><img src="docs/assets/apollo-logo.jpg" alt="Apollo.io" width="100"/></a>
16
+
17
+ Used at Apollo.io against a Rails codebase with 20k+ Ruby files.
18
+
19
+ ## Use cases
20
+
21
+ 1. Learn a new codebase or code areas quickly. With your AI client and a running server, you can ask it to research while executing snippets from your actual application code. It effectively acts as an in-loop code-verification block.
22
+ 2. Perform quick, preliminary investigations of customer escalations using a read-only copy of the production environment. It can execute your application code, locate models, and run relevant class methods or code paths from the codebase to do preliminary root-cause analysis (RCA). Even better if your application uses an event-sourcing framework (i.e., change logs). The AI client, together with the code-execution capabilities via rails-mcp, can deliver fast preliminary RCAs.
23
+ 3. Use it for quick data analytics and export reports as CSV.
24
+
25
+ ## Installation
26
+
27
+ Add this line to your application's Gemfile:
28
+
29
+ ```ruby
30
+ gem "rails-mcp"
31
+ ```
32
+
33
+ Or install locally for development:
34
+
35
+ ```bash
36
+ bundle install
37
+ ```
38
+
39
+ ## Usage
40
+
41
+ ### Mounting the MCP Server
42
+
43
+ **Rails** (`config/routes.rb`):
44
+ ```ruby
45
+ require "rails_mcp/mcp/server"
46
+
47
+ Rails.application.routes.draw do
48
+ mount RailsMcp::MCP::Server.new => "/mcp"
49
+ end
50
+ ```
51
+
52
+ **Rack** (`config.ru`):
53
+ ```ruby
54
+ require "rails_mcp"
55
+ require "rails_mcp/mcp/server"
56
+
57
+ map "/mcp" do
58
+ run RailsMcp::MCP::Server.new
59
+ end
60
+ ```
61
+
62
+ **Sinatra**:
63
+ ```ruby
64
+ require "rails_mcp/mcp/server"
65
+
66
+ mount RailsMcp::MCP::Server.new, at: "/mcp"
67
+ ```
68
+
69
+ ### Starting the Server
70
+
71
+ ```bash
72
+ # Standalone with Rackup
73
+ bundle exec rackup -p 9292
74
+
75
+ # With Rails
76
+ bundle exec rails server
77
+ ```
78
+
79
+ ### Environment-scoped mounting
80
+
81
+ This gem ships without authentication — the MCP endpoint will accept any request that reaches it. You are responsible for ensuring it is only mounted where appropriate. A typical Rails setup gates it on environment:
82
+
83
+ ```ruby
84
+ Rails.application.routes.draw do
85
+ mount RailsMcp::MCP::Server.new => "/mcp" if Rails.env.development?
86
+ end
87
+ ```
88
+
89
+ For staging or production access, combine that with network-level restrictions (firewall, VPC, SSH port-forward, VPN) so the endpoint is never reachable from the open internet.
90
+
91
+ ## MCP Protocol
92
+
93
+ ### Endpoint
94
+
95
+ The MCP server exposes a single JSON-RPC endpoint:
96
+
97
+ - **POST /mcp/rpc** - JSON-RPC request and response
98
+
99
+ ### Available Tools
100
+
101
+ **evaluate_ruby_code**
102
+ - Description: Evaluates Ruby code and returns the result with captured stdout/stderr
103
+ - Parameters:
104
+ - `code` (string, required): Ruby code to execute
105
+
106
+ ## Connecting AI Assistants
107
+
108
+ ### Cursor/ Claude Desktop
109
+
110
+ Add to your MCP client configuration (`.cursor/mcp.json` for Cursor or `claude_desktop_config.json` for Claude Desktop):
111
+
112
+ ```json
113
+ {
114
+ "mcpServers": {
115
+ "rails-mcp": {
116
+ "url": "http://localhost:3001/mcp/rpc"
117
+ }
118
+ }
119
+ }
120
+ ```
121
+
122
+ For Claude Code, add it from the command line:
123
+
124
+ ```bash
125
+ claude mcp add rails-mcp --transport http http://localhost:3001/mcp/rpc
126
+ ```
127
+
128
+ ![MCP integration in Cursor](docs/assets/mcp-in-cursor.png)
129
+
130
+ ### Other MCP Clients
131
+
132
+ Any MCP-compatible client can connect to the server by making JSON-RPC requests to the `/mcp/rpc` endpoint.
133
+
134
+ Example with curl:
135
+
136
+ ```bash
137
+ curl -X POST "http://localhost:3001/mcp/rpc" \
138
+ -H "Content-Type: application/json" \
139
+ -d '{
140
+ "jsonrpc": "2.0",
141
+ "id": 1,
142
+ "method": "tools/list"
143
+ }'
144
+ ```
145
+
146
+ ## Testing
147
+
148
+ Run the test suite:
149
+
150
+ ```bash
151
+ bundle exec rspec
152
+ ```
153
+
154
+ ## Security Warning
155
+
156
+ ⚠️ **This gem executes arbitrary Ruby code.**
157
+
158
+ **Important security considerations:**
159
+ - **No built-in authentication.** Gate the mount on environment (e.g., `if Rails.env.development?`) so the endpoint isn't exposed in production by accident
160
+ - Only use in development environments or secure, isolated production environments
161
+ - Rely on network-level restrictions (firewall, VPC, SSH port-forward, VPN) to limit access
162
+ - Consider running in a sandboxed or containerized environment
163
+ - Monitor and log all code execution requests
164
+
165
+ ## Concurrency Note
166
+
167
+ This gem uses global `$stdout/$stderr` redirection during evaluation, which can clash in multi-threaded servers. For production use with concurrency, consider:
168
+ - Running in a single worker/thread mode
169
+ - Isolating evaluation per request (e.g., via `fork`)
170
+ - Using a dedicated job worker for code execution
171
+
172
+ ## License
173
+
174
+ MIT License - see LICENSE file for details.
175
+
@@ -0,0 +1,38 @@
1
+ # typed: strict
2
+ require "stringio"
3
+
4
+ module RailsMcp
5
+ class Executor
6
+ # Evaluates Ruby code and captures stdout/stderr.
7
+ def self.eval(code)
8
+ code = code.to_s
9
+ raise ArgumentError, "code can't be blank" if code.strip.empty?
10
+
11
+ out, err = StringIO.new, StringIO.new
12
+ old_out, old_err = $stdout, $stderr
13
+ result = nil
14
+ error = nil
15
+
16
+ begin
17
+ $stdout, $stderr = out, err
18
+ result = TOPLEVEL_BINDING.eval(code)
19
+ rescue SyntaxError, StandardError => e
20
+ error = e
21
+ ensure
22
+ $stdout, $stderr = old_out, old_err
23
+ end
24
+
25
+ if error
26
+ backtrace = error.backtrace&.first(3)&.join("\n ")
27
+ return "#{error.class}: #{error.message}\n#{backtrace ? " #{backtrace}\n" : ""}"
28
+ end
29
+
30
+ parts = []
31
+ parts << "=> #{result.inspect}\n" unless result.nil?
32
+ parts << out.string unless out.string.empty?
33
+ parts << err.string unless err.string.empty?
34
+ parts.join
35
+ end
36
+ end
37
+ end
38
+
@@ -0,0 +1,85 @@
1
+ # frozen_string_literal: true
2
+ require "json"
3
+ require "rack"
4
+ require_relative "../version"
5
+ require_relative "../executor"
6
+
7
+ module RailsMcp
8
+ module MCP
9
+ # Minimal MCP-over-HTTP (JSON-RPC) server.
10
+ # Single-session, single-process demo: fine for local/dev usage.
11
+ class Server
12
+ def initialize
13
+ @tools = [
14
+ {
15
+ "name" => "evaluate_ruby_code",
16
+ "description" => "Evaluate the Ruby code in the context of the current application, returns the result of the code execution",
17
+ "inputSchema" => {
18
+ "type" => "object",
19
+ "properties" => {
20
+ "code" => {
21
+ "type" => "string",
22
+ "description" => "The Ruby code to evaluate, must be a valid Ruby expression or statement"
23
+ }
24
+ },
25
+ "required" => ["code"]
26
+ }
27
+ }
28
+ ]
29
+ end
30
+
31
+ def call(env)
32
+ req = Rack::Request.new(env)
33
+
34
+ case [req.request_method, req.path_info]
35
+ when ["POST", "/rpc"] then handle_rpc(req)
36
+ else
37
+ [404, {"content-type" => "text/plain"}, ["Not Found\n"]]
38
+ end
39
+ end
40
+
41
+ private
42
+
43
+ def handle_rpc(req)
44
+ payload = JSON.parse(req.body.read)
45
+ id = payload["id"]
46
+ method = payload["method"]
47
+
48
+ result =
49
+ case method
50
+ when "initialize"
51
+ {
52
+ "protocolVersion" => "2025-06-18",
53
+ "serverInfo" => { "name" => "rails_mcp", "version" => RailsMcp::VERSION },
54
+ "capabilities" => { "tools" => {} }
55
+ }
56
+
57
+ when "tools/list"
58
+ { "tools" => @tools }
59
+
60
+ when "tools/call"
61
+ name = payload.dig("params", "name")
62
+ args = payload.dig("params", "arguments") || {}
63
+
64
+ if name == "evaluate_ruby_code"
65
+ out = RailsMcp::Executor.eval(args["code"].to_s)
66
+ { "content" => [{ "type" => "text", "text" => out }] }
67
+ else
68
+ raise "Unknown tool: #{name}"
69
+ end
70
+
71
+ else
72
+ raise "Unknown method: #{method}"
73
+ end
74
+
75
+ # Return JSON-RPC response directly
76
+ response = { "jsonrpc" => "2.0", "id" => id, "result" => result }
77
+ [200, {"content-type" => "application/json"}, [JSON.generate(response)]]
78
+ rescue => e
79
+ response = { "jsonrpc" => "2.0", "id" => id, "error" => { "code" => -32601, "message" => e.message } }
80
+ [200, {"content-type" => "application/json"}, [JSON.generate(response)]]
81
+ end
82
+ end
83
+ end
84
+ end
85
+
@@ -0,0 +1,5 @@
1
+ # typed: strict
2
+ module RailsMcp
3
+ VERSION = "0.1.0"
4
+ end
5
+
data/lib/rails_mcp.rb ADDED
@@ -0,0 +1,7 @@
1
+ # typed: strict
2
+ require "rails_mcp/version"
3
+ require "rails_mcp/executor"
4
+
5
+ module RailsMcp
6
+ end
7
+
metadata ADDED
@@ -0,0 +1,117 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rails-mcp
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Raja Jamwal
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: rack
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '2.2'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: '2.2'
26
+ - !ruby/object:Gem::Dependency
27
+ name: rack-test
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '0'
40
+ - !ruby/object:Gem::Dependency
41
+ name: rspec
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '3.0'
47
+ type: :development
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '3.0'
54
+ - !ruby/object:Gem::Dependency
55
+ name: rackup
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ type: :development
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: '0'
68
+ - !ruby/object:Gem::Dependency
69
+ name: webrick
70
+ requirement: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ type: :development
76
+ prerelease: false
77
+ version_requirements: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
82
+ description: A Rack-based MCP server that enables AI assistants to execute Ruby code
83
+ via the Model Context Protocol.
84
+ email:
85
+ - linux.experi@gmail.com
86
+ executables: []
87
+ extensions: []
88
+ extra_rdoc_files: []
89
+ files:
90
+ - LICENSE
91
+ - README.md
92
+ - lib/rails_mcp.rb
93
+ - lib/rails_mcp/executor.rb
94
+ - lib/rails_mcp/mcp/server.rb
95
+ - lib/rails_mcp/version.rb
96
+ homepage: https://github.com/raja-jamwal/rails-mcp
97
+ licenses:
98
+ - MIT
99
+ metadata: {}
100
+ rdoc_options: []
101
+ require_paths:
102
+ - lib
103
+ required_ruby_version: !ruby/object:Gem::Requirement
104
+ requirements:
105
+ - - ">="
106
+ - !ruby/object:Gem::Version
107
+ version: 2.7.0
108
+ required_rubygems_version: !ruby/object:Gem::Requirement
109
+ requirements:
110
+ - - ">="
111
+ - !ruby/object:Gem::Version
112
+ version: '0'
113
+ requirements: []
114
+ rubygems_version: 3.7.2
115
+ specification_version: 4
116
+ summary: Model Context Protocol (MCP) server for Ruby code execution
117
+ test_files: []