rails-active-mcp 0.1.7 → 2.0.7
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 +106 -279
- data/changelog.md +69 -0
- data/docs/DEBUGGING.md +5 -5
- data/docs/README.md +130 -142
- data/exe/rails-active-mcp-server +153 -76
- data/lib/generators/rails_active_mcp/install/install_generator.rb +19 -39
- data/lib/generators/rails_active_mcp/install/templates/README.md +30 -164
- data/lib/generators/rails_active_mcp/install/templates/initializer.rb +37 -38
- data/lib/generators/rails_active_mcp/install/templates/mcp.ru +7 -3
- data/lib/rails_active_mcp/configuration.rb +37 -98
- data/lib/rails_active_mcp/console_executor.rb +13 -3
- data/lib/rails_active_mcp/engine.rb +36 -24
- data/lib/rails_active_mcp/sdk/server.rb +183 -0
- data/lib/rails_active_mcp/sdk/tools/console_execute_tool.rb +103 -0
- data/lib/rails_active_mcp/sdk/tools/dry_run_tool.rb +73 -0
- data/lib/rails_active_mcp/sdk/tools/model_info_tool.rb +106 -0
- data/lib/rails_active_mcp/sdk/tools/safe_query_tool.rb +77 -0
- data/lib/rails_active_mcp/version.rb +1 -1
- data/lib/rails_active_mcp.rb +5 -11
- data/rails_active_mcp.gemspec +4 -1
- metadata +22 -11
- data/app/controllers/rails_active_mcp/mcp_controller.rb +0 -80
- data/lib/rails_active_mcp/mcp_server.rb +0 -383
- data/lib/rails_active_mcp/railtie.rb +0 -70
- data/lib/rails_active_mcp/stdio_server.rb +0 -517
- data/lib/rails_active_mcp/tools/console_execute_tool.rb +0 -61
- data/lib/rails_active_mcp/tools/dry_run_tool.rb +0 -41
- data/lib/rails_active_mcp/tools/model_info_tool.rb +0 -70
- data/lib/rails_active_mcp/tools/safe_query_tool.rb +0 -41
@@ -20,30 +20,24 @@ module RailsActiveMcp
|
|
20
20
|
# This ensures the server runs within the Rails project context
|
21
21
|
|
22
22
|
require 'bundler/setup'
|
23
|
-
require 'stringio'
|
24
23
|
|
25
24
|
# Set Rails environment
|
26
25
|
ENV['RAILS_ENV'] ||= 'development'
|
27
26
|
|
28
|
-
#
|
29
|
-
unless ENV['RAILS_MCP_DEBUG'] == '1'
|
30
|
-
original_stdout = $stdout
|
31
|
-
original_stderr = $stderr
|
32
|
-
$stdout = StringIO.new
|
33
|
-
$stderr = StringIO.new
|
34
|
-
end
|
35
|
-
|
36
|
-
# Load Rails application
|
27
|
+
# Load Rails application first
|
37
28
|
require_relative '../config/environment'
|
38
29
|
|
39
|
-
#
|
40
|
-
|
41
|
-
$stdout = original_stdout
|
42
|
-
$stderr = original_stderr
|
43
|
-
end
|
30
|
+
# Now start the MCP server using the SDK implementation
|
31
|
+
require 'rails_active_mcp/sdk/server'
|
44
32
|
|
45
|
-
|
46
|
-
|
33
|
+
begin
|
34
|
+
server = RailsActiveMcp::SDK::Server.new
|
35
|
+
server.run
|
36
|
+
rescue StandardError => e
|
37
|
+
warn "Error starting Rails Active MCP server: \#{e.message}"
|
38
|
+
warn e.backtrace if ENV['RAILS_MCP_DEBUG'] == '1'
|
39
|
+
exit 1
|
40
|
+
end
|
47
41
|
RUBY
|
48
42
|
|
49
43
|
chmod 'bin/rails-active-mcp-server', 0o755
|
@@ -57,7 +51,6 @@ module RailsActiveMcp
|
|
57
51
|
|
58
52
|
# Rails Active MCP Wrapper Script
|
59
53
|
# Ensures correct Ruby environment for Claude Desktop execution
|
60
|
-
# Research-based solution for version manager compatibility
|
61
54
|
|
62
55
|
# Fix Claude Desktop environment isolation issues
|
63
56
|
export HOME="${HOME:-#{ENV['HOME']}}"
|
@@ -95,24 +88,6 @@ module RailsActiveMcp
|
|
95
88
|
say 'Created environment wrapper at bin/rails-active-mcp-wrapper', :green
|
96
89
|
end
|
97
90
|
|
98
|
-
def create_mcp_route
|
99
|
-
# Check if routes file exists and is writable
|
100
|
-
routes_file = 'config/routes.rb'
|
101
|
-
return unless File.exist?(routes_file)
|
102
|
-
|
103
|
-
# Read current routes to check for conflicts
|
104
|
-
routes_content = File.read(routes_file)
|
105
|
-
|
106
|
-
if routes_content.include?('/mcp')
|
107
|
-
say "Warning: Route '/mcp' already exists. Skipping route creation.", :yellow
|
108
|
-
say "Manual setup: Add 'mount RailsActiveMcp::Engine, at: \"/mcp\"' to your routes.rb", :yellow
|
109
|
-
else
|
110
|
-
# Use Engine mounting instead of direct server mounting
|
111
|
-
route "mount RailsActiveMcp::Engine, at: '/mcp'"
|
112
|
-
say "Added MCP route at '/mcp'. You can change this in config/routes.rb", :green
|
113
|
-
end
|
114
|
-
end
|
115
|
-
|
116
91
|
def create_mcp_config
|
117
92
|
template 'mcp.ru', 'mcp.ru'
|
118
93
|
end
|
@@ -134,7 +109,6 @@ module RailsActiveMcp
|
|
134
109
|
say ' "mcpServers": {', :cyan
|
135
110
|
say ' "rails-active-mcp": {', :cyan
|
136
111
|
say " \"command\": \"#{Rails.root}/bin/rails-active-mcp-wrapper\",", :cyan
|
137
|
-
say ' "args": ["stdio"],', :cyan
|
138
112
|
say " \"cwd\": \"#{Rails.root}\",", :cyan
|
139
113
|
say ' "env": {', :cyan
|
140
114
|
say ' "RAILS_ENV": "development",', :cyan
|
@@ -144,6 +118,12 @@ module RailsActiveMcp
|
|
144
118
|
say ' }', :cyan
|
145
119
|
say '}', :cyan
|
146
120
|
say '', :green
|
121
|
+
say "\nAvailable Tools in Claude Desktop:", :green
|
122
|
+
say '- console_execute: Execute Ruby code with safety checks', :yellow
|
123
|
+
say '- model_info: Get detailed information about Rails models', :yellow
|
124
|
+
say '- safe_query: Execute safe read-only database queries', :yellow
|
125
|
+
say '- dry_run: Analyze Ruby code for safety without execution', :yellow
|
126
|
+
say '', :green
|
147
127
|
say "\nWhy use the wrapper?", :green
|
148
128
|
say '- Handles Ruby version manager environments (asdf, rbenv, etc.)', :yellow
|
149
129
|
say '- Prevents "bundler version" and "Ruby version" conflicts', :yellow
|
@@ -151,8 +131,8 @@ module RailsActiveMcp
|
|
151
131
|
say "\nAlternative (if wrapper doesn't work):", :green
|
152
132
|
say 'Use bin/rails-active-mcp-server instead of the wrapper', :yellow
|
153
133
|
say "\nTesting:", :green
|
154
|
-
say '1. Test manually: bin/rails-active-mcp-wrapper
|
155
|
-
say '2. Should output JSON (not plain text)', :yellow
|
134
|
+
say '1. Test manually: bin/rails-active-mcp-wrapper', :yellow
|
135
|
+
say '2. Should output JSON responses (not plain text)', :yellow
|
156
136
|
say '3. Restart Claude Desktop after config changes', :yellow
|
157
137
|
say "\nTroubleshooting:", :green
|
158
138
|
say '- Set RAILS_MCP_DEBUG=1 for verbose logging', :yellow
|
@@ -1,48 +1,32 @@
|
|
1
1
|
================================================================================
|
2
|
-
Rails Active MCP
|
2
|
+
Rails Active MCP Installation Complete!
|
3
3
|
================================================================================
|
4
4
|
|
5
|
-
|
6
|
-
- Initializer created at: config/initializers/rails_active_mcp.rb
|
7
|
-
- Custom MCP server mounted at: /mcp
|
8
|
-
- MCP server configuration: mcp.ru
|
9
|
-
- Audit log will be created at: log/rails_active_mcp.log
|
5
|
+
🎉 Rails Active MCP v2.0 with Official MCP Ruby SDK has been installed!
|
10
6
|
|
11
|
-
|
7
|
+
📁 Files Created:
|
8
|
+
- config/initializers/rails_active_mcp.rb (Configuration)
|
9
|
+
- bin/rails-active-mcp-server (Main server executable)
|
10
|
+
- bin/rails-active-mcp-wrapper (Environment wrapper for Claude Desktop)
|
11
|
+
- mcp.ru (Rack configuration file)
|
12
12
|
|
13
|
-
|
13
|
+
🛠️ Available MCP Tools:
|
14
|
+
- console_execute: Execute Ruby code with safety checks
|
15
|
+
- model_info: Get detailed information about Rails models
|
16
|
+
- safe_query: Execute safe read-only database queries
|
17
|
+
- dry_run: Analyze Ruby code for safety without execution
|
14
18
|
|
15
|
-
|
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
|
+
🚀 Quick Start:
|
20
20
|
|
21
|
-
|
22
|
-
|
23
|
-
$ bundle exec rails-active-mcp-server
|
24
|
-
|
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
|
33
|
-
$ rackup mcp.ru -p 3001
|
34
|
-
|
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)
|
21
|
+
1. Test the server:
|
22
|
+
$ ./bin/rails-active-mcp-server
|
39
23
|
|
24
|
+
2. For Claude Desktop, add to claude_desktop_config.json:
|
40
25
|
{
|
41
26
|
"mcpServers": {
|
42
27
|
"rails-active-mcp": {
|
43
|
-
"command": "
|
44
|
-
"
|
45
|
-
"cwd": "<%= Rails.root %>",
|
28
|
+
"command": "/path/to/your/project/bin/rails-active-mcp-wrapper",
|
29
|
+
"cwd": "/path/to/your/project",
|
46
30
|
"env": {
|
47
31
|
"RAILS_ENV": "development",
|
48
32
|
"HOME": "/Users/your-username"
|
@@ -51,138 +35,20 @@ Next Steps:
|
|
51
35
|
}
|
52
36
|
}
|
53
37
|
|
54
|
-
|
55
|
-
|
56
|
-
{
|
57
|
-
"mcpServers": {
|
58
|
-
"rails-active-mcp": {
|
59
|
-
"command": "rails-active-mcp-server",
|
60
|
-
"args": ["stdio"],
|
61
|
-
"cwd": "/path/to/your/rails/project"
|
62
|
-
}
|
63
|
-
}
|
64
|
-
}
|
65
|
-
|
66
|
-
5. For other MCP clients (HTTP-based), add this to your MCP configuration:
|
67
|
-
{
|
68
|
-
"mcpServers": {
|
69
|
-
"rails-console": {
|
70
|
-
"command": "curl",
|
71
|
-
"args": ["-X", "POST", "-H", "Content-Type: application/json", "-d", "@-", "http://localhost:3000/mcp"]
|
72
|
-
}
|
73
|
-
}
|
74
|
-
}
|
75
|
-
|
76
|
-
6. Test the installation:
|
77
|
-
$ rails console
|
78
|
-
> RailsActiveMcp.safe?("User.count")
|
79
|
-
> RailsActiveMcp.execute("User.count")
|
80
|
-
|
81
|
-
Built-in Tools Available in Claude:
|
82
|
-
- rails_console_execute: Execute Ruby code in Rails console with safety checks
|
83
|
-
- rails_model_info: Get detailed information about Rails models
|
84
|
-
- rails_safe_query: Execute safe read-only database queries
|
85
|
-
- rails_dry_run: Analyze Ruby code for safety without execution
|
86
|
-
|
87
|
-
Extend with custom tools by modifying the MCP server implementation.
|
88
|
-
|
89
|
-
Security Notes:
|
90
|
-
- Production mode enables strict safety by default
|
91
|
-
- All executions are logged to the audit file
|
92
|
-
- Dangerous operations are blocked in safe mode
|
93
|
-
- Review the safety patterns in the configuration
|
94
|
-
|
95
|
-
Transport Modes:
|
96
|
-
- stdio: For Claude Desktop and compatible MCP clients (recommended)
|
97
|
-
- http: For HTTP-based integrations and web applications
|
98
|
-
|
99
|
-
Configuration Examples:
|
100
|
-
|
101
|
-
For Claude Desktop (default):
|
102
|
-
config.server_mode = :stdio
|
103
|
-
|
104
|
-
For HTTP web integrations:
|
105
|
-
config.server_mode = :http
|
106
|
-
config.server_host = 'localhost'
|
107
|
-
config.server_port = 3001
|
108
|
-
|
109
|
-
For Docker/remote access:
|
110
|
-
config.http_mode!(host: '0.0.0.0', port: 8080)
|
111
|
-
|
112
|
-
For development with multiple transport modes:
|
113
|
-
if Rails.env.development?
|
114
|
-
config.stdio_mode! # Claude Desktop
|
115
|
-
else
|
116
|
-
config.http_mode!(host: '0.0.0.0', port: 3001) # Production HTTP
|
117
|
-
end
|
118
|
-
|
119
|
-
Custom MCP Server Benefits:
|
120
|
-
- No external dependencies
|
121
|
-
- Full control over implementation
|
122
|
-
- Simplified deployment
|
123
|
-
- Enhanced security
|
124
|
-
- Works with Claude Desktop
|
125
|
-
|
126
|
-
Debugging and Troubleshooting:
|
127
|
-
|
128
|
-
For interactive debugging, use the MCP Inspector:
|
129
|
-
$ bin/debug-mcp-server --mode inspector
|
130
|
-
|
131
|
-
This will:
|
132
|
-
- Launch the MCP Inspector connected to your server
|
133
|
-
- Allow interactive testing of all tools
|
134
|
-
- Show real-time debug output and logs
|
135
|
-
|
136
|
-
Debug logging:
|
137
|
-
$ RAILS_MCP_DEBUG=1 bundle exec rails-active-mcp-server stdio
|
138
|
-
|
139
|
-
View Claude Desktop logs:
|
140
|
-
$ tail -f ~/Library/Logs/Claude/mcp*.log # macOS
|
141
|
-
$ tail -f ~/.config/claude-desktop/logs/*.log # Linux
|
142
|
-
|
143
|
-
Common issues:
|
144
|
-
|
145
|
-
1. Ruby Version Manager Conflicts (Most Common Issue):
|
146
|
-
If you see errors like "Could not find 'bundler' (X.X.X)" or "Your Ruby version is X.X.X, but your Gemfile specified Y.Y.Y":
|
147
|
-
|
148
|
-
This happens because Claude Desktop uses system Ruby instead of your project's Ruby version.
|
149
|
-
|
150
|
-
Solution A - Use the wrapper script (Recommended):
|
151
|
-
In claude_desktop_config.json, use:
|
152
|
-
"command": "<%= Rails.root %>/bin/rails-active-mcp-wrapper"
|
153
|
-
|
154
|
-
Solution B - Create system symlink:
|
155
|
-
$ sudo ln -sf $(which ruby) /usr/local/bin/ruby
|
156
|
-
|
157
|
-
Solution C - Use absolute Ruby path:
|
158
|
-
In claude_desktop_config.json, change "command" to your full Ruby path:
|
159
|
-
"command": "$(which ruby)"
|
160
|
-
"args": ["<%= Rails.root %>/bin/rails-active-mcp-server", "stdio"]
|
161
|
-
|
162
|
-
2. Environment Variable Issues:
|
163
|
-
If you see "error loading config: $HOME is not defined":
|
164
|
-
|
165
|
-
This happens because Claude Desktop doesn't inherit all environment variables.
|
166
|
-
|
167
|
-
Solution: Add HOME to your env section in claude_desktop_config.json:
|
168
|
-
"env": {
|
169
|
-
"RAILS_ENV": "development",
|
170
|
-
"HOME": "/Users/your-username"
|
171
|
-
}
|
38
|
+
3. Restart Claude Desktop and start using the tools!
|
172
39
|
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
40
|
+
⚙️ Configuration:
|
41
|
+
Edit config/initializers/rails_active_mcp.rb to customize:
|
42
|
+
- allowed_commands: Shell commands that can be executed
|
43
|
+
- command_timeout: Execution timeout in seconds
|
44
|
+
- enable_logging: Enable/disable logging
|
45
|
+
- log_level: Logging verbosity (:debug, :info, :warn, :error)
|
178
46
|
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
- Check Claude logs: $ tail -f ~/Library/Logs/Claude/mcp*.log
|
184
|
-
- Test environment variables: $ echo $HOME (should show your home directory)
|
47
|
+
🔧 Troubleshooting:
|
48
|
+
- Use the wrapper script to avoid Ruby version manager conflicts
|
49
|
+
- Set RAILS_MCP_DEBUG=1 for verbose logging
|
50
|
+
- Ensure Claude Desktop has correct paths and environment variables
|
185
51
|
|
186
|
-
|
52
|
+
📚 Documentation: https://github.com/goodpie/rails-active-mcp
|
187
53
|
|
188
54
|
================================================================================
|
@@ -1,43 +1,42 @@
|
|
1
1
|
require 'rails_active_mcp'
|
2
2
|
|
3
3
|
RailsActiveMcp.configure do |config|
|
4
|
-
#
|
5
|
-
config.
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
#
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
config.
|
18
|
-
|
19
|
-
#
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
# Environment-specific settings
|
29
|
-
case Rails.env
|
30
|
-
when 'production'
|
31
|
-
config.production_mode! # Very strict settings
|
32
|
-
when 'development'
|
33
|
-
config.permissive_mode! # More relaxed for development
|
34
|
-
when 'test'
|
35
|
-
config.strict_mode! # Safe for testing
|
4
|
+
# Core configuration options
|
5
|
+
config.allowed_commands = %w[
|
6
|
+
ls pwd cat head tail grep find wc
|
7
|
+
rails console rails runner
|
8
|
+
bundle exec rspec bundle exec test
|
9
|
+
git status git log git diff
|
10
|
+
]
|
11
|
+
|
12
|
+
# Execution timeout in seconds
|
13
|
+
config.command_timeout = 30
|
14
|
+
|
15
|
+
# Logging configuration
|
16
|
+
config.enable_logging = true
|
17
|
+
config.log_level = :info # :debug, :info, :warn, :error
|
18
|
+
|
19
|
+
# Environment-specific adjustments
|
20
|
+
if Rails.env.production?
|
21
|
+
# More restrictive settings for production
|
22
|
+
config.log_level = :warn
|
23
|
+
config.command_timeout = 15
|
24
|
+
elsif Rails.env.development?
|
25
|
+
# More permissive settings for development
|
26
|
+
config.log_level = :debug
|
27
|
+
config.command_timeout = 60
|
36
28
|
end
|
37
|
-
|
38
|
-
# Add custom safety patterns
|
39
|
-
# config.add_safety_pattern(/CustomDangerousMethod/, "Custom dangerous operation")
|
40
|
-
|
41
|
-
# Operations that require manual confirmation
|
42
|
-
config.require_confirmation_for = %i[delete destroy update_all delete_all]
|
43
29
|
end
|
30
|
+
|
31
|
+
# Rails Active MCP is now ready!
|
32
|
+
#
|
33
|
+
# Available MCP Tools:
|
34
|
+
# - console_execute: Execute Ruby code with safety checks
|
35
|
+
# - model_info: Get detailed information about Rails models
|
36
|
+
# - safe_query: Execute safe read-only database queries
|
37
|
+
# - dry_run: Analyze Ruby code for safety without execution
|
38
|
+
#
|
39
|
+
# To start the server:
|
40
|
+
# bin/rails-active-mcp-server
|
41
|
+
#
|
42
|
+
# For Claude Desktop integration, see the post-install instructions.
|
@@ -1,7 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require_relative 'config/environment'
|
4
|
-
require 'rails_active_mcp'
|
4
|
+
require 'rails_active_mcp/sdk/server'
|
5
5
|
|
6
|
-
# Run the Rails Active MCP server
|
7
|
-
|
6
|
+
# Run the Rails Active MCP server using the official MCP Ruby SDK
|
7
|
+
# Note: This file is primarily for reference. The recommended way to run
|
8
|
+
# the server is using: bin/rails-active-mcp-server
|
9
|
+
|
10
|
+
server = RailsActiveMcp::SDK::Server.new
|
11
|
+
server.run
|
@@ -1,119 +1,58 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'fileutils'
|
2
4
|
|
3
5
|
module RailsActiveMcp
|
4
6
|
class Configuration
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
7
|
+
# Core configuration options
|
8
|
+
attr_accessor :allowed_commands, :command_timeout, :enable_logging, :log_level
|
9
|
+
|
10
|
+
# Safety and execution options
|
11
|
+
attr_accessor :safe_mode, :default_timeout, :max_results, :log_executions, :audit_file
|
12
|
+
attr_accessor :custom_safety_patterns, :allowed_models
|
10
13
|
|
11
14
|
def initialize
|
12
|
-
@
|
15
|
+
@allowed_commands = %w[
|
16
|
+
ls pwd cat head tail grep find wc
|
17
|
+
rails console rails runner
|
18
|
+
bundle exec rspec bundle exec test
|
19
|
+
git status git log git diff
|
20
|
+
]
|
21
|
+
@command_timeout = 30
|
22
|
+
@enable_logging = true
|
23
|
+
@log_level = :info
|
24
|
+
|
25
|
+
# Safety and execution defaults
|
13
26
|
@safe_mode = true
|
14
27
|
@default_timeout = 30
|
15
28
|
@max_results = 100
|
16
|
-
@
|
17
|
-
@
|
29
|
+
@log_executions = false
|
30
|
+
@audit_file = nil
|
18
31
|
@custom_safety_patterns = []
|
19
|
-
@
|
20
|
-
# Safe Rails.root access
|
21
|
-
if defined?(Rails) && Rails.respond_to?(:root) && Rails.root
|
22
|
-
@audit_file = rails_root_join('log',
|
23
|
-
'rails_active_mcp.log')
|
24
|
-
end
|
25
|
-
@enable_mutation_tools = false
|
26
|
-
@require_confirmation_for = %i[delete destroy update_all delete_all]
|
27
|
-
@execution_environment = :current # :current, :sandbox, :readonly_replica
|
28
|
-
@server_mode = :stdio # :stdio, :http
|
29
|
-
@server_host = 'localhost'
|
30
|
-
@server_port = 3001
|
31
|
-
end
|
32
|
-
|
33
|
-
# Safety configuration
|
34
|
-
def strict_mode!
|
35
|
-
@safe_mode = true
|
36
|
-
@enable_mutation_tools = false
|
37
|
-
@default_timeout = 15
|
38
|
-
@max_results = 50
|
39
|
-
end
|
40
|
-
|
41
|
-
def permissive_mode!
|
42
|
-
@safe_mode = false
|
43
|
-
@enable_mutation_tools = true
|
44
|
-
@default_timeout = 60
|
45
|
-
@max_results = 1000
|
46
|
-
end
|
47
|
-
|
48
|
-
def production_mode!
|
49
|
-
strict_mode!
|
50
|
-
@execution_environment = :readonly_replica
|
51
|
-
@log_executions = true
|
52
|
-
@require_confirmation_for = %i[delete destroy update create save]
|
53
|
-
end
|
54
|
-
|
55
|
-
# Model access configuration
|
56
|
-
def allow_models(*models)
|
57
|
-
@allowed_models.concat(models.map(&:to_s))
|
58
|
-
end
|
59
|
-
|
60
|
-
def block_models(*models)
|
61
|
-
@blocked_models.concat(models.map(&:to_s))
|
32
|
+
@allowed_models = []
|
62
33
|
end
|
63
34
|
|
64
|
-
def add_safety_pattern(pattern, description = nil)
|
65
|
-
@custom_safety_patterns << { pattern: pattern, description: description }
|
66
|
-
end
|
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
|
-
|
83
|
-
# Validation
|
84
35
|
def model_allowed?(model_name)
|
85
|
-
|
86
|
-
|
87
|
-
# Check if specifically blocked
|
88
|
-
return false if @blocked_models.include?(model_str)
|
89
|
-
|
90
|
-
# If allow list is empty, allow all (except blocked)
|
91
|
-
return true if @allowed_models.empty?
|
36
|
+
return true if @allowed_models.empty? # Allow all if none specified
|
92
37
|
|
93
|
-
|
94
|
-
@allowed_models.include?(model_str)
|
38
|
+
@allowed_models.include?(model_name.to_s)
|
95
39
|
end
|
96
40
|
|
97
|
-
def
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
41
|
+
def valid?
|
42
|
+
allowed_commands.is_a?(Array) &&
|
43
|
+
command_timeout.is_a?(Numeric) && command_timeout > 0 &&
|
44
|
+
[true, false].include?(enable_logging) &&
|
45
|
+
%i[debug info warn error].include?(log_level) &&
|
46
|
+
[true, false].include?(safe_mode) &&
|
47
|
+
default_timeout.is_a?(Numeric) && default_timeout > 0 &&
|
48
|
+
max_results.is_a?(Numeric) && max_results > 0 &&
|
49
|
+
[true, false].include?(log_executions) &&
|
50
|
+
custom_safety_patterns.is_a?(Array) &&
|
51
|
+
allowed_models.is_a?(Array)
|
107
52
|
end
|
108
53
|
|
109
|
-
|
110
|
-
|
111
|
-
def rails_root_join(*args)
|
112
|
-
if defined?(Rails) && Rails.respond_to?(:root) && Rails.root
|
113
|
-
Rails.root.join(*args)
|
114
|
-
else
|
115
|
-
File.join(Dir.pwd, *args)
|
116
|
-
end
|
54
|
+
def reset!
|
55
|
+
initialize
|
117
56
|
end
|
118
57
|
end
|
119
58
|
end
|
@@ -194,10 +194,13 @@ module RailsActiveMcp
|
|
194
194
|
def execute_with_captured_output(code)
|
195
195
|
# Thread-safe output capture using mutex
|
196
196
|
@execution_mutex.synchronize do
|
197
|
-
# Capture both stdout and
|
197
|
+
# Capture both stdout and stderr to prevent any Rails output leakage
|
198
198
|
old_stdout = $stdout
|
199
|
+
old_stderr = $stderr
|
199
200
|
captured_output = StringIO.new
|
201
|
+
captured_errors = StringIO.new
|
200
202
|
$stdout = captured_output
|
203
|
+
$stderr = captured_errors
|
201
204
|
|
202
205
|
begin
|
203
206
|
# Create thread-safe execution context
|
@@ -209,17 +212,22 @@ module RailsActiveMcp
|
|
209
212
|
execution_time = Time.now - start_time
|
210
213
|
|
211
214
|
output = captured_output.string
|
215
|
+
errors = captured_errors.string
|
216
|
+
|
217
|
+
# Combine output and errors for comprehensive result
|
218
|
+
combined_output = [output, errors].reject(&:empty?).join("\n")
|
212
219
|
|
213
220
|
{
|
214
221
|
success: true,
|
215
222
|
return_value: return_value,
|
216
|
-
output:
|
223
|
+
output: combined_output,
|
217
224
|
return_value_string: safe_inspect(return_value),
|
218
225
|
execution_time: execution_time,
|
219
226
|
code: code
|
220
227
|
}
|
221
228
|
rescue StandardError => e
|
222
229
|
execution_time = Time.now - start_time if defined?(start_time)
|
230
|
+
errors = captured_errors.string
|
223
231
|
|
224
232
|
{
|
225
233
|
success: false,
|
@@ -227,10 +235,12 @@ module RailsActiveMcp
|
|
227
235
|
error_class: e.class.name,
|
228
236
|
backtrace: e.backtrace&.first(10),
|
229
237
|
execution_time: execution_time,
|
230
|
-
code: code
|
238
|
+
code: code,
|
239
|
+
stderr: errors.empty? ? nil : errors
|
231
240
|
}
|
232
241
|
ensure
|
233
242
|
$stdout = old_stdout if old_stdout
|
243
|
+
$stderr = old_stderr if old_stderr
|
234
244
|
end
|
235
245
|
end
|
236
246
|
end
|