rails-active-mcp 2.0.7 → 2.0.12
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/.rubocop.yml +141 -0
- data/README.md +3 -3
- data/examples/rails_app_integration.md +405 -0
- data/exe/rails-active-mcp-server +8 -8
- data/gemfiles/rails_6.0.gemfile +34 -0
- data/gemfiles/rails_6.1.gemfile +34 -0
- data/gemfiles/rails_7.0.gemfile +34 -0
- data/gemfiles/rails_7.1.gemfile +34 -0
- data/gemfiles/rails_7.2.gemfile +34 -0
- data/lib/generators/rails_active_mcp/install/install_generator.rb +44 -94
- data/lib/generators/rails_active_mcp/install/templates/README.md +134 -54
- data/lib/generators/rails_active_mcp/install/templates/initializer.rb +44 -6
- data/lib/generators/rails_active_mcp/install/templates/rails-active-mcp-server +104 -0
- data/lib/generators/rails_active_mcp/install/templates/rails-active-mcp-wrapper +94 -0
- data/lib/rails_active_mcp/configuration.rb +44 -4
- data/lib/rails_active_mcp/console_executor.rb +185 -83
- data/lib/rails_active_mcp/engine.rb +2 -2
- data/lib/rails_active_mcp/garbage_collection_utils.rb +13 -0
- data/lib/rails_active_mcp/safety_checker.rb +17 -7
- data/lib/rails_active_mcp/sdk/server.rb +1 -1
- data/lib/rails_active_mcp/sdk/tools/console_execute_tool.rb +0 -2
- data/lib/rails_active_mcp/sdk/tools/dry_run_tool.rb +0 -2
- data/lib/rails_active_mcp/sdk/tools/model_info_tool.rb +1 -3
- data/lib/rails_active_mcp/sdk/tools/safe_query_tool.rb +0 -2
- data/lib/rails_active_mcp/tasks.rake +238 -82
- data/lib/rails_active_mcp/version.rb +1 -1
- data/lib/rails_active_mcp.rb +4 -3
- data/mcp.ru +2 -2
- data/rails_active_mcp.gemspec +62 -14
- metadata +72 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fee611445971a5e113a23146281a9f2a68d0c8c0690213df2704ee7fb80f7700
|
4
|
+
data.tar.gz: ce6ba7ab86616fd0a5a0e60aff50e9c4e8f29101a9866597e1dfd99ef2c6ee85
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 312b0f2384b4cc7a57b0be9284a52c559897d10e31487eb859cd70b9e5dc385a1005a245cff4a42b7d3abe7f0480b1fdcd8caa317e7ff2388fbeb635ed447c13
|
7
|
+
data.tar.gz: 875467cc1ad75645d32607f2c6c3a98951807da776b626dc113f186720fc6042fe90303fe19ae8c230f036a2a085e6caa1e38e518da0a3ef71356d2cbbce10fd
|
data/.rubocop.yml
ADDED
@@ -0,0 +1,141 @@
|
|
1
|
+
plugins:
|
2
|
+
- rubocop-rails
|
3
|
+
- rubocop-rspec
|
4
|
+
|
5
|
+
AllCops:
|
6
|
+
NewCops: enable
|
7
|
+
SuggestExtensions: false
|
8
|
+
TargetRubyVersion: 3.1
|
9
|
+
Exclude:
|
10
|
+
- 'bin/bundle'
|
11
|
+
- 'bin/setup'
|
12
|
+
- 'vendor/**/*'
|
13
|
+
- 'tmp/**/*'
|
14
|
+
- 'db/schema.rb'
|
15
|
+
- 'log/**/*'
|
16
|
+
|
17
|
+
# Documentation is not always necessary for utility classes and tools
|
18
|
+
Style/Documentation:
|
19
|
+
Enabled: false
|
20
|
+
|
21
|
+
# Allow longer classes for main functionality classes
|
22
|
+
Metrics/ClassLength:
|
23
|
+
Max: 400
|
24
|
+
Exclude:
|
25
|
+
- 'bin/*'
|
26
|
+
|
27
|
+
# Allow longer methods for setup/configuration methods
|
28
|
+
Metrics/MethodLength:
|
29
|
+
Max: 50
|
30
|
+
Exclude:
|
31
|
+
- 'bin/*'
|
32
|
+
- 'lib/generators/**/*'
|
33
|
+
|
34
|
+
# Allow higher complexity for main execution methods
|
35
|
+
Metrics/AbcSize:
|
36
|
+
Max: 55
|
37
|
+
Exclude:
|
38
|
+
- 'bin/*'
|
39
|
+
|
40
|
+
Metrics/CyclomaticComplexity:
|
41
|
+
Max: 15
|
42
|
+
|
43
|
+
Metrics/PerceivedComplexity:
|
44
|
+
Max: 15
|
45
|
+
|
46
|
+
# Allow longer blocks in specs and configuration
|
47
|
+
Metrics/BlockLength:
|
48
|
+
Max: 50
|
49
|
+
Exclude:
|
50
|
+
- 'spec/**/*'
|
51
|
+
- 'lib/rails_active_mcp/tasks.rake'
|
52
|
+
- 'lib/generators/**/*'
|
53
|
+
|
54
|
+
# Allow longer lines for error messages and documentation
|
55
|
+
Layout/LineLength:
|
56
|
+
Max: 150
|
57
|
+
Exclude:
|
58
|
+
- 'bin/*'
|
59
|
+
- 'exe/*'
|
60
|
+
|
61
|
+
# Disable some style checks that are too strict for utility scripts
|
62
|
+
Lint/UnusedMethodArgument:
|
63
|
+
Enabled: false
|
64
|
+
|
65
|
+
# Allow safe navigation preference but don't enforce it everywhere
|
66
|
+
Style/SafeNavigation:
|
67
|
+
Enabled: true
|
68
|
+
|
69
|
+
# Allow both single and double quotes
|
70
|
+
Style/StringLiterals:
|
71
|
+
EnforcedStyle: single_quotes
|
72
|
+
|
73
|
+
# Don't enforce frozen string literals in every file
|
74
|
+
Style/FrozenStringLiteralComment:
|
75
|
+
Enabled: false
|
76
|
+
|
77
|
+
# Allow numeric comparisons with zero
|
78
|
+
Style/NumericPredicate:
|
79
|
+
Enabled: false
|
80
|
+
|
81
|
+
# Rails specific configurations
|
82
|
+
Rails:
|
83
|
+
Enabled: true
|
84
|
+
|
85
|
+
# RSpec specific configurations
|
86
|
+
RSpec:
|
87
|
+
Enabled: true
|
88
|
+
|
89
|
+
# Gemspec specific configurations
|
90
|
+
Gemspec/DevelopmentDependencies:
|
91
|
+
Enabled: false
|
92
|
+
|
93
|
+
# Allow some duplication in methods that handle similar cases
|
94
|
+
Lint/DuplicateMethods:
|
95
|
+
Enabled: false
|
96
|
+
|
97
|
+
Lint/DuplicateBranch:
|
98
|
+
Enabled: false
|
99
|
+
|
100
|
+
# RSpec specific overrides for test quality
|
101
|
+
RSpec/MultipleExpectations:
|
102
|
+
Max: 5
|
103
|
+
|
104
|
+
RSpec/ExampleLength:
|
105
|
+
Max: 15
|
106
|
+
|
107
|
+
RSpec/DescribeClass:
|
108
|
+
Enabled: false
|
109
|
+
|
110
|
+
RSpec/InstanceVariable:
|
111
|
+
Enabled: false
|
112
|
+
|
113
|
+
RSpec/BeforeAfterAll:
|
114
|
+
Enabled: false
|
115
|
+
|
116
|
+
RSpec/VerifiedDoubles:
|
117
|
+
Enabled: false
|
118
|
+
|
119
|
+
RSpec/MessageSpies:
|
120
|
+
Enabled: false
|
121
|
+
|
122
|
+
RSpec/MessageChain:
|
123
|
+
Enabled: false
|
124
|
+
|
125
|
+
RSpec/ReceiveMessages:
|
126
|
+
Enabled: false
|
127
|
+
|
128
|
+
RSpec/ScatteredSetup:
|
129
|
+
Enabled: false
|
130
|
+
|
131
|
+
RSpec/SpecFilePathFormat:
|
132
|
+
Enabled: false
|
133
|
+
|
134
|
+
# Allow Time.zone vs Time.now flexibility
|
135
|
+
Rails/TimeZone:
|
136
|
+
Enabled: false
|
137
|
+
|
138
|
+
# Naming conventions - allow short parameter names in specs/tools
|
139
|
+
Naming/MethodParameterName:
|
140
|
+
Exclude:
|
141
|
+
- 'spec/**/*'
|
data/README.md
CHANGED
@@ -24,13 +24,13 @@ gem 'rails-active-mcp'
|
|
24
24
|
And then execute:
|
25
25
|
|
26
26
|
```bash
|
27
|
-
|
27
|
+
bundle install
|
28
28
|
```
|
29
29
|
|
30
30
|
Run the installer:
|
31
31
|
|
32
32
|
```bash
|
33
|
-
|
33
|
+
rails generate rails_active_mcp:install
|
34
34
|
```
|
35
35
|
|
36
36
|
This will:
|
@@ -298,4 +298,4 @@ The gem is available as open source under the [MIT License](https://opensource.o
|
|
298
298
|
|
299
299
|
### Previous Versions
|
300
300
|
|
301
|
-
See [CHANGELOG.md](CHANGELOG.md) for detailed version history.
|
301
|
+
See [CHANGELOG.md](CHANGELOG.md) for detailed version history.
|
@@ -0,0 +1,405 @@
|
|
1
|
+
# Rails Active MCP - Real-World Integration Examples
|
2
|
+
|
3
|
+
This guide demonstrates how to integrate Rails Active MCP in various real-world scenarios, following the best practices outlined in the [Rails application structure guide](https://dev.to/kimrgrey/tuning-rails-application-structure-5f74).
|
4
|
+
|
5
|
+
## E-commerce Application Example
|
6
|
+
|
7
|
+
### Model Setup
|
8
|
+
```ruby
|
9
|
+
# app/models/user.rb
|
10
|
+
class User < ApplicationRecord
|
11
|
+
has_many :orders, dependent: :destroy
|
12
|
+
has_one :profile, dependent: :destroy
|
13
|
+
|
14
|
+
validates :email, presence: true, uniqueness: true
|
15
|
+
scope :active, -> { where(active: true) }
|
16
|
+
end
|
17
|
+
|
18
|
+
# app/models/order.rb
|
19
|
+
class Order < ApplicationRecord
|
20
|
+
belongs_to :user
|
21
|
+
has_many :order_items, dependent: :destroy
|
22
|
+
has_many :products, through: :order_items
|
23
|
+
|
24
|
+
validates :total_amount, presence: true, numericality: { greater_than: 0 }
|
25
|
+
scope :recent, -> { where('created_at > ?', 1.week.ago) }
|
26
|
+
end
|
27
|
+
|
28
|
+
# app/models/product.rb
|
29
|
+
class Product < ApplicationRecord
|
30
|
+
has_many :order_items
|
31
|
+
has_many :orders, through: :order_items
|
32
|
+
|
33
|
+
validates :name, presence: true
|
34
|
+
validates :price, presence: true, numericality: { greater_than: 0 }
|
35
|
+
scope :available, -> { where(available: true) }
|
36
|
+
end
|
37
|
+
```
|
38
|
+
|
39
|
+
### Configuration for E-commerce
|
40
|
+
```ruby
|
41
|
+
# config/initializers/rails_active_mcp.rb
|
42
|
+
RailsActiveMcp.configure do |config|
|
43
|
+
# Core safety settings
|
44
|
+
config.safe_mode = true
|
45
|
+
config.max_results = 100
|
46
|
+
config.command_timeout = 30
|
47
|
+
|
48
|
+
# Environment-specific settings
|
49
|
+
case Rails.env
|
50
|
+
when 'production'
|
51
|
+
# Strict production settings
|
52
|
+
config.safe_mode = true
|
53
|
+
config.max_results = 50
|
54
|
+
config.command_timeout = 15
|
55
|
+
config.log_executions = true
|
56
|
+
|
57
|
+
# Only allow safe models in production
|
58
|
+
config.allowed_models = %w[User Order Product OrderItem]
|
59
|
+
|
60
|
+
when 'development'
|
61
|
+
# More permissive for development
|
62
|
+
config.safe_mode = false
|
63
|
+
config.max_results = 200
|
64
|
+
config.command_timeout = 60
|
65
|
+
config.log_level = :debug
|
66
|
+
|
67
|
+
when 'staging'
|
68
|
+
# Production-like but slightly more permissive
|
69
|
+
config.safe_mode = true
|
70
|
+
config.max_results = 100
|
71
|
+
config.command_timeout = 30
|
72
|
+
config.log_executions = true
|
73
|
+
end
|
74
|
+
|
75
|
+
# Custom safety patterns for e-commerce
|
76
|
+
config.custom_safety_patterns = [
|
77
|
+
{
|
78
|
+
pattern: /payment.*delete|destroy.*payment/i,
|
79
|
+
description: "Payment data modification is dangerous"
|
80
|
+
},
|
81
|
+
{
|
82
|
+
pattern: /User.*\.update_all.*role/i,
|
83
|
+
description: "Mass role updates are dangerous"
|
84
|
+
}
|
85
|
+
]
|
86
|
+
end
|
87
|
+
```
|
88
|
+
|
89
|
+
### Claude Desktop Queries for E-commerce
|
90
|
+
|
91
|
+
#### Sales Analytics
|
92
|
+
```ruby
|
93
|
+
# Ask Claude: "What are our sales metrics for the last week?"
|
94
|
+
Order.recent.sum(:total_amount)
|
95
|
+
Order.recent.count
|
96
|
+
Order.recent.average(:total_amount)
|
97
|
+
|
98
|
+
# Ask Claude: "Who are our top customers by order value?"
|
99
|
+
User.joins(:orders)
|
100
|
+
.group('users.id', 'users.email')
|
101
|
+
.order('SUM(orders.total_amount) DESC')
|
102
|
+
.limit(10)
|
103
|
+
.pluck('users.email', 'SUM(orders.total_amount)')
|
104
|
+
```
|
105
|
+
|
106
|
+
#### Inventory Management
|
107
|
+
```ruby
|
108
|
+
# Ask Claude: "Which products are running low on inventory?"
|
109
|
+
Product.where('inventory_count < ?', 10)
|
110
|
+
.order(:inventory_count)
|
111
|
+
.pluck(:name, :inventory_count)
|
112
|
+
|
113
|
+
# Ask Claude: "What are our best-selling products this month?"
|
114
|
+
Product.joins(:order_items)
|
115
|
+
.where(order_items: { created_at: 1.month.ago.. })
|
116
|
+
.group(:name)
|
117
|
+
.order('COUNT(*) DESC')
|
118
|
+
.limit(10)
|
119
|
+
.count
|
120
|
+
```
|
121
|
+
|
122
|
+
#### Customer Support
|
123
|
+
```ruby
|
124
|
+
# Ask Claude: "Find recent orders for customer email@example.com"
|
125
|
+
User.find_by(email: 'email@example.com')
|
126
|
+
&.orders
|
127
|
+
&.recent
|
128
|
+
&.includes(:products)
|
129
|
+
&.map { |o| { id: o.id, total: o.total_amount, products: o.products.pluck(:name) } }
|
130
|
+
|
131
|
+
# Ask Claude: "Check the User model structure"
|
132
|
+
# Uses model_info tool to show schema, associations, validations
|
133
|
+
```
|
134
|
+
|
135
|
+
## SaaS Application Example
|
136
|
+
|
137
|
+
### Multi-tenant Setup
|
138
|
+
```ruby
|
139
|
+
# app/models/account.rb
|
140
|
+
class Account < ApplicationRecord
|
141
|
+
has_many :users, dependent: :destroy
|
142
|
+
has_many :projects, dependent: :destroy
|
143
|
+
|
144
|
+
validates :name, presence: true
|
145
|
+
validates :plan, inclusion: { in: %w[free pro enterprise] }
|
146
|
+
end
|
147
|
+
|
148
|
+
# app/models/project.rb
|
149
|
+
class Project < ApplicationRecord
|
150
|
+
belongs_to :account
|
151
|
+
belongs_to :user, -> { where(role: 'owner') }
|
152
|
+
has_many :tasks, dependent: :destroy
|
153
|
+
|
154
|
+
validates :name, presence: true
|
155
|
+
scope :active, -> { where(archived: false) }
|
156
|
+
end
|
157
|
+
```
|
158
|
+
|
159
|
+
### SaaS-specific Configuration
|
160
|
+
```ruby
|
161
|
+
# config/initializers/rails_active_mcp.rb
|
162
|
+
RailsActiveMcp.configure do |config|
|
163
|
+
config.safe_mode = true
|
164
|
+
config.max_results = 100
|
165
|
+
|
166
|
+
# Tenant isolation safety
|
167
|
+
config.custom_safety_patterns = [
|
168
|
+
{
|
169
|
+
pattern: /Account.*delete_all|destroy_all/i,
|
170
|
+
description: "Account mass operations are forbidden"
|
171
|
+
},
|
172
|
+
{
|
173
|
+
pattern: /User.*update_all.*account_id/i,
|
174
|
+
description: "Cross-tenant user moves are dangerous"
|
175
|
+
}
|
176
|
+
]
|
177
|
+
|
178
|
+
# Production tenant restrictions
|
179
|
+
if Rails.env.production?
|
180
|
+
config.allowed_models = %w[Account User Project Task]
|
181
|
+
config.max_results = 50
|
182
|
+
end
|
183
|
+
end
|
184
|
+
```
|
185
|
+
|
186
|
+
### Claude Queries for SaaS Analytics
|
187
|
+
```ruby
|
188
|
+
# Ask Claude: "How many active accounts do we have by plan?"
|
189
|
+
Account.group(:plan).count
|
190
|
+
|
191
|
+
# Ask Claude: "What's our monthly recurring revenue?"
|
192
|
+
Account.where(plan: ['pro', 'enterprise'])
|
193
|
+
.sum('CASE
|
194
|
+
WHEN plan = "pro" THEN 29
|
195
|
+
WHEN plan = "enterprise" THEN 99
|
196
|
+
ELSE 0 END')
|
197
|
+
|
198
|
+
# Ask Claude: "Which accounts have the most projects?"
|
199
|
+
Account.joins(:projects)
|
200
|
+
.group('accounts.name')
|
201
|
+
.order('COUNT(projects.id) DESC')
|
202
|
+
.limit(10)
|
203
|
+
.count
|
204
|
+
```
|
205
|
+
|
206
|
+
## Content Management System Example
|
207
|
+
|
208
|
+
### CMS Model Structure
|
209
|
+
```ruby
|
210
|
+
# app/models/article.rb
|
211
|
+
class Article < ApplicationRecord
|
212
|
+
belongs_to :author, class_name: 'User'
|
213
|
+
belongs_to :category
|
214
|
+
has_many :comments, dependent: :destroy
|
215
|
+
|
216
|
+
validates :title, presence: true
|
217
|
+
validates :content, presence: true
|
218
|
+
|
219
|
+
scope :published, -> { where(published: true) }
|
220
|
+
scope :recent, -> { order(created_at: :desc) }
|
221
|
+
end
|
222
|
+
|
223
|
+
# app/models/category.rb
|
224
|
+
class Category < ApplicationRecord
|
225
|
+
has_many :articles
|
226
|
+
validates :name, presence: true, uniqueness: true
|
227
|
+
end
|
228
|
+
```
|
229
|
+
|
230
|
+
### CMS Configuration
|
231
|
+
```ruby
|
232
|
+
# config/initializers/rails_active_mcp.rb
|
233
|
+
RailsActiveMcp.configure do |config|
|
234
|
+
config.safe_mode = true
|
235
|
+
|
236
|
+
# Content-specific safety patterns
|
237
|
+
config.custom_safety_patterns = [
|
238
|
+
{
|
239
|
+
pattern: /Article.*delete_all.*published.*true/i,
|
240
|
+
description: "Mass deletion of published articles is dangerous"
|
241
|
+
}
|
242
|
+
]
|
243
|
+
|
244
|
+
# Environment-specific settings
|
245
|
+
case Rails.env
|
246
|
+
when 'production'
|
247
|
+
config.allowed_models = %w[Article Category User Comment]
|
248
|
+
config.max_results = 25 # Smaller for content queries
|
249
|
+
end
|
250
|
+
end
|
251
|
+
```
|
252
|
+
|
253
|
+
### Claude Queries for Content Analytics
|
254
|
+
```ruby
|
255
|
+
# Ask Claude: "What are our most popular categories?"
|
256
|
+
Category.joins(:articles)
|
257
|
+
.where(articles: { published: true })
|
258
|
+
.group(:name)
|
259
|
+
.order('COUNT(articles.id) DESC')
|
260
|
+
.count
|
261
|
+
|
262
|
+
# Ask Claude: "Show me recent article performance"
|
263
|
+
Article.published
|
264
|
+
.recent
|
265
|
+
.limit(10)
|
266
|
+
.pluck(:title, :views_count, :created_at)
|
267
|
+
|
268
|
+
# Ask Claude: "Find articles that need moderation"
|
269
|
+
Article.joins(:comments)
|
270
|
+
.where(comments: { flagged: true })
|
271
|
+
.distinct
|
272
|
+
.pluck(:title, :id)
|
273
|
+
```
|
274
|
+
|
275
|
+
## Advanced Safety Patterns
|
276
|
+
|
277
|
+
### Custom Validators
|
278
|
+
```ruby
|
279
|
+
# config/initializers/rails_active_mcp.rb
|
280
|
+
RailsActiveMcp.configure do |config|
|
281
|
+
# Financial data protection
|
282
|
+
config.custom_safety_patterns += [
|
283
|
+
{ pattern: /payment|billing|card|bank/i, description: "Financial data access" },
|
284
|
+
{ pattern: /password|token|secret|key/i, description: "Sensitive credential access" },
|
285
|
+
{ pattern: /delete.*where.*id.*in/i, description: "Bulk deletion by ID list" }
|
286
|
+
]
|
287
|
+
|
288
|
+
# Model-specific restrictions
|
289
|
+
config.allowed_models = case Rails.env
|
290
|
+
when 'production'
|
291
|
+
%w[User Order Product Customer Invoice] # Whitelist approach
|
292
|
+
else
|
293
|
+
[] # Empty = allow all models
|
294
|
+
end
|
295
|
+
end
|
296
|
+
```
|
297
|
+
|
298
|
+
### Environment-specific Presets
|
299
|
+
```ruby
|
300
|
+
# config/initializers/rails_active_mcp.rb
|
301
|
+
RailsActiveMcp.configure do |config|
|
302
|
+
case Rails.env
|
303
|
+
when 'production'
|
304
|
+
# Ultra-safe production mode
|
305
|
+
config.safe_mode = true
|
306
|
+
config.command_timeout = 10
|
307
|
+
config.max_results = 25
|
308
|
+
config.log_executions = true
|
309
|
+
|
310
|
+
when 'staging'
|
311
|
+
# Production-like testing
|
312
|
+
config.safe_mode = true
|
313
|
+
config.command_timeout = 20
|
314
|
+
config.max_results = 50
|
315
|
+
config.log_executions = true
|
316
|
+
|
317
|
+
when 'development'
|
318
|
+
# Developer-friendly
|
319
|
+
config.safe_mode = false
|
320
|
+
config.command_timeout = 60
|
321
|
+
config.max_results = 200
|
322
|
+
config.log_level = :debug
|
323
|
+
|
324
|
+
when 'test'
|
325
|
+
# Fast and minimal for tests
|
326
|
+
config.safe_mode = true
|
327
|
+
config.command_timeout = 5
|
328
|
+
config.max_results = 10
|
329
|
+
config.log_executions = false
|
330
|
+
end
|
331
|
+
end
|
332
|
+
```
|
333
|
+
|
334
|
+
## Best Practices
|
335
|
+
|
336
|
+
### 1. Always Use Limits
|
337
|
+
```ruby
|
338
|
+
# ✅ Good - Always include limits
|
339
|
+
User.where(active: true).limit(10)
|
340
|
+
Order.recent.limit(20)
|
341
|
+
|
342
|
+
# ❌ Avoid - Unlimited queries can overwhelm Claude
|
343
|
+
User.all
|
344
|
+
Order.where(status: 'pending')
|
345
|
+
```
|
346
|
+
|
347
|
+
### 2. Prefer Aggregations Over Raw Data
|
348
|
+
```ruby
|
349
|
+
# ✅ Good - Summary data
|
350
|
+
User.group(:status).count
|
351
|
+
Order.group_by_day(:created_at).sum(:total_amount)
|
352
|
+
|
353
|
+
# ❌ Less useful - Raw data dumps
|
354
|
+
User.pluck(:email, :status, :created_at)
|
355
|
+
```
|
356
|
+
|
357
|
+
### 3. Use Meaningful Scopes
|
358
|
+
```ruby
|
359
|
+
# ✅ Good - Readable business logic
|
360
|
+
User.active.recent_signups.count
|
361
|
+
Order.completed.this_month.sum(:total_amount)
|
362
|
+
|
363
|
+
# ❌ Less clear - Complex inline conditions
|
364
|
+
User.where(active: true, created_at: 1.week.ago..).count
|
365
|
+
```
|
366
|
+
|
367
|
+
### 4. Structure Claude Queries Naturally
|
368
|
+
```ruby
|
369
|
+
# Ask Claude natural questions:
|
370
|
+
# "How many users signed up this week?"
|
371
|
+
# "What's our average order value?"
|
372
|
+
# "Which products need restocking?"
|
373
|
+
# "Show me the User model structure"
|
374
|
+
```
|
375
|
+
|
376
|
+
## Troubleshooting Common Issues
|
377
|
+
|
378
|
+
### Performance Issues
|
379
|
+
```ruby
|
380
|
+
# Monitor execution times
|
381
|
+
rails rails_active_mcp:benchmark
|
382
|
+
|
383
|
+
# Check for slow queries
|
384
|
+
rails rails_active_mcp:status
|
385
|
+
```
|
386
|
+
|
387
|
+
### Safety Violations
|
388
|
+
```ruby
|
389
|
+
# Test code safety before asking Claude
|
390
|
+
rails rails_active_mcp:check_safety['User.delete_all']
|
391
|
+
|
392
|
+
# View current configuration
|
393
|
+
rails rails_active_mcp:validate_config
|
394
|
+
```
|
395
|
+
|
396
|
+
### Claude Desktop Integration
|
397
|
+
```ruby
|
398
|
+
# Generate Claude Desktop config
|
399
|
+
rails rails_active_mcp:install_claude_config
|
400
|
+
|
401
|
+
# Test server connectivity
|
402
|
+
bin/rails-active-mcp-wrapper
|
403
|
+
```
|
404
|
+
|
405
|
+
This comprehensive integration guide helps Rails developers understand how to effectively use Rails Active MCP in real-world applications, following modern Rails patterns and ensuring secure, efficient AI-powered database interactions.
|
data/exe/rails-active-mcp-server
CHANGED
@@ -4,11 +4,11 @@
|
|
4
4
|
# Require essential gems first
|
5
5
|
require 'json'
|
6
6
|
require 'stringio'
|
7
|
+
require 'fileutils'
|
7
8
|
|
8
9
|
# CRITICAL: Redirect stdout IMMEDIATELY for stdio mode to prevent any output interference
|
9
10
|
# This must happen before any other gem loading
|
10
11
|
original_stdout = $stdout
|
11
|
-
original_stderr = $stderr
|
12
12
|
|
13
13
|
# Determine if we should redirect output (stdio mode or explicit request)
|
14
14
|
should_redirect = (ARGV.first == 'stdio' || ARGV.first.nil?) && !ENV['RAILS_MCP_DEBUG']
|
@@ -16,7 +16,7 @@ should_redirect = (ARGV.first == 'stdio' || ARGV.first.nil?) && !ENV['RAILS_MCP_
|
|
16
16
|
if should_redirect
|
17
17
|
# Create log directory early
|
18
18
|
log_dir = File.join(Dir.pwd, 'log')
|
19
|
-
|
19
|
+
FileUtils.mkdir_p(log_dir)
|
20
20
|
|
21
21
|
# Redirect stderr to log file immediately, before any loading
|
22
22
|
stderr_log = File.join(log_dir, 'rails_mcp_stderr.log')
|
@@ -74,8 +74,8 @@ end
|
|
74
74
|
|
75
75
|
# Parse command line options
|
76
76
|
transport = ARGV[0] || 'stdio'
|
77
|
-
|
78
|
-
|
77
|
+
ARGV.include?('--port') ? ARGV[ARGV.index('--port') + 1].to_i : 3001
|
78
|
+
ARGV.include?('--host') ? ARGV[ARGV.index('--host') + 1] : 'localhost'
|
79
79
|
|
80
80
|
# Determine and set correct working directory
|
81
81
|
def find_rails_root(start_dir = Dir.pwd)
|
@@ -116,7 +116,9 @@ elsif rails_root.nil?
|
|
116
116
|
warn "[#{Time.now}] [RAILS-MCP] ERROR: Could not locate Gemfile in current directory: #{Dir.pwd}"
|
117
117
|
warn "[#{Time.now}] [RAILS-MCP] ERROR: Please ensure you're running from a Rails application root directory"
|
118
118
|
warn "[#{Time.now}] [RAILS-MCP] ERROR: Current directory contents:"
|
119
|
-
Dir.entries('.').each
|
119
|
+
Dir.entries('.').each do |entry|
|
120
|
+
warn "[#{Time.now}] [RAILS-MCP] ERROR: #{entry}" unless entry.start_with?('.')
|
121
|
+
end
|
120
122
|
exit(1)
|
121
123
|
end
|
122
124
|
end
|
@@ -132,9 +134,7 @@ when 'stdio'
|
|
132
134
|
require_relative '../lib/rails_active_mcp/sdk/server'
|
133
135
|
|
134
136
|
# Log startup information
|
135
|
-
if should_redirect
|
136
|
-
warn "[#{Time.now}] [RAILS-MCP] INFO: Starting Rails Active MCP Server v#{RailsActiveMcp::VERSION}"
|
137
|
-
end
|
137
|
+
warn "[#{Time.now}] [RAILS-MCP] INFO: Starting Rails Active MCP Server v#{RailsActiveMcp::VERSION}" if should_redirect
|
138
138
|
warn "[#{Time.now}] [RAILS-MCP] INFO: Rails loaded: #{rails_loaded}" if should_redirect
|
139
139
|
if rails_load_error && should_redirect
|
140
140
|
warn "[#{Time.now}] [RAILS-MCP] WARNING: Rails load error: #{rails_load_error.class.name}: #{rails_load_error.message}"
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# Rails 6.0 Gemfile for CI testing
|
2
|
+
source 'https://rubygems.org'
|
3
|
+
|
4
|
+
# Specify the Rails version
|
5
|
+
gem 'rails', '~> 6.0'
|
6
|
+
|
7
|
+
# Include the main gemspec
|
8
|
+
gemspec path: '../'
|
9
|
+
|
10
|
+
group :development, :test do
|
11
|
+
gem 'byebug'
|
12
|
+
gem 'database_cleaner-active_record', '~> 2.1'
|
13
|
+
gem 'factory_bot_rails', '~> 6.0'
|
14
|
+
gem 'rspec', '~> 3.1'
|
15
|
+
gem 'rspec-rails'
|
16
|
+
gem 'sqlite3', '~> 2.7'
|
17
|
+
gem 'timecop', '~> 0.9.8'
|
18
|
+
gem 'webmock', '~> 3.19'
|
19
|
+
end
|
20
|
+
|
21
|
+
group :development do
|
22
|
+
gem 'redcarpet' # For YARD markdown support
|
23
|
+
gem 'rubocop', '~> 1.77'
|
24
|
+
gem 'rubocop-rails', '~> 2.32'
|
25
|
+
gem 'rubocop-rspec'
|
26
|
+
gem 'simplecov', '~> 0.22'
|
27
|
+
gem 'yard'
|
28
|
+
end
|
29
|
+
|
30
|
+
# For testing the gem in a Rails app
|
31
|
+
gem 'sprockets-rails' # Required for Rails 7+
|
32
|
+
|
33
|
+
# Official MCP Ruby SDK for migration
|
34
|
+
gem 'mcp', '~> 0.1.0'
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# Rails 6.0 Gemfile for CI testing
|
2
|
+
source 'https://rubygems.org'
|
3
|
+
|
4
|
+
# Specify the Rails version
|
5
|
+
gem 'rails', '~> 6.0'
|
6
|
+
|
7
|
+
# Include the main gemspec
|
8
|
+
gemspec path: '../'
|
9
|
+
|
10
|
+
group :development, :test do
|
11
|
+
gem 'byebug'
|
12
|
+
gem 'database_cleaner-active_record', '~> 2.1'
|
13
|
+
gem 'factory_bot_rails', '~> 6.0'
|
14
|
+
gem 'rspec', '~> 3.1'
|
15
|
+
gem 'rspec-rails'
|
16
|
+
gem 'sqlite3', '~> 2.7'
|
17
|
+
gem 'timecop', '~> 0.9.8'
|
18
|
+
gem 'webmock', '~> 3.19'
|
19
|
+
end
|
20
|
+
|
21
|
+
group :development do
|
22
|
+
gem 'redcarpet' # For YARD markdown support
|
23
|
+
gem 'rubocop', '~> 1.77'
|
24
|
+
gem 'rubocop-rails', '~> 2.32'
|
25
|
+
gem 'rubocop-rspec'
|
26
|
+
gem 'simplecov', '~> 0.22'
|
27
|
+
gem 'yard'
|
28
|
+
end
|
29
|
+
|
30
|
+
# For testing the gem in a Rails app
|
31
|
+
gem 'sprockets-rails' # Required for Rails 7+
|
32
|
+
|
33
|
+
# Official MCP Ruby SDK for migration
|
34
|
+
gem 'mcp', '~> 0.1.0'
|