debug-mcp 0.1.2

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.
Files changed (122) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +3 -0
  3. data/CHANGELOG.md +83 -0
  4. data/LICENSE +21 -0
  5. data/README.ja.md +383 -0
  6. data/README.md +384 -0
  7. data/examples/01_simple_bug.rb +43 -0
  8. data/examples/02_data_pipeline.rb +93 -0
  9. data/examples/03_recursion.rb +96 -0
  10. data/examples/RAILS_SCENARIOS.md +350 -0
  11. data/examples/SCENARIOS.md +142 -0
  12. data/examples/rails_test_app/setup.sh +428 -0
  13. data/examples/rails_test_app/testapp/.dockerignore +10 -0
  14. data/examples/rails_test_app/testapp/.ruby-version +1 -0
  15. data/examples/rails_test_app/testapp/Dockerfile +23 -0
  16. data/examples/rails_test_app/testapp/Gemfile +17 -0
  17. data/examples/rails_test_app/testapp/README.md +65 -0
  18. data/examples/rails_test_app/testapp/Rakefile +6 -0
  19. data/examples/rails_test_app/testapp/app/assets/images/.keep +0 -0
  20. data/examples/rails_test_app/testapp/app/assets/stylesheets/application.css +1 -0
  21. data/examples/rails_test_app/testapp/app/controllers/application_controller.rb +4 -0
  22. data/examples/rails_test_app/testapp/app/controllers/concerns/.keep +0 -0
  23. data/examples/rails_test_app/testapp/app/controllers/dashboard_controller.rb +38 -0
  24. data/examples/rails_test_app/testapp/app/controllers/health_controller.rb +11 -0
  25. data/examples/rails_test_app/testapp/app/controllers/orders_controller.rb +100 -0
  26. data/examples/rails_test_app/testapp/app/controllers/posts_controller.rb +82 -0
  27. data/examples/rails_test_app/testapp/app/controllers/sessions_controller.rb +25 -0
  28. data/examples/rails_test_app/testapp/app/controllers/users_controller.rb +44 -0
  29. data/examples/rails_test_app/testapp/app/helpers/application_helper.rb +2 -0
  30. data/examples/rails_test_app/testapp/app/models/application_record.rb +3 -0
  31. data/examples/rails_test_app/testapp/app/models/comment.rb +8 -0
  32. data/examples/rails_test_app/testapp/app/models/concerns/.keep +0 -0
  33. data/examples/rails_test_app/testapp/app/models/order.rb +56 -0
  34. data/examples/rails_test_app/testapp/app/models/order_item.rb +16 -0
  35. data/examples/rails_test_app/testapp/app/models/post.rb +29 -0
  36. data/examples/rails_test_app/testapp/app/models/user.rb +34 -0
  37. data/examples/rails_test_app/testapp/app/services/order_report_service.rb +40 -0
  38. data/examples/rails_test_app/testapp/app/views/layouts/application.html.erb +28 -0
  39. data/examples/rails_test_app/testapp/app/views/pwa/manifest.json.erb +22 -0
  40. data/examples/rails_test_app/testapp/app/views/pwa/service-worker.js +26 -0
  41. data/examples/rails_test_app/testapp/bin/ci +6 -0
  42. data/examples/rails_test_app/testapp/bin/dev +2 -0
  43. data/examples/rails_test_app/testapp/bin/rails +4 -0
  44. data/examples/rails_test_app/testapp/bin/rake +4 -0
  45. data/examples/rails_test_app/testapp/bin/setup +35 -0
  46. data/examples/rails_test_app/testapp/config/application.rb +42 -0
  47. data/examples/rails_test_app/testapp/config/boot.rb +3 -0
  48. data/examples/rails_test_app/testapp/config/ci.rb +14 -0
  49. data/examples/rails_test_app/testapp/config/database.yml +32 -0
  50. data/examples/rails_test_app/testapp/config/environment.rb +5 -0
  51. data/examples/rails_test_app/testapp/config/environments/development.rb +54 -0
  52. data/examples/rails_test_app/testapp/config/environments/production.rb +67 -0
  53. data/examples/rails_test_app/testapp/config/environments/test.rb +42 -0
  54. data/examples/rails_test_app/testapp/config/initializers/content_security_policy.rb +29 -0
  55. data/examples/rails_test_app/testapp/config/initializers/filter_parameter_logging.rb +8 -0
  56. data/examples/rails_test_app/testapp/config/initializers/inflections.rb +16 -0
  57. data/examples/rails_test_app/testapp/config/locales/en.yml +31 -0
  58. data/examples/rails_test_app/testapp/config/puma.rb +39 -0
  59. data/examples/rails_test_app/testapp/config/routes.rb +34 -0
  60. data/examples/rails_test_app/testapp/config.ru +6 -0
  61. data/examples/rails_test_app/testapp/db/migrate/20260216002916_create_users.rb +12 -0
  62. data/examples/rails_test_app/testapp/db/migrate/20260216002919_create_posts.rb +13 -0
  63. data/examples/rails_test_app/testapp/db/migrate/20260216002922_create_comments.rb +11 -0
  64. data/examples/rails_test_app/testapp/db/migrate/20260222000001_create_orders.rb +14 -0
  65. data/examples/rails_test_app/testapp/db/migrate/20260222000002_create_order_items.rb +13 -0
  66. data/examples/rails_test_app/testapp/db/schema.rb +71 -0
  67. data/examples/rails_test_app/testapp/db/seeds.rb +85 -0
  68. data/examples/rails_test_app/testapp/docker-compose.yml +21 -0
  69. data/examples/rails_test_app/testapp/docker-entrypoint.sh +10 -0
  70. data/examples/rails_test_app/testapp/lib/tasks/.keep +0 -0
  71. data/examples/rails_test_app/testapp/log/.keep +0 -0
  72. data/examples/rails_test_app/testapp/public/400.html +135 -0
  73. data/examples/rails_test_app/testapp/public/404.html +135 -0
  74. data/examples/rails_test_app/testapp/public/406-unsupported-browser.html +135 -0
  75. data/examples/rails_test_app/testapp/public/422.html +135 -0
  76. data/examples/rails_test_app/testapp/public/500.html +135 -0
  77. data/examples/rails_test_app/testapp/public/icon.png +0 -0
  78. data/examples/rails_test_app/testapp/public/icon.svg +3 -0
  79. data/examples/rails_test_app/testapp/public/robots.txt +1 -0
  80. data/examples/rails_test_app/testapp/script/.keep +0 -0
  81. data/examples/rails_test_app/testapp/storage/.keep +0 -0
  82. data/examples/rails_test_app/testapp/tmp/.keep +0 -0
  83. data/examples/rails_test_app/testapp/tmp/pids/.keep +0 -0
  84. data/examples/rails_test_app/testapp/tmp/storage/.keep +0 -0
  85. data/examples/rails_test_app/testapp/vendor/.keep +0 -0
  86. data/exe/debug-mcp +39 -0
  87. data/exe/debug-rails +127 -0
  88. data/lib/debug_mcp/client_cleanup.rb +102 -0
  89. data/lib/debug_mcp/code_safety_analyzer.rb +124 -0
  90. data/lib/debug_mcp/debug_client.rb +1143 -0
  91. data/lib/debug_mcp/exit_message_builder.rb +112 -0
  92. data/lib/debug_mcp/pending_http_helper.rb +25 -0
  93. data/lib/debug_mcp/rails_helper.rb +155 -0
  94. data/lib/debug_mcp/server.rb +364 -0
  95. data/lib/debug_mcp/session_manager.rb +436 -0
  96. data/lib/debug_mcp/stop_event_annotator.rb +152 -0
  97. data/lib/debug_mcp/tcp_session_discovery.rb +226 -0
  98. data/lib/debug_mcp/tools/connect.rb +669 -0
  99. data/lib/debug_mcp/tools/continue_execution.rb +161 -0
  100. data/lib/debug_mcp/tools/disconnect.rb +169 -0
  101. data/lib/debug_mcp/tools/evaluate_code.rb +354 -0
  102. data/lib/debug_mcp/tools/finish.rb +84 -0
  103. data/lib/debug_mcp/tools/get_context.rb +217 -0
  104. data/lib/debug_mcp/tools/get_source.rb +193 -0
  105. data/lib/debug_mcp/tools/inspect_object.rb +107 -0
  106. data/lib/debug_mcp/tools/list_debug_sessions.rb +60 -0
  107. data/lib/debug_mcp/tools/list_files.rb +189 -0
  108. data/lib/debug_mcp/tools/list_paused_sessions.rb +108 -0
  109. data/lib/debug_mcp/tools/next.rb +70 -0
  110. data/lib/debug_mcp/tools/rails_info.rb +200 -0
  111. data/lib/debug_mcp/tools/rails_model.rb +362 -0
  112. data/lib/debug_mcp/tools/rails_routes.rb +186 -0
  113. data/lib/debug_mcp/tools/read_file.rb +214 -0
  114. data/lib/debug_mcp/tools/remove_breakpoint.rb +173 -0
  115. data/lib/debug_mcp/tools/run_debug_command.rb +55 -0
  116. data/lib/debug_mcp/tools/run_script.rb +293 -0
  117. data/lib/debug_mcp/tools/set_breakpoint.rb +206 -0
  118. data/lib/debug_mcp/tools/step.rb +67 -0
  119. data/lib/debug_mcp/tools/trigger_request.rb +515 -0
  120. data/lib/debug_mcp/version.rb +5 -0
  121. data/lib/debug_mcp.rb +40 -0
  122. metadata +251 -0
@@ -0,0 +1,428 @@
1
+ #!/bin/bash
2
+ # debug-mcp Rails テスト用アプリのセットアップスクリプト
3
+ #
4
+ # 使い方:
5
+ # cd examples/rails_test_app
6
+ # bash setup.sh
7
+ #
8
+ # これにより、debug-mcpのRailsツールをテストするための
9
+ # 最小限のRailsアプリケーションが生成されます。
10
+
11
+ set -e
12
+
13
+ APP_DIR="$(cd "$(dirname "$0")" && pwd)/testapp"
14
+
15
+ echo "=== debug-mcp Rails テストアプリ セットアップ ==="
16
+ echo ""
17
+
18
+ # 既存のアプリがあれば確認
19
+ if [ -d "$APP_DIR" ]; then
20
+ echo "既存のテストアプリが見つかりました: $APP_DIR"
21
+ read -p "削除して再作成しますか? (y/N): " confirm
22
+ if [ "$confirm" != "y" ] && [ "$confirm" != "Y" ]; then
23
+ echo "中止しました。"
24
+ exit 0
25
+ fi
26
+ rm -rf "$APP_DIR"
27
+ fi
28
+
29
+ echo "1/6: Rails アプリを生成中..."
30
+ rails new "$APP_DIR" \
31
+ --database=sqlite3 \
32
+ --skip-git \
33
+ --skip-docker \
34
+ --skip-action-mailer \
35
+ --skip-action-mailbox \
36
+ --skip-action-text \
37
+ --skip-active-storage \
38
+ --skip-action-cable \
39
+ --skip-hotwire \
40
+ --skip-jbuilder \
41
+ --skip-test \
42
+ --skip-system-test \
43
+ --skip-bootsnap \
44
+ --skip-asset-pipeline \
45
+ --skip-javascript \
46
+ --minimal \
47
+ --quiet
48
+
49
+ cd "$APP_DIR"
50
+
51
+ # debug gem を追加
52
+ echo "" >> Gemfile
53
+ echo '# debug-mcp テスト用' >> Gemfile
54
+ echo 'gem "debug"' >> Gemfile
55
+ bundle install --quiet
56
+
57
+ echo "2/6: モデルを生成中..."
58
+
59
+ # User モデル: バリデーション、enum、アソシエーション
60
+ bin/rails generate model User \
61
+ name:string \
62
+ email:string \
63
+ role:integer \
64
+ active:boolean \
65
+ --quiet --no-test-framework
66
+
67
+ # Post モデル: belongs_to、スコープ
68
+ bin/rails generate model Post \
69
+ title:string \
70
+ body:text \
71
+ status:integer \
72
+ user:references \
73
+ published_at:datetime \
74
+ --quiet --no-test-framework
75
+
76
+ # Comment モデル: ポリモーフィック的な関連
77
+ bin/rails generate model Comment \
78
+ body:text \
79
+ user:references \
80
+ post:references \
81
+ --quiet --no-test-framework
82
+
83
+ echo "3/6: モデルコードを設定中..."
84
+
85
+ # User モデル
86
+ cat > app/models/user.rb << 'RUBY'
87
+ class User < ApplicationRecord
88
+ has_many :posts, dependent: :destroy
89
+ has_many :comments, dependent: :destroy
90
+
91
+ validates :name, presence: true, length: { maximum: 50 }
92
+ validates :email, presence: true, uniqueness: true,
93
+ format: { with: /\A[^@\s]+@[^@\s]+\z/ }
94
+
95
+ enum :role, { guest: 0, member: 1, editor: 2, admin: 3 }
96
+
97
+ scope :active, -> { where(active: true) }
98
+ scope :admins, -> { where(role: :admin) }
99
+ scope :recent, -> { order(created_at: :desc) }
100
+
101
+ def display_name
102
+ "#{name} (#{role})"
103
+ end
104
+ end
105
+ RUBY
106
+
107
+ # Post モデル
108
+ cat > app/models/post.rb << 'RUBY'
109
+ class Post < ApplicationRecord
110
+ belongs_to :user
111
+ has_many :comments, dependent: :destroy
112
+
113
+ validates :title, presence: true, length: { maximum: 100 }
114
+ validates :body, presence: true
115
+
116
+ enum :status, { draft: 0, published: 1, archived: 2 }
117
+
118
+ scope :published, -> { where(status: :published) }
119
+ scope :drafts, -> { where(status: :draft) }
120
+ scope :recent, -> { order(published_at: :desc) }
121
+ scope :by_user, ->(user_id) { where(user_id: user_id) }
122
+
123
+ def summary
124
+ body.to_s.truncate(100)
125
+ end
126
+ end
127
+ RUBY
128
+
129
+ # Comment モデル
130
+ cat > app/models/comment.rb << 'RUBY'
131
+ class Comment < ApplicationRecord
132
+ belongs_to :user
133
+ belongs_to :post
134
+
135
+ validates :body, presence: true, length: { minimum: 3 }
136
+
137
+ scope :recent, -> { order(created_at: :desc) }
138
+ end
139
+ RUBY
140
+
141
+ echo "4/6: コントローラとルーティングを設定中..."
142
+
143
+ # UsersController
144
+ mkdir -p app/controllers
145
+ cat > app/controllers/users_controller.rb << 'RUBY'
146
+ class UsersController < ApplicationController
147
+ before_action :set_user, only: [:show, :update, :destroy]
148
+
149
+ def index
150
+ @users = User.all
151
+ render json: @users
152
+ end
153
+
154
+ def show
155
+ render json: @user.as_json(include: { posts: { only: [:id, :title, :status] } })
156
+ end
157
+
158
+ def create
159
+ @user = User.new(user_params)
160
+ if @user.save
161
+ render json: @user, status: :created
162
+ else
163
+ render json: { errors: @user.errors.full_messages }, status: :unprocessable_entity
164
+ end
165
+ end
166
+
167
+ def update
168
+ if @user.update(user_params)
169
+ render json: @user
170
+ else
171
+ render json: { errors: @user.errors.full_messages }, status: :unprocessable_entity
172
+ end
173
+ end
174
+
175
+ def destroy
176
+ @user.destroy
177
+ head :no_content
178
+ end
179
+
180
+ private
181
+
182
+ def set_user
183
+ @user = User.find(params[:id])
184
+ end
185
+
186
+ def user_params
187
+ params.permit(:name, :email, :role, :active)
188
+ end
189
+ end
190
+ RUBY
191
+
192
+ # PostsController
193
+ cat > app/controllers/posts_controller.rb << 'RUBY'
194
+ class PostsController < ApplicationController
195
+ before_action :set_post, only: [:show, :update]
196
+
197
+ def index
198
+ @posts = Post.published.includes(:user).recent
199
+ render json: @posts.as_json(include: { user: { only: [:id, :name] } })
200
+ end
201
+
202
+ def show
203
+ render json: @post.as_json(
204
+ include: {
205
+ user: { only: [:id, :name] },
206
+ comments: { include: { user: { only: [:id, :name] } } }
207
+ }
208
+ )
209
+ end
210
+
211
+ def create
212
+ @post = Post.new(post_params)
213
+ if @post.save
214
+ render json: @post, status: :created
215
+ else
216
+ render json: { errors: @post.errors.full_messages }, status: :unprocessable_entity
217
+ end
218
+ end
219
+
220
+ def update
221
+ if @post.update(post_params)
222
+ render json: @post
223
+ else
224
+ render json: { errors: @post.errors.full_messages }, status: :unprocessable_entity
225
+ end
226
+ end
227
+
228
+ # 検索エンドポイント(デバッグ向け:N+1問題あり)
229
+ def search
230
+ query = params[:q].to_s
231
+ @posts = Post.where("title LIKE ?", "%#{query}%")
232
+
233
+ # 意図的なN+1(デバッグで発見させる)
234
+ results = @posts.map do |post|
235
+ {
236
+ id: post.id,
237
+ title: post.title,
238
+ author: post.user.name,
239
+ comments_count: post.comments.count
240
+ }
241
+ end
242
+
243
+ render json: results
244
+ end
245
+
246
+ private
247
+
248
+ def set_post
249
+ @post = Post.find(params[:id])
250
+ end
251
+
252
+ def post_params
253
+ params.permit(:title, :body, :status, :user_id, :published_at)
254
+ end
255
+ end
256
+ RUBY
257
+
258
+ # SessionsController(Cookie テスト用)
259
+ cat > app/controllers/sessions_controller.rb << 'RUBY'
260
+ class SessionsController < ApplicationController
261
+ def create
262
+ user = User.find_by(email: params[:email])
263
+ if user
264
+ session[:user_id] = user.id
265
+ render json: { message: "Logged in", user: user.as_json(only: [:id, :name, :email, :role]) }
266
+ else
267
+ render json: { error: "Invalid email" }, status: :unauthorized
268
+ end
269
+ end
270
+
271
+ def show
272
+ if session[:user_id]
273
+ user = User.find(session[:user_id])
274
+ render json: { logged_in: true, user: user.as_json(only: [:id, :name, :email, :role]) }
275
+ else
276
+ render json: { logged_in: false }
277
+ end
278
+ end
279
+
280
+ def destroy
281
+ session.delete(:user_id)
282
+ render json: { message: "Logged out" }
283
+ end
284
+ end
285
+ RUBY
286
+
287
+ # HealthController(シンプルなテスト用)
288
+ cat > app/controllers/health_controller.rb << 'RUBY'
289
+ class HealthController < ApplicationController
290
+ def show
291
+ render json: {
292
+ status: "ok",
293
+ rails_version: Rails::VERSION::STRING,
294
+ ruby_version: RUBY_VERSION,
295
+ environment: Rails.env,
296
+ time: Time.current.iso8601
297
+ }
298
+ end
299
+ end
300
+ RUBY
301
+
302
+ # DashboardController(HTMLレスポンス テスト用)
303
+ cat > app/controllers/dashboard_controller.rb << 'RUBY'
304
+ class DashboardController < ApplicationController
305
+ def index
306
+ @stats = {
307
+ users: User.count,
308
+ posts: Post.count,
309
+ comments: Comment.count,
310
+ published_posts: Post.published.count
311
+ }
312
+
313
+ render html: <<~HTML.html_safe
314
+ <!DOCTYPE html>
315
+ <html>
316
+ <head><title>Dashboard</title></head>
317
+ <body>
318
+ <h1>Dashboard</h1>
319
+ <ul>
320
+ <li>Users: #{@stats[:users]}</li>
321
+ <li>Posts: #{@stats[:posts]}</li>
322
+ <li>Comments: #{@stats[:comments]}</li>
323
+ <li>Published: #{@stats[:published_posts]}</li>
324
+ </ul>
325
+ </body>
326
+ </html>
327
+ HTML
328
+ end
329
+ end
330
+ RUBY
331
+
332
+ # ルーティング
333
+ cat > config/routes.rb << 'RUBY'
334
+ Rails.application.routes.draw do
335
+ resources :users, only: [:index, :show, :create, :update, :destroy]
336
+
337
+ resources :posts, only: [:index, :show, :create, :update] do
338
+ collection do
339
+ get :search
340
+ end
341
+ end
342
+
343
+ # セッション管理
344
+ post "/login", to: "sessions#create"
345
+ get "/me", to: "sessions#show"
346
+ delete "/logout", to: "sessions#destroy"
347
+
348
+ # ヘルスチェック
349
+ get "/health", to: "health#show"
350
+
351
+ # ダッシュボード(HTML)
352
+ get "/dashboard", to: "dashboard#index"
353
+
354
+ # ルートパス
355
+ root "health#show"
356
+ end
357
+ RUBY
358
+
359
+ echo "5/6: データベースをセットアップ中..."
360
+
361
+ bin/rails db:create db:migrate --quiet
362
+
363
+ # シードデータ
364
+ cat > db/seeds.rb << 'RUBY'
365
+ puts "シードデータを作成中..."
366
+
367
+ # ユーザー
368
+ alice = User.create!(name: "Alice", email: "alice@example.com", role: :admin, active: true)
369
+ bob = User.create!(name: "Bob", email: "bob@example.com", role: :editor, active: true)
370
+ carol = User.create!(name: "Carol", email: "carol@example.com", role: :member, active: true)
371
+ dave = User.create!(name: "Dave", email: "dave@example.com", role: :guest, active: false)
372
+
373
+ # 投稿
374
+ post1 = Post.create!(
375
+ title: "Rails デバッグ入門",
376
+ body: "debug gemを使ったRailsアプリケーションのデバッグ方法について解説します。breakpointの設定、変数の確認、ステップ実行など基本的なデバッグ技法を紹介します。",
377
+ status: :published,
378
+ user: alice,
379
+ published_at: 2.days.ago
380
+ )
381
+
382
+ post2 = Post.create!(
383
+ title: "ActiveRecordのN+1問題を解決する",
384
+ body: "includesやpreloadを使ってN+1クエリを解消する方法を紹介します。BulletやProsopiteなどの検出ツールも併せて解説します。",
385
+ status: :published,
386
+ user: bob,
387
+ published_at: 1.day.ago
388
+ )
389
+
390
+ post3 = Post.create!(
391
+ title: "下書き: テスト駆動開発のすすめ",
392
+ body: "RSpecを使ったTDDの実践方法について。まだ書きかけです。",
393
+ status: :draft,
394
+ user: alice
395
+ )
396
+
397
+ post4 = Post.create!(
398
+ title: "アーカイブ済み: 古い記事",
399
+ body: "この記事はアーカイブされました。",
400
+ status: :archived,
401
+ user: carol
402
+ )
403
+
404
+ # コメント
405
+ Comment.create!(body: "とても分かりやすい記事です!", user: bob, post: post1)
406
+ Comment.create!(body: "binding.breakの使い方も知りたいです。", user: carol, post: post1)
407
+ Comment.create!(body: "N+1問題に困っていたので助かりました。", user: alice, post: post2)
408
+ Comment.create!(body: "Bulletの設定方法をもう少し詳しく書いてほしいです。", user: dave, post: post2)
409
+
410
+ puts "完了: ユーザー#{User.count}人、投稿#{Post.count}件、コメント#{Comment.count}件"
411
+ RUBY
412
+
413
+ bin/rails db:seed
414
+
415
+ echo "6/6: 動作確認..."
416
+
417
+ echo ""
418
+ echo "=== セットアップ完了 ==="
419
+ echo ""
420
+ echo "テストアプリの起動方法:"
421
+ echo " cd $APP_DIR"
422
+ echo " RUBY_DEBUG_OPEN=true bin/rails server -p 3999"
423
+ echo ""
424
+ echo "debug-mcpからの接続:"
425
+ echo " 1. connect で Rails プロセスに接続"
426
+ echo " 2. rails_info でアプリ概要を確認"
427
+ echo " 3. 詳しいシナリオは examples/RAILS_SCENARIOS.md を参照"
428
+ echo ""
@@ -0,0 +1,10 @@
1
+ tmp/
2
+ log/
3
+ storage/*.sqlite3
4
+ .git
5
+ .gitignore
6
+ .ruby-version
7
+ .claude/
8
+ db/development.sqlite3
9
+ node_modules/
10
+ vendor/bundle
@@ -0,0 +1 @@
1
+ 3.3.4
@@ -0,0 +1,23 @@
1
+ FROM ruby:3.3.4-slim
2
+
3
+ RUN apt-get update -qq && \
4
+ apt-get install --no-install-recommends -y \
5
+ build-essential \
6
+ libsqlite3-dev \
7
+ curl && \
8
+ rm -rf /var/lib/apt/lists/*
9
+
10
+ WORKDIR /app
11
+
12
+ COPY Gemfile Gemfile.lock ./
13
+ RUN bundle install
14
+
15
+ COPY . .
16
+
17
+ COPY docker-entrypoint.sh /usr/bin/
18
+ RUN chmod +x /usr/bin/docker-entrypoint.sh
19
+
20
+ EXPOSE 3000 12345
21
+
22
+ ENTRYPOINT ["docker-entrypoint.sh"]
23
+ CMD ["bin/rails", "server", "-b", "0.0.0.0"]
@@ -0,0 +1,17 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Bundle edge Rails instead: gem "rails", github: "rails/rails", branch: "main"
4
+ gem "rails", "~> 8.1.1"
5
+ # Use sqlite3 as the database for Active Record
6
+ gem "sqlite3", ">= 2.1"
7
+ # Use the Puma web server [https://github.com/puma/puma]
8
+ gem "puma", ">= 5.0"
9
+
10
+ # Windows does not include zoneinfo files, so bundle the tzinfo-data gem
11
+ gem "tzinfo-data", platforms: %i[ windows jruby ]
12
+
13
+ group :development, :test do
14
+ # See https://guides.rubyonrails.org/debugging_rails_applications.html#debugging-with-the-debug-gem
15
+ gem "debug", platforms: %i[ mri windows ]
16
+ end
17
+
@@ -0,0 +1,65 @@
1
+ # Rails Test App for debug-mcp
2
+
3
+ debug-mcpの動作検証用Railsアプリケーション。ローカルでもDockerでも実行可能。
4
+
5
+ ## ローカル実行
6
+
7
+ ```bash
8
+ bundle install
9
+ bin/rails db:prepare
10
+ RUBY_DEBUG_OPEN=true bin/rails server
11
+ ```
12
+
13
+ debug-mcpから接続:
14
+ ```
15
+ connect # Unix socketで自動検出
16
+ ```
17
+
18
+ ## Docker実行
19
+
20
+ ```bash
21
+ docker compose up --build
22
+ ```
23
+
24
+ 起動確認:
25
+ ```bash
26
+ curl http://localhost:3000/health
27
+ ```
28
+
29
+ debug-mcpから接続:
30
+ ```
31
+ connect(host: "localhost", port: 12345)
32
+ ```
33
+
34
+ ### Dockerデバッグの流れ
35
+
36
+ 接続するとtrap context(Pumaのシグナルハンドラ内)で停止します。
37
+ DB操作やモデルのautoloadingは使えないため、ブレークポイント経由で通常コンテキストに移行します:
38
+
39
+ ```
40
+ 1. set_breakpoint(file: "app/controllers/users_controller.rb", line: 5)
41
+ 2. trigger_request(method: "GET", url: "http://localhost:3000/users")
42
+ 3. # ブレークポイントにヒット → evaluate_code, get_context 等が使える
43
+ 4. continue_execution # リクエスト完了
44
+ ```
45
+
46
+ 停止:
47
+ ```bash
48
+ docker compose down
49
+ ```
50
+
51
+ ## エンドポイント
52
+
53
+ | メソッド | パス | 説明 |
54
+ |---------|------|------|
55
+ | GET | /health | ヘルスチェック |
56
+ | GET | /users | ユーザー一覧 |
57
+ | GET | /users/:id | ユーザー詳細 |
58
+ | GET | /posts | 投稿一覧 |
59
+ | GET | /orders | 注文一覧 |
60
+ | GET | /dashboard | ダッシュボード(HTML) |
61
+
62
+ ## シードデータ
63
+
64
+ - ユーザー4人 (Alice/admin, Bob/editor, Carol/member, Dave/guest)
65
+ - 投稿4件、コメント4件、注文6件
@@ -0,0 +1,6 @@
1
+ # Add your own tasks in files placed in lib/tasks ending in .rake,
2
+ # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
3
+
4
+ require_relative "config/application"
5
+
6
+ Rails.application.load_tasks
@@ -0,0 +1 @@
1
+ /* Application styles */
@@ -0,0 +1,4 @@
1
+ class ApplicationController < ActionController::Base
2
+ # Only allow modern browsers supporting webp images, web push, badges, import maps, CSS nesting, and CSS :has.
3
+ allow_browser versions: :modern
4
+ end
@@ -0,0 +1,38 @@
1
+ class DashboardController < ApplicationController
2
+ def index
3
+ @stats = {
4
+ users: User.count,
5
+ posts: Post.count,
6
+ comments: Comment.count,
7
+ published_posts: Post.published.count
8
+ }
9
+ @trending = Post.trending(3)
10
+ @revenue = Order.revenue_stats
11
+
12
+ render html: <<~HTML.html_safe
13
+ <!DOCTYPE html>
14
+ <html>
15
+ <head><title>Dashboard</title></head>
16
+ <body>
17
+ <h1>Dashboard</h1>
18
+ <ul>
19
+ <li>Users: #{@stats[:users]}</li>
20
+ <li>Posts: #{@stats[:posts]}</li>
21
+ <li>Comments: #{@stats[:comments]}</li>
22
+ <li>Published: #{@stats[:published_posts]}</li>
23
+ </ul>
24
+ <h2>Trending Posts</h2>
25
+ <ol>
26
+ #{@trending.map { |p| "<li>#{p.title} (#{p.comments.size} comments)</li>" }.join}
27
+ </ol>
28
+ <h2>Revenue</h2>
29
+ <ul>
30
+ <li>Total Revenue: #{@revenue[:total_revenue]} cents</li>
31
+ <li>Average Order: #{@revenue[:average_order]} cents</li>
32
+ <li>Order Count: #{@revenue[:order_count]}</li>
33
+ </ul>
34
+ </body>
35
+ </html>
36
+ HTML
37
+ end
38
+ end
@@ -0,0 +1,11 @@
1
+ class HealthController < ApplicationController
2
+ def show
3
+ render json: {
4
+ status: "ok",
5
+ rails_version: Rails::VERSION::STRING,
6
+ ruby_version: RUBY_VERSION,
7
+ environment: Rails.env,
8
+ time: Time.current.iso8601
9
+ }
10
+ end
11
+ end