rails-mcp 0.1.2 → 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 +4 -4
- data/README.md +39 -0
- data/lib/rails_mcp/mcp/server.rb +20 -1
- data/lib/rails_mcp/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9abbdcbddd03422c13399b75c6f3e45a360f349b0ea409b6c5aa2466aed79ef9
|
|
4
|
+
data.tar.gz: 2171f3dba98480579cc725e7ad7cdd558cd06d53e0ec3f2fe2fea1e10fb2270b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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:
|
data/lib/rails_mcp/mcp/server.rb
CHANGED
|
@@ -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
|
-
|
|
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"]
|
data/lib/rails_mcp/version.rb
CHANGED