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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 25c3767eb1c84eb4ac69450ab2118659b7b8eeca87722bfb3456be06543182b6
4
- data.tar.gz: e0c62dcc4abba55695290ba082007f0ea6b5bd19dae7bf257f51f4d426a51de5
3
+ metadata.gz: 65769f824f1dbb5bfe856a40f0a46aed59d4591b3e2d23c486b6f6a08687075c
4
+ data.tar.gz: 596d5a5bd1d22559a0d4d9ea1369b1c375546ce790a3c71edc378c053c75b433
5
5
  SHA512:
6
- metadata.gz: 0677e15106d3574a9f061022aa4f37977a1d3e79166d54b59293127ae84f806d8f4f19d03384924072b455c1787bb68016d8cdc486ca6e5a0f7822848766403b
7
- data.tar.gz: d13b1175daf7fc56b1d245994d2ed741d33fd6f073acabbd899a89cd3608d23782c5fe9e671716087ae81b52b33090791dc8fcc0a1aab68432442cc434e02148
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) = 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
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) = 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
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) = 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)
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 = "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"
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 = "cdd6f4"
57
- GUM_SUBTEXT = "a6adc8"
58
- GUM_OVERLAY = "6c7086"
59
- GUM_BASE = "1e1e2e"
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 = options + ["Cancel"] if allow_cancel
123
+ options += ["Cancel"] if allow_cancel
124
124
 
125
125
  if gum_available?
126
- result = `gum choose --header "#{prompt}" \
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(" ")}`.strip
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 = `gum choose --no-limit --header "#{prompt}" \
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(" ")}`.strip
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 >= 1 && i <= options.length }.map { |i| options[i - 1] }
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
- while !stop_spinner
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
- { name: guide, downloaded: downloaded }
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 = { downloaded: 0, skipped: 0, failed: 0 }
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
- begin
753
- downloader = RailsMcpServer::ResourceDownloader.new(
754
- guide,
755
- config_dir: config_dir,
756
- force: force,
757
- verbose: false
758
- )
759
- downloader.download
760
- rescue => e
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
- begin
822
- importer = RailsMcpServer::ResourceImporter.new(
823
- "custom",
824
- config_dir: config_dir,
825
- source_path: expanded,
826
- force: force,
827
- verbose: false
828
- )
829
- importer.import
830
- rescue => e
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
- { name: name, path: file, size: size, mtime: mtime }
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 = { "mcpServers" => {} }
1019
+ config = {"mcpServers" => {}}
1024
1020
 
1025
- if mode == :stdio
1026
- config["mcpServers"]["railsMcpServer"] = generate_stdio_config
1021
+ config["mcpServers"]["railsMcpServer"] = if mode == :stdio
1022
+ generate_stdio_config
1027
1023
  else
1028
- config["mcpServers"]["railsMcpServer"] = generate_http_config(url || "http://localhost:3001/mcp")
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['command']}")
1061
- puts Colors.text(" args: #{rails_config['args']&.join(' ') || '(none)'}")
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('%Y%m%d_%H%M%S')}"
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 = ["#{controller_class}", " File: #{relative_path}", " Actions: #{data[:actions].size}"]
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]}#{opts.any? ? ", #{opts.join(", ")}" : ""}"
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 && model_names.is_a?(Array) && model_names.any?
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 = +"Rails Routes (#{routes.size} routes):\n"
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 = +"Rails Routes (#{routes.size} routes):\n"
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 && table_names.is_a?(Array) && table_names.any?
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})#{nullable ? ", nullable" : ""}#{default ? ", default: #{default}" : ""}"
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})#{unique ? " UNIQUE" : ""}"
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
- #{description.empty? ? "" : "**Description:** #{description}"}
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
- #{description.empty? ? "" : "**Description:** #{description}"}
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]}\"#{example[:comment] ? " # " + example[:comment] : ""}\n"
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"
@@ -103,7 +103,7 @@ module RailsMcpServer
103
103
  <<~GUIDE
104
104
  ### #{title}
105
105
  **Guide name:** `#{short_name}`
106
- #{description.empty? ? "" : "**Description:** #{description}"}
106
+ #{"**Description:** #{description}" unless description.empty?}
107
107
  GUIDE
108
108
  end
109
109
  end
@@ -1,3 +1,3 @@
1
1
  module RailsMcpServer
2
- VERSION = "1.4.0"
2
+ VERSION = "1.4.1"
3
3
  end
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.0
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.0
221
+ rubygems_version: 4.0.1
222
222
  specification_version: 4
223
223
  summary: MCP server for Rails projects
224
224
  test_files: []