rails-mcp-server 1.4.0 → 1.4.1
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/CHANGELOG.md +62 -0
- data/exe/rails-mcp-config +70 -74
- data/lib/rails-mcp-server/analyzers/analyze_controller_views.rb +2 -2
- data/lib/rails-mcp-server/analyzers/analyze_models.rb +1 -1
- data/lib/rails-mcp-server/analyzers/get_routes.rb +2 -2
- data/lib/rails-mcp-server/analyzers/get_schema.rb +3 -3
- data/lib/rails-mcp-server/analyzers/project_info.rb +1 -1
- data/lib/rails-mcp-server/resources/guide_content_formatter.rb +3 -3
- data/lib/rails-mcp-server/resources/kamal_guides_resources.rb +1 -1
- data/lib/rails-mcp-server/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 65769f824f1dbb5bfe856a40f0a46aed59d4591b3e2d23c486b6f6a08687075c
|
|
4
|
+
data.tar.gz: 596d5a5bd1d22559a0d4d9ea1369b1c375546ce790a3c71edc378c053c75b433
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 4c51f927f27949ec313ce1762911676f338553513189f030fc610847ced95d0b1f31d8badcfafe6d89d077e15fde6b6ec2d4e9a4417afd2aaeccd3275b46c170
|
|
7
|
+
data.tar.gz: 5d290f823f45a04ef7a4e0fed4a2ec2820e6be1c086af40441dc33cba7423ac2698e58b300febe2f8cd7accbdf49e7f5663dbd38f2e4a8162d6c30b326849cc2
|
data/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,67 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [1.4.1] - 2025-12-11
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
|
|
12
|
+
- **rails-mcp-config rbenv compatibility**: Fixed silent failure when running via rbenv shims
|
|
13
|
+
- The `__FILE__ == $0` guard failed because RubyGems' `load` creates a path mismatch between `__FILE__` (gem path) and `$0` (shim path)
|
|
14
|
+
- Now correctly detects execution via `File.basename($0) == "rails-mcp-config"`
|
|
15
|
+
|
|
16
|
+
## [1.4.0] - 2025-12-10
|
|
17
|
+
|
|
18
|
+
### Added
|
|
19
|
+
|
|
20
|
+
- **Context-Efficient Architecture**: Reduced registered MCP tools from 12 to 4, cutting initial context consumption by 67%
|
|
21
|
+
- 4 bootstrap tools: `switch_project`, `search_tools`, `execute_tool`, `execute_ruby`
|
|
22
|
+
- 9 internal analyzers invoked via `execute_tool` meta-dispatcher
|
|
23
|
+
- Tools are now discovered on-demand rather than loaded upfront
|
|
24
|
+
- **Sandboxed Ruby Execution** (`execute_ruby`): Secure code execution in Rails context
|
|
25
|
+
- File/network/system call restrictions
|
|
26
|
+
- Sensitive file protection (.env, credentials, .gitignore'd files)
|
|
27
|
+
- Helper methods: `read_file`, `file_exists?`, `list_files`, `project_root`
|
|
28
|
+
- **Interactive Configuration Tool** (`rails-mcp-config`): New TUI for project management
|
|
29
|
+
- Project management with validation
|
|
30
|
+
- Guide downloading with progress indicators
|
|
31
|
+
- Claude Desktop auto-configuration (STDIO/HTTP modes)
|
|
32
|
+
- Gum-enhanced UI with terminal fallback
|
|
33
|
+
- **Claude Code Integration**: Added CLAUDE.md, .claudeignore, and .claude/ configuration
|
|
34
|
+
- **Agent Documentation**: New docs/AGENT.md comprehensive AI agent guide
|
|
35
|
+
|
|
36
|
+
### Changed
|
|
37
|
+
|
|
38
|
+
- **Architecture Refactor**: Separation of tools/ (FastMCP) vs analyzers/ (plain Ruby classes)
|
|
39
|
+
- New `lib/rails-mcp-server/analyzers/` directory with `RailsMcpServer::Analyzers` namespace
|
|
40
|
+
- Removed deprecated extensions (resource_templating, server_templating)
|
|
41
|
+
- **Rails Introspection** (replaces regex parsing):
|
|
42
|
+
- `Model.reflect_on_all_associations` for accurate association data
|
|
43
|
+
- `Model.validators` with conditions and options
|
|
44
|
+
- `Controller.action_methods` instead of scanning for `def`
|
|
45
|
+
- `Rails.application.routes.routes` for direct route access
|
|
46
|
+
- `_process_action_callbacks` for before/after actions
|
|
47
|
+
- **Prism Static Analysis**: AST-based code inspection for callbacks, scopes, concerns
|
|
48
|
+
- Method definitions with line numbers
|
|
49
|
+
- Instance variables per controller action
|
|
50
|
+
- New `analysis_type` parameter: introspection | static | full
|
|
51
|
+
|
|
52
|
+
### Improved
|
|
53
|
+
|
|
54
|
+
- **Output Optimization**: New `detail_level` parameter (names | summary | full)
|
|
55
|
+
- **Route Filtering**: Filter by controller, verb, or path
|
|
56
|
+
- **Batch Operations**: Support for analyzing multiple models and schemas at once
|
|
57
|
+
- **Quick Start Guide**: Shown after `switch_project` for better onboarding
|
|
58
|
+
- **execute_ruby Hints**: Improved feedback for missing puts statements
|
|
59
|
+
|
|
60
|
+
### Fixed
|
|
61
|
+
|
|
62
|
+
- **get_routes**: Fixed method definition order bug
|
|
63
|
+
|
|
64
|
+
### Technical
|
|
65
|
+
|
|
66
|
+
- Test suite with 32 tests covering analyzers and tools
|
|
67
|
+
- Test fixtures with sample Rails project structure
|
|
68
|
+
|
|
8
69
|
## [1.2.3] - 2025-12-10
|
|
9
70
|
|
|
10
71
|
### Fixed
|
|
@@ -201,6 +262,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
201
262
|
|
|
202
263
|
## Version History Summary
|
|
203
264
|
|
|
265
|
+
- **v1.4.0** (2025-12-10): Context-efficient architecture with progressive tool discovery (67% token reduction)
|
|
204
266
|
- **v1.2.3** (2025-12-10): Setup script fix for readonly filesystems (NixOS compatibility)
|
|
205
267
|
- **v1.2.2** (2025-07-21): Network access support with --bind-all flag
|
|
206
268
|
- **v1.2.1** (2025-06-09): Bug fixes for STDIO output and tool naming
|
data/exe/rails-mcp-config
CHANGED
|
@@ -19,44 +19,44 @@ module RailsMcpConfig
|
|
|
19
19
|
end
|
|
20
20
|
|
|
21
21
|
# Catppuccin Mocha palette
|
|
22
|
-
def self.green(text)
|
|
23
|
-
def self.red(text)
|
|
24
|
-
def self.yellow(text)
|
|
25
|
-
def self.blue(text)
|
|
26
|
-
def self.mauve(text)
|
|
27
|
-
def self.teal(text)
|
|
28
|
-
def self.peach(text)
|
|
29
|
-
def self.pink(text)
|
|
30
|
-
def self.sky(text)
|
|
22
|
+
def self.green(text) = rgb(166, 227, 161, text) # #a6e3a1
|
|
23
|
+
def self.red(text) = rgb(243, 139, 168, text) # #f38ba8
|
|
24
|
+
def self.yellow(text) = rgb(249, 226, 175, text) # #f9e2af
|
|
25
|
+
def self.blue(text) = rgb(137, 180, 250, text) # #89b4fa
|
|
26
|
+
def self.mauve(text) = rgb(203, 166, 247, text) # #cba6f7
|
|
27
|
+
def self.teal(text) = rgb(148, 226, 213, text) # #94e2d5
|
|
28
|
+
def self.peach(text) = rgb(250, 179, 135, text) # #fab387
|
|
29
|
+
def self.pink(text) = rgb(245, 194, 231, text) # #f5c2e7
|
|
30
|
+
def self.sky(text) = rgb(137, 220, 235, text) # #89dceb
|
|
31
31
|
def self.lavender(text) = rgb(180, 190, 254, text) # #b4befe
|
|
32
|
-
def self.text(text)
|
|
33
|
-
def self.subtext(text)
|
|
34
|
-
def self.overlay(text)
|
|
32
|
+
def self.text(text) = rgb(205, 214, 244, text) # #cdd6f4
|
|
33
|
+
def self.subtext(text) = rgb(166, 173, 200, text) # #a6adc8
|
|
34
|
+
def self.overlay(text) = rgb(108, 112, 134, text) # #6c7086
|
|
35
35
|
|
|
36
36
|
# Semantic aliases
|
|
37
|
-
def self.success(text)
|
|
38
|
-
def self.error(text)
|
|
39
|
-
def self.warning(text)
|
|
40
|
-
def self.info(text)
|
|
41
|
-
def self.accent(text)
|
|
42
|
-
def self.bold(text)
|
|
43
|
-
def self.dim(text)
|
|
37
|
+
def self.success(text) = green(text)
|
|
38
|
+
def self.error(text) = red(text)
|
|
39
|
+
def self.warning(text) = yellow(text)
|
|
40
|
+
def self.info(text) = sky(text)
|
|
41
|
+
def self.accent(text) = mauve(text)
|
|
42
|
+
def self.bold(text) = "\e[1m#{text}\e[0m"
|
|
43
|
+
def self.dim(text) = overlay(text)
|
|
44
44
|
|
|
45
45
|
# Gum hex colors (without #)
|
|
46
|
-
GUM_GREEN
|
|
47
|
-
GUM_RED
|
|
48
|
-
GUM_YELLOW
|
|
49
|
-
GUM_BLUE
|
|
50
|
-
GUM_MAUVE
|
|
51
|
-
GUM_TEAL
|
|
52
|
-
GUM_PEACH
|
|
53
|
-
GUM_PINK
|
|
54
|
-
GUM_SKY
|
|
46
|
+
GUM_GREEN = "a6e3a1"
|
|
47
|
+
GUM_RED = "f38ba8"
|
|
48
|
+
GUM_YELLOW = "f9e2af"
|
|
49
|
+
GUM_BLUE = "89b4fa"
|
|
50
|
+
GUM_MAUVE = "cba6f7"
|
|
51
|
+
GUM_TEAL = "94e2d5"
|
|
52
|
+
GUM_PEACH = "fab387"
|
|
53
|
+
GUM_PINK = "f5c2e7"
|
|
54
|
+
GUM_SKY = "89dceb"
|
|
55
55
|
GUM_LAVENDER = "b4befe"
|
|
56
|
-
GUM_TEXT
|
|
57
|
-
GUM_SUBTEXT
|
|
58
|
-
GUM_OVERLAY
|
|
59
|
-
GUM_BASE
|
|
56
|
+
GUM_TEXT = "cdd6f4"
|
|
57
|
+
GUM_SUBTEXT = "a6adc8"
|
|
58
|
+
GUM_OVERLAY = "6c7086"
|
|
59
|
+
GUM_BASE = "1e1e2e"
|
|
60
60
|
end
|
|
61
61
|
|
|
62
62
|
# Gum wrapper with fallback to basic terminal
|
|
@@ -120,14 +120,14 @@ module RailsMcpConfig
|
|
|
120
120
|
def choose(prompt, options, allow_cancel: true)
|
|
121
121
|
return nil if options.empty?
|
|
122
122
|
|
|
123
|
-
options
|
|
123
|
+
options += ["Cancel"] if allow_cancel
|
|
124
124
|
|
|
125
125
|
if gum_available?
|
|
126
|
-
result =
|
|
126
|
+
result = %x(gum choose --header "#{prompt}" \
|
|
127
127
|
--header.foreground "##{Colors::GUM_MAUVE}" \
|
|
128
128
|
--cursor.foreground "##{Colors::GUM_PINK}" \
|
|
129
129
|
--item.foreground "##{Colors::GUM_TEXT}" \
|
|
130
|
-
#{options.map { |o| "'#{o}'" }.join(" ")}
|
|
130
|
+
#{options.map { |o| "'#{o}'" }.join(" ")}).strip
|
|
131
131
|
return nil if result.empty? || result == "Cancel" || separator?(result)
|
|
132
132
|
result
|
|
133
133
|
else
|
|
@@ -162,12 +162,12 @@ module RailsMcpConfig
|
|
|
162
162
|
return [] if options.empty?
|
|
163
163
|
|
|
164
164
|
if gum_available?
|
|
165
|
-
result =
|
|
165
|
+
result = %x(gum choose --no-limit --header "#{prompt}" \
|
|
166
166
|
--header.foreground "##{Colors::GUM_MAUVE}" \
|
|
167
167
|
--cursor.foreground "##{Colors::GUM_PINK}" \
|
|
168
168
|
--item.foreground "##{Colors::GUM_TEXT}" \
|
|
169
169
|
--selected.foreground "##{Colors::GUM_GREEN}" \
|
|
170
|
-
#{options.map { |o| "'#{o}'" }.join(" ")}
|
|
170
|
+
#{options.map { |o| "'#{o}'" }.join(" ")}).strip
|
|
171
171
|
result.split("\n").map(&:strip).reject(&:empty?)
|
|
172
172
|
else
|
|
173
173
|
puts
|
|
@@ -183,7 +183,7 @@ module RailsMcpConfig
|
|
|
183
183
|
return options.dup if input == "all"
|
|
184
184
|
|
|
185
185
|
indices = input.split(/[\s,]+/).map(&:to_i)
|
|
186
|
-
indices.select { |i| i
|
|
186
|
+
indices.select { |i| i.between?(1, options.length) }.map { |i| options[i - 1] }
|
|
187
187
|
end
|
|
188
188
|
end
|
|
189
189
|
|
|
@@ -247,7 +247,7 @@ module RailsMcpConfig
|
|
|
247
247
|
all_rows = [headers] + rows
|
|
248
248
|
widths = headers.map.with_index do |_, i|
|
|
249
249
|
calculated = all_rows.map { |row| row[i].to_s.length }.max
|
|
250
|
-
max_widths && max_widths[i] ? [calculated, max_widths[i]].min : calculated
|
|
250
|
+
(max_widths && max_widths[i]) ? [calculated, max_widths[i]].min : calculated
|
|
251
251
|
end
|
|
252
252
|
|
|
253
253
|
# Print header
|
|
@@ -293,7 +293,7 @@ module RailsMcpConfig
|
|
|
293
293
|
|
|
294
294
|
spinner_thread = Thread.new do
|
|
295
295
|
i = 0
|
|
296
|
-
|
|
296
|
+
until stop_spinner
|
|
297
297
|
print "\r#{Colors.pink(frames[i % frames.length])} #{Colors.text(title)}"
|
|
298
298
|
$stdout.flush
|
|
299
299
|
sleep 0.08
|
|
@@ -716,7 +716,7 @@ module RailsMcpConfig
|
|
|
716
716
|
# Check download status for each guide
|
|
717
717
|
guide_status = available.map do |guide|
|
|
718
718
|
downloaded = guide_downloaded?(guide)
|
|
719
|
-
{
|
|
719
|
+
{name: guide, downloaded: downloaded}
|
|
720
720
|
end
|
|
721
721
|
|
|
722
722
|
# Build options with clear status
|
|
@@ -743,23 +743,21 @@ module RailsMcpConfig
|
|
|
743
743
|
force = ui.confirm("Force re-download (overwrite existing)?", default: false)
|
|
744
744
|
|
|
745
745
|
puts
|
|
746
|
-
total_results = {
|
|
746
|
+
total_results = {downloaded: 0, skipped: 0, failed: 0}
|
|
747
747
|
|
|
748
748
|
guide_names.each do |guide|
|
|
749
749
|
puts Colors.sky("Downloading #{guide}...")
|
|
750
750
|
|
|
751
751
|
results = ui.spin(" Fetching files...") do
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
{ downloaded: 0, skipped: 0, failed: 1, error: e.message }
|
|
762
|
-
end
|
|
752
|
+
downloader = RailsMcpServer::ResourceDownloader.new(
|
|
753
|
+
guide,
|
|
754
|
+
config_dir: config_dir,
|
|
755
|
+
force: force,
|
|
756
|
+
verbose: false
|
|
757
|
+
)
|
|
758
|
+
downloader.download
|
|
759
|
+
rescue => e
|
|
760
|
+
{downloaded: 0, skipped: 0, failed: 1, error: e.message}
|
|
763
761
|
end
|
|
764
762
|
|
|
765
763
|
if results[:error]
|
|
@@ -818,18 +816,16 @@ module RailsMcpConfig
|
|
|
818
816
|
puts Colors.sky("Importing from #{File.basename(path)}...")
|
|
819
817
|
|
|
820
818
|
results = ui.spin(" Processing files...") do
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
{ imported: 0, skipped: 0, failed: 1, error: e.message }
|
|
832
|
-
end
|
|
819
|
+
importer = RailsMcpServer::ResourceImporter.new(
|
|
820
|
+
"custom",
|
|
821
|
+
config_dir: config_dir,
|
|
822
|
+
source_path: expanded,
|
|
823
|
+
force: force,
|
|
824
|
+
verbose: false
|
|
825
|
+
)
|
|
826
|
+
importer.import
|
|
827
|
+
rescue => e
|
|
828
|
+
{imported: 0, skipped: 0, failed: 1, error: e.message}
|
|
833
829
|
end
|
|
834
830
|
|
|
835
831
|
if results[:error]
|
|
@@ -852,7 +848,7 @@ module RailsMcpConfig
|
|
|
852
848
|
name = File.basename(file, ".md")
|
|
853
849
|
size = File.size(file)
|
|
854
850
|
mtime = File.mtime(file)
|
|
855
|
-
{
|
|
851
|
+
{name: name, path: file, size: size, mtime: mtime}
|
|
856
852
|
end.sort_by { |f| f[:name] }
|
|
857
853
|
end
|
|
858
854
|
|
|
@@ -1020,12 +1016,12 @@ module RailsMcpConfig
|
|
|
1020
1016
|
end
|
|
1021
1017
|
|
|
1022
1018
|
def generate_example_config(mode, url = nil)
|
|
1023
|
-
config = {
|
|
1019
|
+
config = {"mcpServers" => {}}
|
|
1024
1020
|
|
|
1025
|
-
if mode == :stdio
|
|
1026
|
-
|
|
1021
|
+
config["mcpServers"]["railsMcpServer"] = if mode == :stdio
|
|
1022
|
+
generate_stdio_config
|
|
1027
1023
|
else
|
|
1028
|
-
|
|
1024
|
+
generate_http_config(url || "http://localhost:3001/mcp")
|
|
1029
1025
|
end
|
|
1030
1026
|
|
|
1031
1027
|
config
|
|
@@ -1057,8 +1053,8 @@ module RailsMcpConfig
|
|
|
1057
1053
|
ui.success("Rails MCP Server is configured")
|
|
1058
1054
|
puts
|
|
1059
1055
|
puts Colors.lavender("Current configuration:")
|
|
1060
|
-
puts Colors.text(" command: #{rails_config[
|
|
1061
|
-
puts Colors.text(" args: #{rails_config[
|
|
1056
|
+
puts Colors.text(" command: #{rails_config["command"]}")
|
|
1057
|
+
puts Colors.text(" args: #{rails_config["args"]&.join(" ") || "(none)"}")
|
|
1062
1058
|
else
|
|
1063
1059
|
ui.warning("Rails MCP Server is NOT configured")
|
|
1064
1060
|
end
|
|
@@ -1273,7 +1269,7 @@ module RailsMcpConfig
|
|
|
1273
1269
|
config_file = claude_config_path
|
|
1274
1270
|
return unless File.exist?(config_file)
|
|
1275
1271
|
|
|
1276
|
-
backup_file = "#{config_file}.backup.#{Time.now.strftime(
|
|
1272
|
+
backup_file = "#{config_file}.backup.#{Time.now.strftime("%Y%m%d_%H%M%S")}"
|
|
1277
1273
|
FileUtils.cp(config_file, backup_file)
|
|
1278
1274
|
ui.success("Backed up existing config to: #{File.basename(backup_file)}")
|
|
1279
1275
|
end
|
|
@@ -1364,7 +1360,7 @@ module RailsMcpConfig
|
|
|
1364
1360
|
end
|
|
1365
1361
|
|
|
1366
1362
|
# Entry point
|
|
1367
|
-
if __FILE__ == $0
|
|
1363
|
+
if __FILE__ == $0 || File.basename($0) == "rails-mcp-config"
|
|
1368
1364
|
require "shellwords"
|
|
1369
1365
|
|
|
1370
1366
|
# Handle --help
|
|
@@ -63,7 +63,7 @@ module RailsMcpServer
|
|
|
63
63
|
|
|
64
64
|
def format_summary(controller_class, file_path, relative_path)
|
|
65
65
|
data = get_controller_summary(controller_class)
|
|
66
|
-
output = [
|
|
66
|
+
output = [controller_class.to_s, " File: #{relative_path}", " Actions: #{data[:actions].size}"]
|
|
67
67
|
data[:actions].each do |action|
|
|
68
68
|
route = data[:routes].find { |r| r[:action] == action }
|
|
69
69
|
output << if route
|
|
@@ -148,7 +148,7 @@ module RailsMcpServer
|
|
|
148
148
|
opts = []
|
|
149
149
|
opts << "only: [#{cb[:only].join(", ")}]" if cb[:only]&.any?
|
|
150
150
|
opts << "except: [#{cb[:except].join(", ")}]" if cb[:except]&.any?
|
|
151
|
-
output << " #{cb[:kind]}_action :#{cb[:filter]}#{
|
|
151
|
+
output << " #{cb[:kind]}_action :#{cb[:filter]}#{", #{opts.join(", ")}" if opts.any?}"
|
|
152
152
|
end
|
|
153
153
|
end
|
|
154
154
|
|
|
@@ -9,7 +9,7 @@ module RailsMcpServer
|
|
|
9
9
|
detail_level = "full" unless %w[names associations full].include?(detail_level)
|
|
10
10
|
analysis_type = "introspection" unless %w[introspection static full].include?(analysis_type)
|
|
11
11
|
|
|
12
|
-
if model_names
|
|
12
|
+
if model_names&.is_a?(Array) && model_names.any?
|
|
13
13
|
return batch_model_info(model_names, detail_level, analysis_type)
|
|
14
14
|
end
|
|
15
15
|
|
|
@@ -152,7 +152,7 @@ module RailsMcpServer
|
|
|
152
152
|
"Route paths (#{paths.size} unique):\n\n#{paths.join("\n")}"
|
|
153
153
|
|
|
154
154
|
when "summary"
|
|
155
|
-
output =
|
|
155
|
+
output = "Rails Routes (#{routes.size} routes):\n"
|
|
156
156
|
|
|
157
157
|
by_controller = routes.group_by { |r| r[:controller] }
|
|
158
158
|
|
|
@@ -169,7 +169,7 @@ module RailsMcpServer
|
|
|
169
169
|
output
|
|
170
170
|
|
|
171
171
|
when "full"
|
|
172
|
-
output =
|
|
172
|
+
output = "Rails Routes (#{routes.size} routes):\n"
|
|
173
173
|
output << "=" * 70 << "\n"
|
|
174
174
|
|
|
175
175
|
routes.each do |r|
|
|
@@ -10,7 +10,7 @@ module RailsMcpServer
|
|
|
10
10
|
|
|
11
11
|
detail_level = "full" unless %w[tables summary full].include?(detail_level)
|
|
12
12
|
|
|
13
|
-
if table_names
|
|
13
|
+
if table_names&.is_a?(Array) && table_names.any?
|
|
14
14
|
return batch_table_info(table_names)
|
|
15
15
|
end
|
|
16
16
|
|
|
@@ -110,7 +110,7 @@ module RailsMcpServer
|
|
|
110
110
|
end
|
|
111
111
|
|
|
112
112
|
formatted_columns = columns.map do |name, type, nullable, default|
|
|
113
|
-
" #{name} (#{type})#{
|
|
113
|
+
" #{name} (#{type})#{", nullable" if nullable}#{", default: #{default}" if default}"
|
|
114
114
|
end
|
|
115
115
|
|
|
116
116
|
output = <<~SCHEMA
|
|
@@ -199,7 +199,7 @@ module RailsMcpServer
|
|
|
199
199
|
|
|
200
200
|
formatted_indexes = indexes.map do |name, columns, unique|
|
|
201
201
|
cols = columns.is_a?(Array) ? columns.join(", ") : columns
|
|
202
|
-
" #{name} (#{cols})#{
|
|
202
|
+
" #{name} (#{cols})#{" UNIQUE" if unique}"
|
|
203
203
|
end
|
|
204
204
|
|
|
205
205
|
<<~IDX
|
|
@@ -8,7 +8,7 @@ module RailsMcpServer
|
|
|
8
8
|
return message
|
|
9
9
|
end
|
|
10
10
|
|
|
11
|
-
max_depth = [[max_depth.to_i, 1].max, 5].min
|
|
11
|
+
max_depth = [[max_depth.to_i, 1].max, 5].min # rubocop:disable Style/ComparableClamp
|
|
12
12
|
detail_level = "full" unless %w[minimal summary full].include?(detail_level)
|
|
13
13
|
|
|
14
14
|
gemfile_path = File.join(active_project_path, "Gemfile")
|
|
@@ -40,13 +40,13 @@ module RailsMcpServer
|
|
|
40
40
|
<<~GUIDE
|
|
41
41
|
### #{title}
|
|
42
42
|
**Guide name:** `#{short_name}` or `#{full_name}`
|
|
43
|
-
#{
|
|
43
|
+
#{"**Description:** #{description}" unless description.empty?}
|
|
44
44
|
GUIDE
|
|
45
45
|
else
|
|
46
46
|
<<~GUIDE
|
|
47
47
|
## #{title}
|
|
48
48
|
**Guide name:** `#{short_name}`
|
|
49
|
-
#{
|
|
49
|
+
#{"**Description:** #{description}" unless description.empty?}
|
|
50
50
|
GUIDE
|
|
51
51
|
end
|
|
52
52
|
end
|
|
@@ -59,7 +59,7 @@ module RailsMcpServer
|
|
|
59
59
|
usage += "```\n"
|
|
60
60
|
|
|
61
61
|
examples.each do |example|
|
|
62
|
-
usage += "load_guide guides: \"#{framework_name.downcase}\", guide: \"#{example[:guide]}\"#{
|
|
62
|
+
usage += "load_guide guides: \"#{framework_name.downcase}\", guide: \"#{example[:guide]}\"#{" # " + example[:comment] if example[:comment]}\n"
|
|
63
63
|
end
|
|
64
64
|
|
|
65
65
|
usage += "```\n"
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rails-mcp-server
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.4.
|
|
4
|
+
version: 1.4.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Mario Alberto Chávez Cárdenas
|
|
@@ -218,7 +218,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
218
218
|
- !ruby/object:Gem::Version
|
|
219
219
|
version: '0'
|
|
220
220
|
requirements: []
|
|
221
|
-
rubygems_version: 4.0.
|
|
221
|
+
rubygems_version: 4.0.1
|
|
222
222
|
specification_version: 4
|
|
223
223
|
summary: MCP server for Rails projects
|
|
224
224
|
test_files: []
|