rails-active-mcp 0.1.2 → 0.1.4

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: bec983e79b11a278a9f7c39de53d6eff389f4ebbd951e9a613ce313ea3a48ba2
4
- data.tar.gz: ed94322b6c2bb06cff349166dbdf4d95babeea80ac6ae2c355683c19c0dc682e
3
+ metadata.gz: 38778186d51ca223866b9cdf181cbe389957c840609934897547d11af69c150c
4
+ data.tar.gz: 9ed227e53b104de6e482428a37837b80dd0b30f01405d3abaab8e12c4e6175c8
5
5
  SHA512:
6
- metadata.gz: 2281c14e99c4f2ad588fe0b222e060cb0b04e9bf0b3b874c284d6f6d6db8757a91d46a1aba7a77f365fe45c518d3a9e9bc58e2e2fbd6738c167334adfd252436
7
- data.tar.gz: '0178374d4a7e8c365c582f8cc11ffce5c28d23b3ea8d0d35078cea47eaff5a3d316749ec28b7e724815e293c439b05c989be20187abed0f076d443463da4afbb'
6
+ metadata.gz: e80bc1548f85c52f88e766a273a7f6a3f4637a398b549a36dd65b756a4243a2d86511354324120938aabdd40c5427abe9be12169890b7745721847f6da2dbfa4
7
+ data.tar.gz: fd5511135a658f588d154526bbcbe1da8b2d75b7c13d3c73687aba726293555cbd1b3f38defbe8f51ea1ce33fef3c05b38fb82c7e1d8d8f9fb96f6e214d742b2
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Rails Active MCP
2
2
 
3
- A Ruby gem that provides secure Rails console access through Model Context Protocol (MCP) for AI agents and development tools like Warp Terminal. Built with a custom MCP server implementation for full control and flexibility.
3
+ A Ruby gem that provides secure Rails console access through Model Context Protocol (MCP) for AI agents and development tools like Claude Desktop, Warp Terminal, and other MCP clients. Built with a custom MCP server implementation for full control and flexibility.
4
4
 
5
5
  ## Features
6
6
 
@@ -51,6 +51,11 @@ RailsActiveMcp.configure do |config|
51
51
  config.default_timeout = 30
52
52
  config.max_results = 100
53
53
 
54
+ # Server configuration
55
+ config.server_mode = :stdio # :stdio for Claude Desktop, :http for web
56
+ config.server_host = 'localhost'
57
+ config.server_port = 3001
58
+
54
59
  # Model access control
55
60
  config.allowed_models = %w[User Post Comment] # Empty = all allowed
56
61
  config.blocked_models = %w[AdminUser Secret]
@@ -64,6 +69,10 @@ RailsActiveMcp.configure do |config|
64
69
  config.production_mode! # Very strict
65
70
  config.strict_mode! # Safe defaults
66
71
  config.permissive_mode! # Development friendly
72
+
73
+ # Server mode shortcuts
74
+ config.stdio_mode! # Set stdio mode for Claude Desktop
75
+ config.http_mode!(host: '0.0.0.0', port: 8080) # Set HTTP mode with custom host/port
67
76
  end
68
77
  ```
69
78
 
@@ -71,24 +80,37 @@ end
71
80
 
72
81
  You have several options for running the MCP server:
73
82
 
74
- ### Option 1: Rails-mounted (recommended for development)
83
+ ### Option 1: Use configured mode (recommended)
84
+
85
+ ```bash
86
+ $ bundle exec rails-active-mcp-server
87
+ ```
88
+
89
+ This will use the server mode configured in your initializer (`:stdio` by default). You can override the mode:
90
+
91
+ ```bash
92
+ $ bundle exec rails-active-mcp-server stdio # Force stdio mode
93
+ $ bundle exec rails-active-mcp-server http # Force HTTP mode
94
+ ```
95
+
96
+ ### Option 2: Rails-mounted (HTTP, good for development)
75
97
 
76
98
  ```bash
77
99
  $ rails server
78
100
  # MCP server available at http://localhost:3000/mcp
79
101
  ```
80
102
 
81
- ### Option 2: Standalone server
103
+ ### Option 3: Standalone HTTP server
82
104
 
83
105
  ```bash
84
- $ bundle exec rails-active-mcp-server
106
+ $ bundle exec rails-active-mcp-server http
85
107
  # Default: http://localhost:3001
86
108
 
87
109
  # Custom host/port
88
- $ bundle exec rails-active-mcp-server --host 0.0.0.0 --port 8080
110
+ $ bundle exec rails-active-mcp-server http --host 0.0.0.0 --port 8080
89
111
  ```
90
112
 
91
- ### Option 3: Using rackup
113
+ ### Option 4: Using rackup
92
114
 
93
115
  ```bash
94
116
  $ rackup mcp.ru -p 3001
@@ -98,7 +120,48 @@ $ rackup mcp.ru -p 3001
98
120
 
99
121
  ### With MCP Clients
100
122
 
101
- #### Warp Terminal Integration
123
+ #### Claude Desktop Integration (Preferred)
124
+
125
+ Add to your Claude Desktop configuration file:
126
+
127
+ **Location:**
128
+ - macOS/Linux: `~/.config/claude-desktop/claude_desktop_config.json`
129
+ - Windows: `%APPDATA%\Claude\claude_desktop_config.json`
130
+
131
+ ```json
132
+ {
133
+ "mcpServers": {
134
+ "rails-active-mcp": {
135
+ "command": "bundle",
136
+ "args": ["exec", "rails-active-mcp-server", "stdio"],
137
+ "cwd": "/path/to/your/rails/project"
138
+ }
139
+ }
140
+ }
141
+ ```
142
+
143
+ Or if installed globally:
144
+
145
+ ```json
146
+ {
147
+ "mcpServers": {
148
+ "rails-active-mcp": {
149
+ "command": "rails-active-mcp-server",
150
+ "args": ["stdio"],
151
+ "cwd": "/path/to/your/rails/project"
152
+ }
153
+ }
154
+ }
155
+ ```
156
+
157
+ Then in Claude Desktop, you can use prompts like:
158
+
159
+ - "Show me all users created in the last week"
160
+ - "What's the average order value?"
161
+ - "Check the User model schema and associations"
162
+ - "Analyze this code for safety: User.delete_all"
163
+
164
+ #### Warp Terminal Integration (HTTP)
102
165
 
103
166
  Add to your Warp MCP configuration:
104
167
 
@@ -120,16 +183,6 @@ Add to your Warp MCP configuration:
120
183
  }
121
184
  ```
122
185
 
123
- Then in Warp, you can use prompts like:
124
-
125
- - "Show me all users created in the last week"
126
- - "What's the average order value?"
127
- - "Check the User model schema and associations"
128
-
129
- #### Claude Desktop / Cline
130
-
131
- Use the same configuration format as above, pointing to your MCP server.
132
-
133
186
  #### Custom MCP Clients
134
187
 
135
188
  The server implements the MCP protocol (JSONRPC 2.0). Connect any MCP-compatible client to:
@@ -154,9 +207,11 @@ puts analysis[:estimated_risk] # => :critical
154
207
 
155
208
  ### Available MCP Tools
156
209
 
210
+ The Rails Active MCP server provides several built-in tools that will appear in Claude Desktop:
211
+
157
212
  #### `rails_console_execute`
158
213
 
159
- Execute Ruby code with safety checks:
214
+ Execute Ruby code with safety checks and timeout protection:
160
215
 
161
216
  ```json
162
217
  {
@@ -165,15 +220,65 @@ Execute Ruby code with safety checks:
165
220
  "name": "rails_console_execute",
166
221
  "arguments": {
167
222
  "code": "User.where(active: true).count",
168
- "timeout": 30
223
+ "timeout": 30,
224
+ "safe_mode": true
225
+ }
226
+ }
227
+ }
228
+ ```
229
+
230
+ #### `rails_model_info`
231
+
232
+ Get detailed information about Rails models:
233
+
234
+ ```json
235
+ {
236
+ "method": "tools/call",
237
+ "params": {
238
+ "name": "rails_model_info",
239
+ "arguments": {
240
+ "model_name": "User"
241
+ }
242
+ }
243
+ }
244
+ ```
245
+
246
+ #### `rails_safe_query`
247
+
248
+ Execute safe, read-only database queries:
249
+
250
+ ```json
251
+ {
252
+ "method": "tools/call",
253
+ "params": {
254
+ "name": "rails_safe_query",
255
+ "arguments": {
256
+ "query": "where(active: true).count",
257
+ "model": "User"
258
+ }
259
+ }
260
+ }
261
+ ```
262
+
263
+ #### `rails_dry_run`
264
+
265
+ Analyze Ruby code for safety without executing:
266
+
267
+ ```json
268
+ {
269
+ "method": "tools/call",
270
+ "params": {
271
+ "name": "rails_dry_run",
272
+ "arguments": {
273
+ "code": "User.delete_all"
169
274
  }
170
275
  }
171
276
  }
172
277
  ```
173
278
 
174
- #### Additional Tools
279
+ #### Adding Custom Tools
175
280
 
176
- The custom server includes built-in support for the main console execute tool. You can extend the server with additional tools by modifying the `McpServer` class in `lib/rails_active_mcp/mcp_server.rb`:
281
+ You can extend the server with additional tools by modifying the `McpServer` class in `lib/rails_active_mcp/mcp_server.rb` or `lib/rails_active_mcp/stdio_server.rb`:
177
282
 
178
283
  ```ruby
179
284
  def register_default_tools
data/docs/DEBUGGING.md ADDED
@@ -0,0 +1,313 @@
1
+ # Rails Active MCP Debugging Guide
2
+
3
+ This guide covers debugging and troubleshooting for the Rails Active MCP server, following the [MCP debugging best practices](https://modelcontextprotocol.io/docs/tools/debugging).
4
+
5
+ ## Quick Debug Commands
6
+
7
+ ```bash
8
+ # Test with MCP Inspector (recommended)
9
+ bin/debug-mcp-server --mode inspector
10
+
11
+ # Enable debug logging
12
+ RAILS_MCP_DEBUG=1 bundle exec rails-active-mcp-server stdio
13
+
14
+ # View recent logs
15
+ bin/debug-mcp-server --mode logs
16
+
17
+ # Basic connectivity test
18
+ bin/debug-mcp-server --mode test
19
+ ```
20
+
21
+ ## Debug Tools Overview
22
+
23
+ ### 1. MCP Inspector (Interactive Testing)
24
+
25
+ The MCP Inspector provides the best debugging experience for MCP servers:
26
+
27
+ ```bash
28
+ # Launch inspector connected to your Rails MCP server
29
+ bin/debug-mcp-server --mode inspector
30
+
31
+ # Or manually:
32
+ npx @modelcontextprotocol/inspector bundle exec rails-active-mcp-server stdio
33
+ ```
34
+
35
+ The Inspector provides:
36
+ - ✅ Interactive tool testing
37
+ - ✅ Real-time message inspection
38
+ - ✅ Error visualization
39
+ - ✅ Request/response history
40
+ - ✅ Server capability discovery
41
+
42
+ ### 2. Debug Logging
43
+
44
+ Enable detailed logging with the `RAILS_MCP_DEBUG` environment variable:
45
+
46
+ ```bash
47
+ RAILS_MCP_DEBUG=1 bundle exec rails-active-mcp-server stdio
48
+ ```
49
+
50
+ This enables:
51
+ - Request/response logging to stderr
52
+ - Tool execution timing
53
+ - Detailed error stack traces
54
+ - JSON-RPC message debugging
55
+
56
+ ### 3. Claude Desktop Integration Debugging
57
+
58
+ #### Checking Server Status in Claude Desktop
59
+
60
+ 1. Click the 🔌 icon to view connected servers
61
+ 2. Click the "Search and tools" 🔍 icon to view available tools
62
+ 3. Look for these Rails Active MCP tools:
63
+ - `rails_console_execute`
64
+ - `rails_model_info`
65
+ - `rails_safe_query`
66
+ - `rails_dry_run`
67
+
68
+ #### Viewing Claude Desktop Logs
69
+
70
+ ```bash
71
+ # macOS
72
+ tail -f ~/Library/Logs/Claude/mcp*.log
73
+
74
+ # Alternative locations
75
+ ls ~/Library/Logs/Claude/
76
+ ```
77
+
78
+ The logs show:
79
+ - Server connection events
80
+ - Configuration issues
81
+ - Runtime errors
82
+ - Tool execution logs
83
+
84
+ #### Using Chrome DevTools in Claude Desktop
85
+
86
+ 1. Enable developer tools:
87
+ ```bash
88
+ echo '{"allowDevTools": true}' > ~/Library/Application\ Support/Claude/developer_settings.json
89
+ ```
90
+
91
+ 2. Open DevTools: `Command-Option-Shift-i`
92
+
93
+ 3. Use Console and Network panels to inspect:
94
+ - Client-side errors
95
+ - Message payloads
96
+ - Connection timing
97
+
98
+ ## Common Issues and Solutions
99
+
100
+ ### 1. Working Directory Issues
101
+
102
+ **Problem**: Server can't find Rails environment or files.
103
+
104
+ **Solution**: Always use absolute paths in Claude Desktop config:
105
+
106
+ ```json
107
+ {
108
+ "mcpServers": {
109
+ "rails-active-mcp": {
110
+ "command": "bundle",
111
+ "args": ["exec", "rails-active-mcp-server", "stdio"],
112
+ "cwd": "/absolute/path/to/your/rails/project"
113
+ }
114
+ }
115
+ }
116
+ ```
117
+
118
+ ### 2. Environment Variables
119
+
120
+ **Problem**: Rails environment or API keys not available.
121
+
122
+ **Solution**: Specify environment variables in config:
123
+
124
+ ```json
125
+ {
126
+ "mcpServers": {
127
+ "rails-active-mcp": {
128
+ "command": "bundle",
129
+ "args": ["exec", "rails-active-mcp-server", "stdio"],
130
+ "cwd": "/path/to/rails/project",
131
+ "env": {
132
+ "RAILS_ENV": "development",
133
+ "RAILS_MCP_DEBUG": "1"
134
+ }
135
+ }
136
+ }
137
+ }
138
+ ```
139
+
140
+ ### 3. Server Initialization Problems
141
+
142
+ **Common initialization issues:**
143
+
144
+ 1. **Path Issues**
145
+ ```bash
146
+ # Test the command directly
147
+ cd /path/to/rails/project
148
+ bundle exec rails-active-mcp-server stdio
149
+ ```
150
+
151
+ 2. **Rails Environment Issues**
152
+ ```bash
153
+ # Verify Rails loads
154
+ cd /path/to/rails/project
155
+ bundle exec rails runner "puts 'Rails loaded successfully'"
156
+ ```
157
+
158
+ 3. **Permission Problems**
159
+ ```bash
160
+ # Check file permissions
161
+ ls -la exe/rails-active-mcp-server
162
+ chmod +x exe/rails-active-mcp-server
163
+ ```
164
+
165
+ ### 4. Connection Problems
166
+
167
+ **Problem**: Claude Desktop can't connect to server.
168
+
169
+ **Debug steps:**
170
+ 1. Check Claude Desktop logs for errors
171
+ 2. Test with MCP Inspector: `bin/debug-mcp-server --mode inspector`
172
+ 3. Verify server process starts: `ps aux | grep rails-active-mcp`
173
+ 4. Test basic JSON-RPC response:
174
+ ```bash
175
+ echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"test","version":"1.0.0"}}}' | bundle exec rails-active-mcp-server stdio
176
+ ```
177
+
178
+ ## Logging Implementation
179
+
180
+ ### Server-Side Logging
181
+
182
+ The Rails Active MCP server implements comprehensive logging:
183
+
184
+ ```ruby
185
+ # Logs to stderr (captured by Claude Desktop)
186
+ @logger = Logger.new(STDERR)
187
+ @logger.level = ENV['RAILS_MCP_DEBUG'] ? Logger::DEBUG : Logger::ERROR
188
+
189
+ # MCP log notifications (sent to client)
190
+ def send_log_notification(level, message)
191
+ notification = {
192
+ jsonrpc: JSONRPC_VERSION,
193
+ method: 'notifications/message',
194
+ params: { level: level, data: message }
195
+ }
196
+ puts notification.to_json
197
+ STDOUT.flush
198
+ end
199
+ ```
200
+
201
+ ### Log Levels and Events
202
+
203
+ - **INFO**: Server startup, tool execution start/completion
204
+ - **ERROR**: Parse errors, tool execution failures, unexpected errors
205
+ - **DEBUG**: Request/response details, execution timing (when `RAILS_MCP_DEBUG=1`)
206
+
207
+ ### Important Events Logged
208
+
209
+ 1. **Initialization**: Server startup, tool registration
210
+ 2. **Tool Execution**: Start time, completion time, success/failure
211
+ 3. **Error Conditions**: Parse errors, execution failures, safety violations
212
+ 4. **Performance**: Execution timing, request processing
213
+
214
+ ## Testing Your Implementation
215
+
216
+ ### Basic Connectivity Test
217
+
218
+ ```bash
219
+ # Test initialize method
220
+ echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"test","version":"1.0.0"}}}' | bundle exec rails-active-mcp-server stdio
221
+ ```
222
+
223
+ Expected response:
224
+ ```json
225
+ {
226
+ "jsonrpc":"2.0",
227
+ "id":1,
228
+ "result": {
229
+ "protocolVersion":"2025-06-18",
230
+ "capabilities":{"tools":{},"resources":{}},
231
+ "serverInfo":{"name":"rails-active-mcp","version":"..."}
232
+ }
233
+ }
234
+ ```
235
+
236
+ ### Tools List Test
237
+
238
+ ```bash
239
+ # Test tools/list method
240
+ echo '{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}' | bundle exec rails-active-mcp-server stdio
241
+ ```
242
+
243
+ Should return all 4 Rails Active MCP tools.
244
+
245
+ ### Tool Execution Test
246
+
247
+ ```bash
248
+ # Test a simple tool call
249
+ echo '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"rails_dry_run","arguments":{"code":"puts \"Hello World\""}}}' | bundle exec rails-active-mcp-server stdio
250
+ ```
251
+
252
+ ## Best Practices
253
+
254
+ ### Development Workflow
255
+
256
+ 1. **Start with Inspector**: Use `bin/debug-mcp-server --mode inspector` for development
257
+ 2. **Enable Debug Logging**: Use `RAILS_MCP_DEBUG=1` during development
258
+ 3. **Test Integration**: Test in Claude Desktop with debug logs enabled
259
+ 4. **Monitor Performance**: Check execution times and resource usage
260
+
261
+ ### Security Considerations When Debugging
262
+
263
+ 1. **Sanitize Logs**: Never log sensitive data (passwords, API keys)
264
+ 2. **Limit Debug Info**: Don't expose internal system details in production
265
+ 3. **Protect Credentials**: Use environment variables, not hardcoded values
266
+
267
+ ### Performance Monitoring
268
+
269
+ - Monitor tool execution times
270
+ - Track memory usage during long operations
271
+ - Log slow queries and operations
272
+ - Monitor connection stability
273
+
274
+ ## Getting Help
275
+
276
+ When reporting issues:
277
+
278
+ 1. **Provide log excerpts** from both server and Claude Desktop
279
+ 2. **Include configuration files** (sanitized)
280
+ 3. **List steps to reproduce** the issue
281
+ 4. **Specify environment details** (Ruby version, Rails version, OS)
282
+
283
+ ### Support Resources
284
+
285
+ - [MCP Inspector Documentation](https://modelcontextprotocol.io/docs/tools/inspector)
286
+ - [MCP Debugging Guide](https://modelcontextprotocol.io/docs/tools/debugging)
287
+ - [GitHub Issues](https://github.com/goodpie/rails-active-mcp/issues)
288
+
289
+ ## Advanced Debugging
290
+
291
+ ### Custom Log Analysis
292
+
293
+ Monitor specific patterns in logs:
294
+
295
+ ```bash
296
+ # Watch for tool executions
297
+ tail -f ~/Library/Logs/Claude/mcp*.log | grep "Executing tool"
298
+
299
+ # Monitor errors only
300
+ tail -f ~/Library/Logs/Claude/mcp*.log | grep "ERROR"
301
+
302
+ # Track performance
303
+ tail -f ~/Library/Logs/Claude/mcp*.log | grep "completed in"
304
+ ```
305
+
306
+ ### Development Tips
307
+
308
+ 1. **Use Inspector First**: Always test changes with MCP Inspector before Claude Desktop
309
+ 2. **Enable All Logging**: Use debug mode to see the full request/response cycle
310
+ 3. **Test Edge Cases**: Invalid inputs, timeouts, concurrent requests
311
+ 4. **Monitor Resource Usage**: Watch memory and CPU during development
312
+
313
+ This debugging guide ensures your Rails Active MCP server works reliably with Claude Desktop and other MCP clients.
@@ -3,22 +3,67 @@
3
3
 
4
4
  require 'rack'
5
5
  require 'rack/handler/webrick'
6
+ require 'json'
6
7
  require_relative '../lib/rails_active_mcp'
7
8
 
8
- # Parse command line options
9
- port = ARGV.include?('--port') ? ARGV[ARGV.index('--port') + 1].to_i : 3001
10
- host = ARGV.include?('--host') ? ARGV[ARGV.index('--host') + 1] : 'localhost'
11
-
12
- puts "Starting Rails Active MCP Server on #{host}:#{port}"
13
- puts "Press Ctrl+C to stop"
14
-
15
- begin
16
- Rack::Handler::WEBrick.run(
17
- RailsActiveMcp::McpServer.new,
18
- Port: port,
19
- Host: host,
20
- Logger: WEBrick::Log.new(nil, WEBrick::BasicLog::WARN)
21
- )
22
- rescue Interrupt
23
- puts "\nShutting down server..."
24
- end
9
+ # Load Rails configuration if available
10
+ require_relative '../config/environment' if File.exist?('config/environment.rb')
11
+
12
+ # Parse command line options with config defaults
13
+ default_mode = if defined?(RailsActiveMcp) && RailsActiveMcp.respond_to?(:config)
14
+ RailsActiveMcp.config.server_mode.to_s
15
+ else
16
+ 'stdio'
17
+ end
18
+ default_port = if defined?(RailsActiveMcp) && RailsActiveMcp.respond_to?(:config)
19
+ RailsActiveMcp.config.server_port
20
+ else
21
+ 3001
22
+ end
23
+ default_host = if defined?(RailsActiveMcp) && RailsActiveMcp.respond_to?(:config)
24
+ RailsActiveMcp.config.server_host
25
+ else
26
+ 'localhost'
27
+ end
28
+
29
+ transport = ARGV[0] || default_mode
30
+ port = ARGV.include?('--port') ? ARGV[ARGV.index('--port') + 1].to_i : default_port
31
+ host = ARGV.include?('--host') ? ARGV[ARGV.index('--host') + 1] : default_host
32
+
33
+ case transport
34
+ when 'stdio'
35
+ # Stdio transport for Claude Desktop
36
+ require_relative '../lib/rails_active_mcp/stdio_server'
37
+
38
+ begin
39
+ # Initialize Rails environment if available
40
+ require_relative '../config/environment' if File.exist?('config/environment.rb')
41
+
42
+ stdio_server = RailsActiveMcp::StdioServer.new
43
+ stdio_server.run
44
+ rescue Interrupt
45
+ exit(0)
46
+ end
47
+
48
+ when 'http'
49
+ # HTTP transport for other integrations
50
+ puts "Starting Rails Active MCP Server on #{host}:#{port}"
51
+ puts 'Press Ctrl+C to stop'
52
+
53
+ begin
54
+ Rack::Handler::WEBrick.run(
55
+ RailsActiveMcp::McpServer.new,
56
+ Port: port,
57
+ Host: host,
58
+ Logger: WEBrick::Log.new(nil, WEBrick::BasicLog::WARN)
59
+ )
60
+ rescue Interrupt
61
+ puts "\nShutting down server..."
62
+ end
63
+
64
+ else
65
+ puts 'Usage: rails-active-mcp-server [stdio|http] [--port PORT] [--host HOST]'
66
+ puts ' stdio: For Claude Desktop integration'
67
+ puts ' http: For HTTP-based integrations (default)'
68
+ exit(1)
69
+ end
@@ -1,4 +1,3 @@
1
-
2
1
  ================================================================================
3
2
  Rails Active MCP has been installed!
4
3
  ================================================================================
@@ -13,17 +12,54 @@ Next Steps:
13
12
 
14
13
  1. Review and customize the configuration in config/initializers/rails_active_mcp.rb
15
14
 
16
- 2. Start the MCP server:
17
- Option A: Rails-mounted server
18
- $ rails server
15
+ 2. Configure server mode in config/initializers/rails_active_mcp.rb:
16
+ config.server_mode = :stdio # For Claude Desktop (default)
17
+ config.server_mode = :http # For HTTP-based integrations
18
+ config.server_host = 'localhost'
19
+ config.server_port = 3001
19
20
 
20
- Option B: Standalone server
21
+ 3. Start the MCP server:
22
+ Option A: Use configured mode (RECOMMENDED)
21
23
  $ bundle exec rails-active-mcp-server
22
24
 
23
- Option C: Using rackup
25
+ Option B: Override mode via command line
26
+ $ bundle exec rails-active-mcp-server stdio # Force stdio mode
27
+ $ bundle exec rails-active-mcp-server http # Force HTTP mode
28
+
29
+ Option C: Rails-mounted server (HTTP)
30
+ $ rails server
31
+
32
+ Option D: Using rackup
24
33
  $ rackup mcp.ru -p 3001
25
34
 
26
- 3. For Warp Terminal integration, add this to your MCP configuration:
35
+ 4. For Claude Desktop integration, add this to your Claude Desktop configuration:
36
+
37
+ Location: ~/.config/claude-desktop/claude_desktop_config.json (Linux/macOS)
38
+ Location: %APPDATA%\Claude\claude_desktop_config.json (Windows)
39
+
40
+ {
41
+ "mcpServers": {
42
+ "rails-active-mcp": {
43
+ "command": "bundle",
44
+ "args": ["exec", "rails-active-mcp-server", "stdio"],
45
+ "cwd": "/path/to/your/rails/project"
46
+ }
47
+ }
48
+ }
49
+
50
+ OR if you've installed the gem globally:
51
+
52
+ {
53
+ "mcpServers": {
54
+ "rails-active-mcp": {
55
+ "command": "rails-active-mcp-server",
56
+ "args": ["stdio"],
57
+ "cwd": "/path/to/your/rails/project"
58
+ }
59
+ }
60
+ }
61
+
62
+ 5. For other MCP clients (HTTP-based), add this to your MCP configuration:
27
63
  {
28
64
  "mcpServers": {
29
65
  "rails-console": {
@@ -33,13 +69,16 @@ Next Steps:
33
69
  }
34
70
  }
35
71
 
36
- 4. Test the installation:
72
+ 6. Test the installation:
37
73
  $ rails console
38
74
  > RailsActiveMcp.safe?("User.count")
39
75
  > RailsActiveMcp.execute("User.count")
40
76
 
41
- Built-in Tools:
42
- - rails_console_execute: Execute Ruby code with safety checks
77
+ Built-in Tools Available in Claude:
78
+ - rails_console_execute: Execute Ruby code in Rails console with safety checks
79
+ - rails_model_info: Get detailed information about Rails models
80
+ - rails_safe_query: Execute safe read-only database queries
81
+ - rails_dry_run: Analyze Ruby code for safety without execution
43
82
 
44
83
  Extend with custom tools by modifying the MCP server implementation.
45
84
 
@@ -49,11 +88,60 @@ Security Notes:
49
88
  - Dangerous operations are blocked in safe mode
50
89
  - Review the safety patterns in the configuration
51
90
 
91
+ Transport Modes:
92
+ - stdio: For Claude Desktop and compatible MCP clients (recommended)
93
+ - http: For HTTP-based integrations and web applications
94
+
95
+ Configuration Examples:
96
+
97
+ For Claude Desktop (default):
98
+ config.server_mode = :stdio
99
+
100
+ For HTTP web integrations:
101
+ config.server_mode = :http
102
+ config.server_host = 'localhost'
103
+ config.server_port = 3001
104
+
105
+ For Docker/remote access:
106
+ config.http_mode!(host: '0.0.0.0', port: 8080)
107
+
108
+ For development with multiple transport modes:
109
+ if Rails.env.development?
110
+ config.stdio_mode! # Claude Desktop
111
+ else
112
+ config.http_mode!(host: '0.0.0.0', port: 3001) # Production HTTP
113
+ end
114
+
52
115
  Custom MCP Server Benefits:
53
116
  - No external dependencies
54
117
  - Full control over implementation
55
118
  - Simplified deployment
56
119
  - Enhanced security
120
+ - Works with Claude Desktop
121
+
122
+ Debugging and Troubleshooting:
123
+
124
+ For interactive debugging, use the MCP Inspector:
125
+ $ bin/debug-mcp-server --mode inspector
126
+
127
+ This will:
128
+ - Launch the MCP Inspector connected to your server
129
+ - Allow interactive testing of all tools
130
+ - Show real-time debug output and logs
131
+
132
+ Debug logging:
133
+ $ RAILS_MCP_DEBUG=1 bundle exec rails-active-mcp-server stdio
134
+
135
+ View Claude Desktop logs:
136
+ $ tail -f ~/Library/Logs/Claude/mcp*.log # macOS
137
+ $ tail -f ~/.config/claude-desktop/logs/*.log # Linux
138
+
139
+ Common issues:
140
+ - Ensure your Rails environment loads properly in the project directory
141
+ - Check that the gem is properly installed and configured
142
+ - Verify the Rails application starts without errors
143
+ - Make sure the cwd path in Claude Desktop config is correct
144
+ - Enable debug logging with RAILS_MCP_DEBUG=1 for detailed output
57
145
 
58
146
  For more information: https://github.com/goodpie/rails-active-mcp
59
147
 
@@ -1,6 +1,5 @@
1
1
  require 'rails_active_mcp'
2
2
 
3
-
4
3
  RailsActiveMcp.configure do |config|
5
4
  # Enable/disable the MCP server
6
5
  config.enabled = true
@@ -19,7 +18,12 @@ RailsActiveMcp.configure do |config|
19
18
 
20
19
  # Logging and auditing
21
20
  config.log_executions = true
22
- config.audit_file = Rails.root.join("log", "rails_active_mcp.log")
21
+ config.audit_file = Rails.root.join('log', 'rails_active_mcp.log')
22
+
23
+ # Server configuration
24
+ config.server_mode = :stdio # :stdio for Claude Desktop, :http for web integrations
25
+ config.server_host = 'localhost'
26
+ config.server_port = 3001
23
27
 
24
28
  # Environment-specific settings
25
29
  case Rails.env
@@ -35,5 +39,5 @@ RailsActiveMcp.configure do |config|
35
39
  # config.add_safety_pattern(/CustomDangerousMethod/, "Custom dangerous operation")
36
40
 
37
41
  # Operations that require manual confirmation
38
- config.require_confirmation_for = [:delete, :destroy, :update_all, :delete_all]
42
+ config.require_confirmation_for = %i[delete destroy update_all delete_all]
39
43
  end
@@ -5,7 +5,8 @@ module RailsActiveMcp
5
5
  attr_accessor :enabled, :safe_mode, :default_timeout, :max_results,
6
6
  :allowed_models, :blocked_models, :custom_safety_patterns,
7
7
  :log_executions, :audit_file, :enable_mutation_tools,
8
- :require_confirmation_for, :execution_environment
8
+ :require_confirmation_for, :execution_environment, :server_mode,
9
+ :server_host, :server_port
9
10
 
10
11
  def initialize
11
12
  @enabled = true
@@ -17,10 +18,16 @@ module RailsActiveMcp
17
18
  @custom_safety_patterns = []
18
19
  @log_executions = true
19
20
  # Safe Rails.root access
20
- @audit_file = rails_root_join("log", "rails_active_mcp.log") if defined?(Rails) && Rails.respond_to?(:root) && Rails.root
21
+ if defined?(Rails) && Rails.respond_to?(:root) && Rails.root
22
+ @audit_file = rails_root_join('log',
23
+ 'rails_active_mcp.log')
24
+ end
21
25
  @enable_mutation_tools = false
22
- @require_confirmation_for = [:delete, :destroy, :update_all, :delete_all]
26
+ @require_confirmation_for = %i[delete destroy update_all delete_all]
23
27
  @execution_environment = :current # :current, :sandbox, :readonly_replica
28
+ @server_mode = :stdio # :stdio, :http
29
+ @server_host = 'localhost'
30
+ @server_port = 3001
24
31
  end
25
32
 
26
33
  # Safety configuration
@@ -42,7 +49,7 @@ module RailsActiveMcp
42
49
  strict_mode!
43
50
  @execution_environment = :readonly_replica
44
51
  @log_executions = true
45
- @require_confirmation_for = [:delete, :destroy, :update, :create, :save]
52
+ @require_confirmation_for = %i[delete destroy update create save]
46
53
  end
47
54
 
48
55
  # Model access configuration
@@ -58,6 +65,21 @@ module RailsActiveMcp
58
65
  @custom_safety_patterns << { pattern: pattern, description: description }
59
66
  end
60
67
 
68
+ # Server configuration
69
+ def stdio_mode!
70
+ @server_mode = :stdio
71
+ end
72
+
73
+ def http_mode!(host: 'localhost', port: 3001)
74
+ @server_mode = :http
75
+ @server_host = host
76
+ @server_port = port
77
+ end
78
+
79
+ def server_mode_valid?
80
+ %i[stdio http].include?(@server_mode)
81
+ end
82
+
61
83
  # Validation
62
84
  def model_allowed?(model_name)
63
85
  model_str = model_name.to_s
@@ -73,13 +95,15 @@ module RailsActiveMcp
73
95
  end
74
96
 
75
97
  def validate!
76
- raise ArgumentError, "timeout must be positive" if @default_timeout <= 0
77
- raise ArgumentError, "max_results must be positive" if @max_results <= 0
98
+ raise ArgumentError, 'timeout must be positive' if @default_timeout <= 0
99
+ raise ArgumentError, 'max_results must be positive' if @max_results <= 0
100
+ raise ArgumentError, "invalid server_mode: #{@server_mode}" unless server_mode_valid?
101
+ raise ArgumentError, 'server_port must be positive' if @server_port <= 0
78
102
 
79
- if defined?(Rails) && @audit_file
80
- audit_dir = File.dirname(@audit_file)
81
- FileUtils.mkdir_p(audit_dir) unless File.directory?(audit_dir)
82
- end
103
+ return unless defined?(Rails) && @audit_file
104
+
105
+ audit_dir = File.dirname(@audit_file)
106
+ FileUtils.mkdir_p(audit_dir) unless File.directory?(audit_dir)
83
107
  end
84
108
 
85
109
  private
@@ -0,0 +1,467 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+ require 'logger'
5
+
6
+ module RailsActiveMcp
7
+ class StdioServer
8
+ JSONRPC_VERSION = '2.0'
9
+ MCP_VERSION = '2025-06-18'
10
+
11
+ def initialize
12
+ @tools = {}
13
+ @logger = Logger.new(STDERR) # Log to stderr to avoid interfering with stdout
14
+ @logger.level = ENV['RAILS_MCP_DEBUG'] ? Logger::DEBUG : Logger::ERROR
15
+ @logger.formatter = proc do |severity, datetime, progname, msg|
16
+ "[#{datetime}] [RAILS-MCP] #{severity}: #{msg}\n"
17
+ end
18
+ register_default_tools
19
+ @logger.info "Rails Active MCP Server initialized with #{@tools.size} tools"
20
+ end
21
+
22
+ def run
23
+ @logger.info 'Starting Rails Active MCP Stdio Server'
24
+ send_log_notification('info', 'Rails Active MCP Server started successfully')
25
+
26
+ STDIN.each_line do |line|
27
+ line = line.strip
28
+ next if line.empty?
29
+
30
+ @logger.debug "Received request: #{line}" if ENV['RAILS_MCP_DEBUG']
31
+ data = JSON.parse(line)
32
+
33
+ @logger.debug "Processing method: #{data['method']}" if ENV['RAILS_MCP_DEBUG']
34
+ response = handle_jsonrpc_request(data)
35
+
36
+ if response
37
+ @logger.debug "Sending response: #{response.to_json}" if ENV['RAILS_MCP_DEBUG']
38
+ puts response.to_json
39
+ STDOUT.flush
40
+ end
41
+ rescue JSON::ParserError => e
42
+ @logger.error "JSON Parse Error: #{e.message}"
43
+ send_log_notification('error', "JSON Parse Error: #{e.message}")
44
+ error_response = jsonrpc_error(nil, -32_700, 'Parse error')
45
+ puts error_response.to_json
46
+ STDOUT.flush
47
+ rescue StandardError => e
48
+ @logger.error "Unexpected error: #{e.message}"
49
+ @logger.error e.backtrace.join("\n")
50
+ send_log_notification('error', "Server error: #{e.message}")
51
+ error_response = jsonrpc_error(nil, -32_603, 'Internal error')
52
+ puts error_response.to_json
53
+ STDOUT.flush
54
+ end
55
+ end
56
+
57
+ private
58
+
59
+ def handle_jsonrpc_request(data)
60
+ case data['method']
61
+ when 'initialize'
62
+ handle_initialize(data)
63
+ when 'tools/list'
64
+ handle_tools_list(data)
65
+ when 'tools/call'
66
+ handle_tools_call(data)
67
+ when 'resources/list'
68
+ handle_resources_list(data)
69
+ when 'resources/read'
70
+ handle_resources_read(data)
71
+ when 'ping'
72
+ handle_ping(data)
73
+ else
74
+ jsonrpc_error(data['id'], -32_601, 'Method not found')
75
+ end
76
+ end
77
+
78
+ def handle_initialize(data)
79
+ {
80
+ jsonrpc: JSONRPC_VERSION,
81
+ id: data['id'],
82
+ result: {
83
+ protocolVersion: MCP_VERSION,
84
+ capabilities: {
85
+ tools: {},
86
+ resources: {}
87
+ },
88
+ serverInfo: {
89
+ name: 'rails-active-mcp',
90
+ version: RailsActiveMcp::VERSION
91
+ }
92
+ }
93
+ }
94
+ end
95
+
96
+ def handle_tools_list(data)
97
+ tools_array = @tools.values.map do |tool|
98
+ tool_def = {
99
+ name: tool[:name],
100
+ description: tool[:description],
101
+ inputSchema: tool[:input_schema]
102
+ }
103
+
104
+ # Add annotations if present
105
+ tool_def[:annotations] = tool[:annotations] if tool[:annotations] && !tool[:annotations].empty?
106
+
107
+ tool_def
108
+ end
109
+
110
+ {
111
+ jsonrpc: JSONRPC_VERSION,
112
+ id: data['id'],
113
+ result: { tools: tools_array }
114
+ }
115
+ end
116
+
117
+ def handle_tools_call(data)
118
+ tool_name = data.dig('params', 'name')
119
+ arguments = data.dig('params', 'arguments') || {}
120
+
121
+ tool = @tools[tool_name]
122
+ return jsonrpc_error(data['id'], -32_602, "Tool '#{tool_name}' not found") unless tool
123
+
124
+ @logger.info "Executing tool: #{tool_name}"
125
+ send_log_notification('info', "Executing tool: #{tool_name}")
126
+
127
+ begin
128
+ start_time = Time.now
129
+ result = tool[:handler].call(arguments)
130
+ execution_time = Time.now - start_time
131
+
132
+ @logger.info "Tool #{tool_name} completed in #{execution_time}s"
133
+ send_log_notification('info', "Tool #{tool_name} completed successfully")
134
+
135
+ {
136
+ jsonrpc: JSONRPC_VERSION,
137
+ id: data['id'],
138
+ result: {
139
+ content: [{ type: 'text', text: result.to_s }],
140
+ isError: false
141
+ }
142
+ }
143
+ rescue StandardError => e
144
+ @logger.error "Tool execution error: #{e.message}"
145
+ @logger.error e.backtrace.first(5).join("\n") if ENV['RAILS_MCP_DEBUG']
146
+ send_log_notification('error', "Tool #{tool_name} failed: #{e.message}")
147
+
148
+ {
149
+ jsonrpc: JSONRPC_VERSION,
150
+ id: data['id'],
151
+ result: {
152
+ content: [{ type: 'text', text: "Error: #{e.message}" }],
153
+ isError: true
154
+ }
155
+ }
156
+ end
157
+ end
158
+
159
+ def handle_resources_list(data)
160
+ {
161
+ jsonrpc: JSONRPC_VERSION,
162
+ id: data['id'],
163
+ result: { resources: [] }
164
+ }
165
+ end
166
+
167
+ def handle_resources_read(data)
168
+ {
169
+ jsonrpc: JSONRPC_VERSION,
170
+ id: data['id'],
171
+ result: { contents: [] }
172
+ }
173
+ end
174
+
175
+ def handle_ping(data)
176
+ {
177
+ jsonrpc: JSONRPC_VERSION,
178
+ id: data['id'],
179
+ result: {}
180
+ }
181
+ end
182
+
183
+ def register_tool(name, description, input_schema, annotations = {}, &handler)
184
+ @tools[name] = {
185
+ name: name,
186
+ description: description,
187
+ input_schema: input_schema,
188
+ annotations: annotations,
189
+ handler: handler
190
+ }
191
+ end
192
+
193
+ def register_default_tools
194
+ register_tool(
195
+ 'rails_console_execute',
196
+ 'Execute Ruby code in Rails console context',
197
+ {
198
+ type: 'object',
199
+ properties: {
200
+ code: { type: 'string', description: 'Ruby code to execute' },
201
+ timeout: { type: 'number', description: 'Timeout in seconds', default: 30 },
202
+ safe_mode: { type: 'boolean', description: 'Enable safety checks', default: true },
203
+ capture_output: { type: 'boolean', description: 'Capture console output', default: true }
204
+ },
205
+ required: ['code']
206
+ },
207
+ {
208
+ title: 'Rails Console Executor',
209
+ readOnlyHint: false,
210
+ destructiveHint: true,
211
+ idempotentHint: false,
212
+ openWorldHint: false
213
+ }
214
+ ) do |args|
215
+ execute_console_code(args)
216
+ end
217
+
218
+ register_tool(
219
+ 'rails_model_info',
220
+ 'Get information about Rails models including columns, associations, and table structure',
221
+ {
222
+ type: 'object',
223
+ properties: {
224
+ model_name: { type: 'string', description: 'Name of the Rails model class to inspect' }
225
+ },
226
+ required: ['model_name']
227
+ },
228
+ {
229
+ title: 'Rails Model Inspector',
230
+ readOnlyHint: true,
231
+ destructiveHint: false,
232
+ idempotentHint: true,
233
+ openWorldHint: false
234
+ }
235
+ ) do |args|
236
+ get_model_info(args['model_name'])
237
+ end
238
+
239
+ register_tool(
240
+ 'rails_safe_query',
241
+ 'Execute safe read-only database queries using ActiveRecord',
242
+ {
243
+ type: 'object',
244
+ properties: {
245
+ query: { type: 'string', description: 'ActiveRecord query to execute (read-only methods only)' },
246
+ model: { type: 'string', description: 'Model class name to query against' }
247
+ },
248
+ required: %w[query model]
249
+ },
250
+ {
251
+ title: 'Rails Safe Query Executor',
252
+ readOnlyHint: true,
253
+ destructiveHint: false,
254
+ idempotentHint: true,
255
+ openWorldHint: false
256
+ }
257
+ ) do |args|
258
+ execute_safe_query(args)
259
+ end
260
+
261
+ register_tool(
262
+ 'rails_dry_run',
263
+ 'Analyze Ruby code for safety without executing it',
264
+ {
265
+ type: 'object',
266
+ properties: {
267
+ code: { type: 'string', description: 'Ruby code to analyze for safety and potential issues' }
268
+ },
269
+ required: ['code']
270
+ },
271
+ {
272
+ title: 'Rails Code Safety Analyzer',
273
+ readOnlyHint: true,
274
+ destructiveHint: false,
275
+ idempotentHint: true,
276
+ openWorldHint: false
277
+ }
278
+ ) do |args|
279
+ dry_run_analysis(args['code'])
280
+ end
281
+ end
282
+
283
+ # Tool implementation methods (reused from McpServer)
284
+ def execute_console_code(args)
285
+ unless defined?(RailsActiveMcp) && RailsActiveMcp.respond_to?(:config) && RailsActiveMcp.config.enabled
286
+ return 'Rails Active MCP is disabled. Enable it in your Rails configuration.'
287
+ end
288
+
289
+ executor = RailsActiveMcp::ConsoleExecutor.new(RailsActiveMcp.config)
290
+
291
+ begin
292
+ result = executor.execute(
293
+ args['code'],
294
+ timeout: args['timeout'] || 30,
295
+ safe_mode: args['safe_mode'] != false,
296
+ capture_output: args['capture_output'] != false
297
+ )
298
+
299
+ if result[:success]
300
+ format_success_result(result)
301
+ else
302
+ "Error: #{result[:error]} (#{result[:error_class]})"
303
+ end
304
+ rescue RailsActiveMcp::SafetyError => e
305
+ "Safety check failed: #{e.message}"
306
+ rescue RailsActiveMcp::TimeoutError => e
307
+ "Execution timed out: #{e.message}"
308
+ rescue StandardError => e
309
+ "Execution failed: #{e.message}"
310
+ end
311
+ end
312
+
313
+ def get_model_info(model_name)
314
+ unless defined?(RailsActiveMcp) && RailsActiveMcp.respond_to?(:config) && RailsActiveMcp.config.enabled
315
+ return 'Rails Active MCP is disabled. Enable it in your Rails configuration.'
316
+ end
317
+
318
+ begin
319
+ # Try to load Rails environment if not already loaded
320
+ require_relative '../../../config/environment' if !defined?(Rails) && File.exist?('config/environment.rb')
321
+
322
+ model_class = model_name.constantize
323
+ unless defined?(ActiveRecord) && model_class < ActiveRecord::Base
324
+ return "#{model_name} is not an ActiveRecord model"
325
+ end
326
+
327
+ info = []
328
+ info << "Model: #{model_class.name}"
329
+ info << "Table: #{model_class.table_name}"
330
+ info << "Columns: #{model_class.column_names.join(', ')}"
331
+
332
+ associations = model_class.reflect_on_all_associations.map(&:name)
333
+ info << "Associations: #{associations.any? ? associations.join(', ') : 'None'}"
334
+
335
+ # Add validation info if available
336
+ if model_class.respond_to?(:validators) && model_class.validators.any?
337
+ validations = model_class.validators.map { |v| "#{v.attributes.join(', ')}: #{v.class.name.demodulize}" }.uniq
338
+ info << "Validations: #{validations.join(', ')}"
339
+ end
340
+
341
+ info.join("\n")
342
+ rescue NameError
343
+ "Model '#{model_name}' not found. Make sure the model class exists and is properly defined."
344
+ rescue StandardError => e
345
+ "Error getting model info: #{e.message}"
346
+ end
347
+ end
348
+
349
+ def execute_safe_query(args)
350
+ unless defined?(RailsActiveMcp) && RailsActiveMcp.respond_to?(:config) && RailsActiveMcp.config.enabled
351
+ return 'Rails Active MCP is disabled. Enable it in your Rails configuration.'
352
+ end
353
+
354
+ begin
355
+ # Try to load Rails environment if not already loaded
356
+ require_relative '../../../config/environment' if !defined?(Rails) && File.exist?('config/environment.rb')
357
+
358
+ model_class = args['model'].constantize
359
+ unless defined?(ActiveRecord) && model_class < ActiveRecord::Base
360
+ return "#{args['model']} is not an ActiveRecord model"
361
+ end
362
+
363
+ # Only allow safe read-only methods
364
+ safe_methods = %w[find find_by where select count sum average maximum minimum first last pluck ids exists?
365
+ empty? any? many? include? limit offset order group having joins includes references distinct uniq readonly]
366
+
367
+ # Extract the first method call to validate it's safe
368
+ query_parts = args['query'].split('.')
369
+ query_method = query_parts.first.split('(').first
370
+
371
+ unless safe_methods.include?(query_method)
372
+ return "Unsafe query method: #{query_method}. Only read-only methods are allowed."
373
+ end
374
+
375
+ result = model_class.instance_eval(args['query'])
376
+
377
+ # Format result appropriately
378
+ case result
379
+ when ActiveRecord::Relation
380
+ "Query returned #{result.count} records: #{result.limit(10).pluck(:id).join(', ')}#{result.count > 10 ? '...' : ''}"
381
+ when Array
382
+ "Array with #{result.length} items: #{result.take(5).inspect}#{result.length > 5 ? '...' : ''}"
383
+ else
384
+ result.to_s
385
+ end
386
+ rescue NameError
387
+ "Model '#{args['model']}' not found. Make sure the model class exists and is properly defined."
388
+ rescue StandardError => e
389
+ "Error executing query: #{e.message}"
390
+ end
391
+ end
392
+
393
+ def dry_run_analysis(code)
394
+ unless defined?(RailsActiveMcp) && RailsActiveMcp.respond_to?(:config) && RailsActiveMcp.config.enabled
395
+ return 'Rails Active MCP is disabled. Enable it in your Rails configuration.'
396
+ end
397
+
398
+ executor = RailsActiveMcp::ConsoleExecutor.new(RailsActiveMcp.config)
399
+
400
+ begin
401
+ analysis = executor.dry_run(code)
402
+
403
+ output = []
404
+ output << 'Code Analysis Results:'
405
+ output << "Code: #{analysis[:code]}"
406
+ output << "Safe: #{analysis[:safety_analysis][:safe] ? 'Yes' : 'No'}"
407
+ output << "Read-only: #{analysis[:safety_analysis][:read_only] ? 'Yes' : 'No'}"
408
+ output << "Risk level: #{analysis[:estimated_risk]}"
409
+ output << "Would execute: #{analysis[:would_execute] ? 'Yes' : 'No'}"
410
+ output << "Summary: #{analysis[:safety_analysis][:summary]}"
411
+
412
+ if analysis[:safety_analysis][:violations] && analysis[:safety_analysis][:violations].any?
413
+ output << "\nSafety Violations:"
414
+ analysis[:safety_analysis][:violations].each do |violation|
415
+ output << " - #{violation[:description]} (#{violation[:severity]})"
416
+ end
417
+ end
418
+
419
+ if analysis[:recommendations] && analysis[:recommendations].any?
420
+ output << "\nRecommendations:"
421
+ analysis[:recommendations].each do |rec|
422
+ output << " - #{rec}"
423
+ end
424
+ end
425
+
426
+ output.join("\n")
427
+ rescue StandardError => e
428
+ "Analysis failed: #{e.message}. Make sure the Rails environment is properly loaded."
429
+ end
430
+ end
431
+
432
+ def format_success_result(result)
433
+ output = []
434
+ output << 'Execution Results:'
435
+ output << "Code: #{result[:code]}"
436
+ output << "Result: #{result[:return_value_string] || result[:return_value]}"
437
+ output << "Output: #{result[:output]}" if result[:output] && !result[:output].empty?
438
+ output << "Execution time: #{result[:execution_time]}s" if result[:execution_time]
439
+ output << "Note: #{result[:note]}" if result[:note]
440
+ output.join("\n")
441
+ end
442
+
443
+ def send_log_notification(level, message)
444
+ notification = {
445
+ jsonrpc: JSONRPC_VERSION,
446
+ method: 'notifications/message',
447
+ params: {
448
+ level: level,
449
+ data: message
450
+ }
451
+ }
452
+
453
+ puts notification.to_json
454
+ STDOUT.flush
455
+ rescue StandardError => e
456
+ @logger.error "Failed to send log notification: #{e.message}"
457
+ end
458
+
459
+ def jsonrpc_error(id, code, message)
460
+ {
461
+ jsonrpc: JSONRPC_VERSION,
462
+ id: id,
463
+ error: { code: code, message: message }
464
+ }
465
+ end
466
+ end
467
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RailsActiveMcp
4
- VERSION = '0.1.2'
4
+ VERSION = '0.1.4'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails-active-mcp
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brandyn Britton
@@ -193,6 +193,7 @@ files:
193
193
  - ".idea/vcs.xml"
194
194
  - README.md
195
195
  - changelog.md
196
+ - docs/DEBUGGING.md
196
197
  - docs/README.md
197
198
  - exe/rails-active-mcp-server
198
199
  - lib/generators/rails_active_mcp/install/install_generator.rb
@@ -206,6 +207,7 @@ files:
206
207
  - lib/rails_active_mcp/mcp_server.rb
207
208
  - lib/rails_active_mcp/railtie.rb
208
209
  - lib/rails_active_mcp/safety_checker.rb
210
+ - lib/rails_active_mcp/stdio_server.rb
209
211
  - lib/rails_active_mcp/tasks.rake
210
212
  - lib/rails_active_mcp/tools/console_execute_tool.rb
211
213
  - lib/rails_active_mcp/tools/dry_run_tool.rb