rails-mcp 0.1.1 → 0.1.3

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: bb0683d35c50e882a06c6eaf4b87a1dc9d159210ceb749390eeadd91d8d63167
4
- data.tar.gz: cb36847aa01cfa2a466598d481300d82d8ef226cdfc735f4bfa7c9cf52e2424a
3
+ metadata.gz: 9abbdcbddd03422c13399b75c6f3e45a360f349b0ea409b6c5aa2466aed79ef9
4
+ data.tar.gz: 2171f3dba98480579cc725e7ad7cdd558cd06d53e0ec3f2fe2fea1e10fb2270b
5
5
  SHA512:
6
- metadata.gz: 2f26054cabebf6b4d475dfcc134b02a50b7492111a619fb9c9c7a4b3a666f966fa77b0521a977242cb729dc5afd3ab3d5545b051281500567b8bb8365c85e5e9
7
- data.tar.gz: 58312fa76044c7285b72bedee876c6118593282060b0160698b8f6a2e4f5392896b7c59dfc082dc823f3b8a3c1fdb29e4c5069dbe7050abd6ab9cfaf73f78bcb
6
+ metadata.gz: 812025d7923995691c0c93236934b0a67df6b4c90ed2e65b64778d32d20740b64d73e4013165859ea6141de98036a75498702c56c690d46475865518f3b90753
7
+ data.tar.gz: faaf14ad99d8cb2789081071a1d71f0ca050b373f73d2837711482b9a3f4106aa69dd116ed41d177dc26d0fbfc6a5879e25f42f97c6751ccb5977099bf403467
data/README.md CHANGED
@@ -143,6 +143,45 @@ curl -X POST "http://localhost:3001/mcp/rpc" \
143
143
  }'
144
144
  ```
145
145
 
146
+ ## Optional: Client Verification
147
+
148
+ If you want a second layer of defense beyond environment-scoped mounting and network gating, enable client verification when constructing the server. When enabled, every request must carry an `X-Rails-Mcp-Token` header whose value matches `ENV["RAILS_MCP_TOKEN"]` (minimum 8 characters); otherwise the server responds `401 Unauthorized`.
149
+
150
+ This deliberately uses a custom header (not `Authorization: Bearer`) and returns no `WWW-Authenticate` so it stays off the standard MCP/OAuth code path — important when the host Rails app already exposes a separate, product-facing MCP server with DCR / well-known discovery.
151
+
152
+ ```ruby
153
+ mount RailsMcp::MCP::Server.new(use_client_verification: true) => "/mcp"
154
+ ```
155
+
156
+ Set the token in the host environment:
157
+
158
+ ```bash
159
+ export RAILS_MCP_TOKEN="<at-least-8-char-secret>"
160
+ ```
161
+
162
+ Claude Code:
163
+
164
+ ```bash
165
+ claude mcp add rails-mcp --transport http \
166
+ --header "X-Rails-Mcp-Token: $RAILS_MCP_TOKEN" \
167
+ http://localhost:3001/mcp/rpc
168
+ ```
169
+
170
+ Cursor (`.cursor/mcp.json`):
171
+
172
+ ```json
173
+ {
174
+ "mcpServers": {
175
+ "rails-mcp": {
176
+ "url": "http://localhost:3001/mcp/rpc",
177
+ "headers": {
178
+ "X-Rails-Mcp-Token": "<at-least-8-char-secret>"
179
+ }
180
+ }
181
+ }
182
+ }
183
+ ```
184
+
146
185
  ## Testing
147
186
 
148
187
  Run the test suite:
@@ -9,7 +9,11 @@ module RailsMcp
9
9
  # Minimal MCP-over-HTTP (JSON-RPC) server.
10
10
  # Single-session, single-process demo: fine for local/dev usage.
11
11
  class Server
12
- def initialize
12
+ VERIFICATION_HEADER = "HTTP_X_RAILS_MCP_TOKEN"
13
+ MIN_TOKEN_LENGTH = 8
14
+
15
+ def initialize(use_client_verification: false)
16
+ @use_client_verification = use_client_verification
13
17
  @tools = [
14
18
  {
15
19
  "name" => "evaluate_ruby_code",
@@ -31,6 +35,10 @@ module RailsMcp
31
35
  def call(env)
32
36
  req = Rack::Request.new(env)
33
37
 
38
+ if @use_client_verification && !verified?(env)
39
+ return [401, {"content-type" => "application/json"}, [JSON.generate({"error" => "Unauthorized"})]]
40
+ end
41
+
34
42
  case [req.request_method, req.path_info]
35
43
  when ["POST", "/rpc"] then handle_rpc(req)
36
44
  else
@@ -40,6 +48,17 @@ module RailsMcp
40
48
 
41
49
  private
42
50
 
51
+ # Checks a custom header against ENV["RAILS_MCP_TOKEN"]. Deliberately not
52
+ # `Authorization: Bearer` — that triggers DCR/well-known discovery in
53
+ # MCP clients and would collide with any product-facing MCP the host app
54
+ # already exposes. The 401 response intentionally omits WWW-Authenticate
55
+ # so OAuth-aware clients don't try to negotiate a token.
56
+ def verified?(env)
57
+ expected = ENV["RAILS_MCP_TOKEN"]
58
+ return false if expected.nil? || expected.length < MIN_TOKEN_LENGTH
59
+ env[VERIFICATION_HEADER] == expected
60
+ end
61
+
43
62
  def handle_rpc(req)
44
63
  payload = JSON.parse(req.body.read)
45
64
  id = payload["id"]
@@ -1,5 +1,5 @@
1
1
  # typed: strict
2
2
  module RailsMcp
3
- VERSION = "0.1.1"
3
+ VERSION = "0.1.3"
4
4
  end
5
5
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails-mcp
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Raja Jamwal
@@ -79,8 +79,9 @@ dependencies:
79
79
  - - ">="
80
80
  - !ruby/object:Gem::Version
81
81
  version: '0'
82
- description: Allows AI assistants to eval and verify rails/ruby code changes at lighting-speed
83
- access without the need restart server.
82
+ description: Lightweight gem, tested in huge Rails codebases (20k+ Ruby files). Allows
83
+ AI assistants to eval and verify rails/ruby code changes at lighting-speed access
84
+ without the need restart server.
84
85
  email:
85
86
  - linux.experi@gmail.com
86
87
  executables: []