rails-dev-mcp 0.1.0

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 03307be97232cb5e690da0c582b6b14b374eac0525a596dfa89f57f1d3837cde
4
+ data.tar.gz: e83d66ea6c9591dd8a0ae1dac29de657417b4568ed217ab5c629f982fcc52382
5
+ SHA512:
6
+ metadata.gz: 8851102c18771b9c8ae57fdab79ee6576fb2de3b10c7db58d76b472c69f23be8342b16b816a5816d92f357f17b9998a71e94ff6aa186b6aa7f5e214827aa6e59
7
+ data.tar.gz: 78b8495d4b67e0c9c32f2fada44851f2e131ec14ff580ff962f3a90b09128dcf20f2a2288ac3a33298309a625829a14f3004d424e79456ba76af799fb28b33d3
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Obie Fernandez
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,126 @@
1
+ # Rails Dev MCP
2
+
3
+ A Model Context Protocol (MCP) server that allows AI agents to manage Rails development servers. Start, stop, and monitor your Rails app directly from Claude!
4
+
5
+ ## Features
6
+
7
+ - **start_dev_server**: Start Rails development server on a specified port
8
+ - **stop_dev_server**: Stop the running Rails server
9
+ - **dev_server_logs**: View recent logs and notable events (errors, warnings, requests)
10
+ - **dev_server_status**: Check if the server is running and get connection details
11
+
12
+ ## Installation
13
+
14
+ ### As a gem
15
+
16
+ ```bash
17
+ gem install rails-dev-mcp
18
+ ```
19
+
20
+ ### From source
21
+
22
+ ```bash
23
+ git clone https://github.com/obie/rails-dev-mcp.git
24
+ cd rails-dev-mcp
25
+ bundle install
26
+ rake install
27
+ ```
28
+
29
+ ## Usage
30
+
31
+ ### With Claude Desktop
32
+
33
+ Add to your Claude Desktop configuration (`~/Library/Application Support/Claude/claude_desktop_config.json`):
34
+
35
+ ```json
36
+ {
37
+ "mcpServers": {
38
+ "rails-dev": {
39
+ "command": "rails-dev-mcp",
40
+ "cwd": "/path/to/your/rails/project"
41
+ }
42
+ }
43
+ }
44
+ ```
45
+
46
+ ### With ClaudeOnRails
47
+
48
+ The Rails Dev MCP integrates seamlessly with ClaudeOnRails. Add to your `claude-swarm.yml`:
49
+
50
+ ```yaml
51
+ mcps:
52
+ - name: rails-dev
53
+ type: stdio
54
+ command: rails-dev-mcp
55
+ args: []
56
+ ```
57
+
58
+ ## Available Tools
59
+
60
+ ### start_dev_server
61
+
62
+ Starts the Rails development server.
63
+
64
+ **Parameters:**
65
+ - `port` (optional): Port number (default: 3000)
66
+
67
+ **Example:**
68
+ ```
69
+ Start the Rails server on port 3001
70
+ ```
71
+
72
+ ### stop_dev_server
73
+
74
+ Stops the running Rails development server.
75
+
76
+ **Example:**
77
+ ```
78
+ Stop the Rails server
79
+ ```
80
+
81
+ ### dev_server_logs
82
+
83
+ Retrieves recent logs from the Rails server.
84
+
85
+ **Parameters:**
86
+ - `lines` (optional): Number of log lines to retrieve (default: 50)
87
+ - `notable_only` (optional): Show only errors, warnings, and requests
88
+
89
+ **Example:**
90
+ ```
91
+ Show me the last 100 lines from the Rails server logs
92
+ Show me only errors from the Rails logs
93
+ ```
94
+
95
+ ### dev_server_status
96
+
97
+ Checks the current status of the Rails development server.
98
+
99
+ **Example:**
100
+ ```
101
+ Is the Rails server running?
102
+ ```
103
+
104
+ ## How It Works
105
+
106
+ 1. **Process Management**: Uses Ruby's Open3 to manage the Rails server process
107
+ 2. **Log Capture**: Redirects server output to a log file for later retrieval
108
+ 3. **PID Tracking**: Maintains PID files to track running processes
109
+ 4. **Smart Log Filtering**: Identifies notable events like errors, warnings, and HTTP requests
110
+
111
+ ## Development
112
+
113
+ ```bash
114
+ # Run tests
115
+ bundle exec rspec
116
+
117
+ # Run linter
118
+ bundle exec rubocop
119
+
120
+ # Build gem
121
+ gem build rails-dev-mcp.gemspec
122
+ ```
123
+
124
+ ## License
125
+
126
+ MIT License - see LICENSE file for details.
data/exe/rails-dev-mcp ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'rails_dev_mcp'
5
+
6
+ RailsDevMCP::Server.new.run
@@ -0,0 +1,161 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'open3'
4
+ require 'fileutils'
5
+
6
+ module RailsDevMCP
7
+ class ProcessManager
8
+ attr_reader :pid, :log_file, :port
9
+
10
+ def initialize(rails_root:, port: 3000)
11
+ @rails_root = rails_root
12
+ @port = port
13
+ @log_file = File.join(rails_root, 'tmp', 'rails-dev-mcp.log')
14
+ @pid_file = File.join(rails_root, 'tmp', 'pids', 'rails-dev-mcp.pid')
15
+ @pid = nil
16
+ @stdin = nil
17
+ @stdout = nil
18
+ @stderr = nil
19
+ @wait_thread = nil
20
+
21
+ ensure_directories
22
+ end
23
+
24
+ def start
25
+ return { success: false, error: 'Server already running' } if running?
26
+
27
+ # Start Rails server with output captured
28
+ cmd = "rails server -p #{@port}"
29
+
30
+ @stdin, @stdout, @stderr, @wait_thread = Open3.popen3(
31
+ cmd,
32
+ chdir: @rails_root,
33
+ err: [:child, :out] # Combine stderr into stdout
34
+ )
35
+
36
+ @pid = @wait_thread.pid
37
+ write_pid_file(@pid)
38
+
39
+ # Start log capture thread
40
+ Thread.new do
41
+ File.open(@log_file, 'a') do |log|
42
+ @stdout.each_line do |line|
43
+ log.puts(line)
44
+ log.flush
45
+ end
46
+ end
47
+ end
48
+
49
+ # Wait a moment to check if it started successfully
50
+ sleep 2
51
+
52
+ if running?
53
+ { success: true, message: "Rails server started on port #{@port}", pid: @pid }
54
+ else
55
+ { success: false, error: 'Failed to start Rails server' }
56
+ end
57
+ rescue StandardError => e
58
+ { success: false, error: e.message }
59
+ end
60
+
61
+ def stop
62
+ return { success: false, error: 'Server not running' } unless running?
63
+
64
+ begin
65
+ Process.kill('TERM', @pid)
66
+ @wait_thread&.join(5) # Wait up to 5 seconds for graceful shutdown
67
+
68
+ if running?
69
+ Process.kill('KILL', @pid) # Force kill if still running
70
+ end
71
+
72
+ cleanup
73
+ { success: true, message: 'Rails server stopped' }
74
+ rescue Errno::ESRCH
75
+ # Process already dead
76
+ cleanup
77
+ { success: true, message: 'Rails server was already stopped' }
78
+ rescue StandardError => e
79
+ { success: false, error: e.message }
80
+ end
81
+ end
82
+
83
+ def logs(lines: 50)
84
+ return { success: false, error: 'Log file not found' } unless File.exist?(@log_file)
85
+
86
+ begin
87
+ log_content = `tail -n #{lines} #{@log_file}`
88
+
89
+ # Extract notable events (errors, warnings, requests)
90
+ notable_lines = log_content.lines.select do |line|
91
+ line =~ /ERROR|WARN|FATAL|Started|Completed|ActionController::RoutingError|ActiveRecord::|NoMethodError|NameError|SyntaxError/
92
+ end
93
+
94
+ {
95
+ success: true,
96
+ full_logs: log_content,
97
+ notable_events: notable_lines.join,
98
+ log_file: @log_file
99
+ }
100
+ rescue StandardError => e
101
+ { success: false, error: e.message }
102
+ end
103
+ end
104
+
105
+ def status
106
+ if running?
107
+ {
108
+ running: true,
109
+ pid: @pid,
110
+ port: @port,
111
+ url: "http://localhost:#{@port}",
112
+ log_file: @log_file
113
+ }
114
+ else
115
+ {
116
+ running: false,
117
+ port: @port,
118
+ log_file: @log_file
119
+ }
120
+ end
121
+ end
122
+
123
+ def running?
124
+ return false unless @pid || read_pid_file
125
+
126
+ begin
127
+ Process.kill(0, @pid || read_pid_file)
128
+ true
129
+ rescue Errno::ESRCH
130
+ false
131
+ end
132
+ end
133
+
134
+ private
135
+
136
+ def ensure_directories
137
+ FileUtils.mkdir_p(File.dirname(@log_file))
138
+ FileUtils.mkdir_p(File.dirname(@pid_file))
139
+ end
140
+
141
+ def write_pid_file(pid)
142
+ File.write(@pid_file, pid.to_s)
143
+ end
144
+
145
+ def read_pid_file
146
+ return nil unless File.exist?(@pid_file)
147
+ File.read(@pid_file).to_i
148
+ rescue StandardError
149
+ nil
150
+ end
151
+
152
+ def cleanup
153
+ File.unlink(@pid_file) if File.exist?(@pid_file)
154
+ @stdin&.close
155
+ @stdout&.close
156
+ @stderr&.close
157
+ @pid = nil
158
+ @wait_thread = nil
159
+ end
160
+ end
161
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'fast_mcp'
4
+ require 'logger'
5
+ require 'forwardable'
6
+
7
+ module RailsDevMCP
8
+ class Server
9
+ def run
10
+ server = FastMcp::Server.new(
11
+ name: 'rails-dev-mcp',
12
+ version: VERSION,
13
+ description: 'MCP server for managing Rails development servers'
14
+ )
15
+
16
+ # Register our tools
17
+ server.register_tools(
18
+ Tools::StartDevServer,
19
+ Tools::StopDevServer,
20
+ Tools::DevServerLogs,
21
+ Tools::DevServerStatus
22
+ )
23
+
24
+ # Start the server in STDIO mode
25
+ server.run
26
+ end
27
+ end
28
+
29
+ # Configuration module
30
+ module Config
31
+ class << self
32
+ attr_accessor :logger, :rails_root, :server_process
33
+
34
+ def setup(rails_root = Dir.pwd)
35
+ @logger = Logger.new($stderr)
36
+ @logger.level = Logger::INFO
37
+ @rails_root = rails_root
38
+ @server_process = nil
39
+ self
40
+ end
41
+ end
42
+ end
43
+
44
+ # Initialize configuration
45
+ @config = Config.setup
46
+
47
+ class << self
48
+ extend Forwardable
49
+ def_delegators :@config, :logger, :rails_root, :server_process, :server_process=
50
+
51
+ def log(level, message)
52
+ levels = { debug: Logger::DEBUG, info: Logger::INFO, warn: Logger::WARN, error: Logger::ERROR }
53
+ logger.add(levels[level] || Logger::INFO, message)
54
+ end
55
+ end
56
+ end
57
+
58
+ # Load tools after module is defined
59
+ require_relative 'tools/base_tool'
60
+ require_relative 'tools/start_dev_server'
61
+ require_relative 'tools/stop_dev_server'
62
+ require_relative 'tools/dev_server_logs'
63
+ require_relative 'tools/dev_server_status'
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'fast_mcp'
4
+ require 'forwardable'
5
+
6
+ module RailsDevMCP
7
+ module Tools
8
+ class BaseTool < FastMcp::Tool
9
+ extend Forwardable
10
+ def_delegators :RailsDevMCP, :log, :rails_root, :server_process
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsDevMCP
4
+ module Tools
5
+ class DevServerLogs < BaseTool
6
+ tool_name 'dev_server_logs'
7
+
8
+ description 'Get latest logs from the Rails development server, highlighting notable events like errors and requests'
9
+
10
+ argument :lines, type: 'integer', description: 'Number of log lines to retrieve (default: 50)', required: false
11
+ argument :notable_only, type: 'boolean', description: 'Show only notable events (errors, warnings, requests)', required: false
12
+
13
+ def call(lines: nil, notable_only: nil)
14
+ lines ||= 50
15
+ notable_only ||= false
16
+
17
+ unless RailsDevMCP.server_process
18
+ # Try to read logs even if process not tracked
19
+ process = ProcessManager.new(rails_root: RailsDevMCP.rails_root)
20
+ result = process.logs(lines: lines)
21
+ else
22
+ result = RailsDevMCP.server_process.logs(lines: lines)
23
+ end
24
+
25
+ if result[:success]
26
+ log(:debug, "Retrieved #{lines} log lines")
27
+
28
+ if notable_only && result[:notable_events].to_s.strip.length > 0
29
+ <<~LOGS
30
+ 📋 Notable events from Rails server logs:
31
+
32
+ #{result[:notable_events]}
33
+
34
+ Log file: #{result[:log_file]}
35
+ LOGS
36
+ elsif result[:full_logs].to_s.strip.length > 0
37
+ <<~LOGS
38
+ 📋 Rails server logs (last #{lines} lines):
39
+
40
+ #{result[:full_logs]}
41
+
42
+ Log file: #{result[:log_file]}
43
+ LOGS
44
+ else
45
+ "📋 No logs available yet. The server may have just started."
46
+ end
47
+ else
48
+ log(:error, "Failed to retrieve logs: #{result[:error]}")
49
+ "❌ Failed to retrieve logs: #{result[:error]}"
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsDevMCP
4
+ module Tools
5
+ class DevServerStatus < BaseTool
6
+ tool_name 'dev_server_status'
7
+
8
+ description 'Check the status of the Rails development server'
9
+
10
+ def call
11
+ # Check for existing process or create new manager to check
12
+ process = RailsDevMCP.server_process || ProcessManager.new(rails_root: RailsDevMCP.rails_root)
13
+ status = process.status
14
+
15
+ if status[:running]
16
+ <<~STATUS
17
+ 🟢 Rails development server is running
18
+
19
+ PID: #{status[:pid]}
20
+ Port: #{status[:port]}
21
+ URL: #{status[:url]}
22
+ Log file: #{status[:log_file]}
23
+ STATUS
24
+ else
25
+ <<~STATUS
26
+ 🔴 Rails development server is not running
27
+
28
+ Port: #{status[:port]} (configured)
29
+ Log file: #{status[:log_file]}
30
+
31
+ Use 'start_dev_server' to start the server.
32
+ STATUS
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsDevMCP
4
+ module Tools
5
+ class StartDevServer < BaseTool
6
+ tool_name 'start_dev_server'
7
+
8
+ description 'Start the Rails development server'
9
+
10
+ argument :port, type: 'integer', description: 'Port to run the server on (default: 3000)', required: false
11
+
12
+ def call(port: nil)
13
+ port ||= 3000
14
+
15
+ # Create process manager if not exists
16
+ RailsDevMCP.server_process ||= ProcessManager.new(
17
+ rails_root: RailsDevMCP.rails_root,
18
+ port: port
19
+ )
20
+
21
+ result = RailsDevMCP.server_process.start
22
+
23
+ if result[:success]
24
+ log(:info, "Rails server started: #{result[:message]}")
25
+ "✅ #{result[:message]}\nPID: #{result[:pid]}\nURL: http://localhost:#{port}"
26
+ else
27
+ log(:error, "Failed to start Rails server: #{result[:error]}")
28
+ "❌ Failed to start Rails server: #{result[:error]}"
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsDevMCP
4
+ module Tools
5
+ class StopDevServer < BaseTool
6
+ tool_name 'stop_dev_server'
7
+
8
+ description 'Stop the Rails development server'
9
+
10
+ def call
11
+ unless RailsDevMCP.server_process
12
+ return "❌ No Rails server process found"
13
+ end
14
+
15
+ result = RailsDevMCP.server_process.stop
16
+
17
+ if result[:success]
18
+ log(:info, "Rails server stopped: #{result[:message]}")
19
+ RailsDevMCP.server_process = nil
20
+ "✅ #{result[:message]}"
21
+ else
22
+ log(:error, "Failed to stop Rails server: #{result[:error]}")
23
+ "❌ Failed to stop Rails server: #{result[:error]}"
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsDevMCP
4
+ VERSION = '0.1.0'
5
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_dev_mcp/version'
4
+ require 'rails_dev_mcp/server'
5
+ require 'rails_dev_mcp/process_manager'
6
+
7
+ module RailsDevMCP
8
+ class Error < StandardError; end
9
+ end
metadata ADDED
@@ -0,0 +1,116 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rails-dev-mcp
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Obie Fernandez
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2025-07-02 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: fast-mcp
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: puma
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '5.0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '5.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rubocop
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.21'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.21'
69
+ description: A Model Context Protocol (MCP) server that allows AI agents to start,
70
+ stop, and monitor Rails development servers
71
+ email:
72
+ - obiefernandez@gmail.com
73
+ executables:
74
+ - rails-dev-mcp
75
+ extensions: []
76
+ extra_rdoc_files: []
77
+ files:
78
+ - Gemfile
79
+ - LICENSE
80
+ - README.md
81
+ - exe/rails-dev-mcp
82
+ - lib/rails_dev_mcp.rb
83
+ - lib/rails_dev_mcp/process_manager.rb
84
+ - lib/rails_dev_mcp/server.rb
85
+ - lib/rails_dev_mcp/tools/base_tool.rb
86
+ - lib/rails_dev_mcp/tools/dev_server_logs.rb
87
+ - lib/rails_dev_mcp/tools/dev_server_status.rb
88
+ - lib/rails_dev_mcp/tools/start_dev_server.rb
89
+ - lib/rails_dev_mcp/tools/stop_dev_server.rb
90
+ - lib/rails_dev_mcp/version.rb
91
+ homepage: https://github.com/obie/rails-dev-mcp
92
+ licenses:
93
+ - MIT
94
+ metadata:
95
+ homepage_uri: https://github.com/obie/rails-dev-mcp
96
+ source_code_uri: https://github.com/obie/rails-dev-mcp
97
+ post_install_message:
98
+ rdoc_options: []
99
+ require_paths:
100
+ - lib
101
+ required_ruby_version: !ruby/object:Gem::Requirement
102
+ requirements:
103
+ - - ">="
104
+ - !ruby/object:Gem::Version
105
+ version: 3.0.0
106
+ required_rubygems_version: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ requirements: []
112
+ rubygems_version: 3.5.22
113
+ signing_key:
114
+ specification_version: 4
115
+ summary: MCP server for managing Rails development servers
116
+ test_files: []