solid_mcp 0.0.1 → 0.2.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: 29d6d3f0a1664e3251f979c1b7101118bcbebfe8d3d9527dcaa882d21fe4e5b8
4
- data.tar.gz: e82f187470b4f1000c636762923500d416824ba22dc03271867d23326591edb3
3
+ metadata.gz: 3aa4d7472deba4836dde19ecd8f77ddf711078e1e67653e217234e68db7e8aba
4
+ data.tar.gz: 980e352ee18764b440a56cad8c8201e9158288ba617812181b72fc04af2c1405
5
5
  SHA512:
6
- metadata.gz: 3ec8873e380d109bce8aeae2765ebf7f9a3d5038279ffd665632fafd5afaf18f78f5b74260fd66f63e617b89ddc6dcb3cdcfe7563f7d85b1a9c13c9c1894e470
7
- data.tar.gz: adc942e4024067f9d99b3cf3089ed5e064a6451a33d170b12214dc3a24de4b95ef8b10122df6997f2a30beda86c6c1bcc36c6df01e641b1547766bf058b684b6
6
+ metadata.gz: ec42aab4269af5a30ae4bf9378cdbbbd0e3e00fc52fdf000ecd05367d520f59dc275e4d4ec536d887508e8fbf93c3de915aeed505a8a31d95439fa3e61f0dd4b
7
+ data.tar.gz: a9804075acc655457b4e857d154278ef3125706478048ec822ce42a8da29e335777017666831ef3b9793cc4bbf7add35d90fb2ae8ff6e74914f78e716ba5cccd
@@ -0,0 +1 @@
1
+ {".":"0.2.1"}
data/CHANGELOG.md CHANGED
@@ -1,5 +1,20 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.2.1](https://github.com/seuros/solid_mcp/compare/solid_mcp/v0.2.0...solid_mcp/v0.2.1) (2025-07-01)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * add issues permission to release workflow ([dd6d90d](https://github.com/seuros/solid_mcp/commit/dd6d90d5d3e87987c80215401bc422abf02da1b0))
9
+ * add issues permission to release workflow ([1105f92](https://github.com/seuros/solid_mcp/commit/1105f926d1266f107dad80839c1ae7bd178f8bd0))
10
+
11
+ ## [0.2.0](https://github.com/seuros/solid_mcp/compare/solid_mcp-v0.1.0...solid_mcp/v0.2.0) (2025-07-01)
12
+
13
+
14
+ ### Features
15
+
16
+ * initial implementation of SolidMCP ([6123b7a](https://github.com/seuros/solid_mcp/commit/6123b7a04a7a726892f04da9e33147ce2bfcfeb5))
17
+
3
18
  ## [0.1.0] - 2025-05-20
4
19
 
5
20
  - Initial release
data/Gemfile.lock ADDED
@@ -0,0 +1,140 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ solid_mcp (0.2.1)
5
+ activejob (>= 8.0)
6
+ activerecord (>= 8.0)
7
+ concurrent-ruby (~> 1.0)
8
+ railties (>= 8.0)
9
+
10
+ GEM
11
+ remote: https://rubygems.org/
12
+ specs:
13
+ actionpack (8.0.2)
14
+ actionview (= 8.0.2)
15
+ activesupport (= 8.0.2)
16
+ nokogiri (>= 1.8.5)
17
+ rack (>= 2.2.4)
18
+ rack-session (>= 1.0.1)
19
+ rack-test (>= 0.6.3)
20
+ rails-dom-testing (~> 2.2)
21
+ rails-html-sanitizer (~> 1.6)
22
+ useragent (~> 0.16)
23
+ actionview (8.0.2)
24
+ activesupport (= 8.0.2)
25
+ builder (~> 3.1)
26
+ erubi (~> 1.11)
27
+ rails-dom-testing (~> 2.2)
28
+ rails-html-sanitizer (~> 1.6)
29
+ activejob (8.0.2)
30
+ activesupport (= 8.0.2)
31
+ globalid (>= 0.3.6)
32
+ activemodel (8.0.2)
33
+ activesupport (= 8.0.2)
34
+ activerecord (8.0.2)
35
+ activemodel (= 8.0.2)
36
+ activesupport (= 8.0.2)
37
+ timeout (>= 0.4.0)
38
+ activesupport (8.0.2)
39
+ base64
40
+ benchmark (>= 0.3)
41
+ bigdecimal
42
+ concurrent-ruby (~> 1.0, >= 1.3.1)
43
+ connection_pool (>= 2.2.5)
44
+ drb
45
+ i18n (>= 1.6, < 2)
46
+ logger (>= 1.4.2)
47
+ minitest (>= 5.1)
48
+ securerandom (>= 0.3)
49
+ tzinfo (~> 2.0, >= 2.0.5)
50
+ uri (>= 0.13.1)
51
+ base64 (0.2.0)
52
+ benchmark (0.4.0)
53
+ bigdecimal (3.1.9)
54
+ builder (3.3.0)
55
+ concurrent-ruby (1.3.5)
56
+ connection_pool (2.5.3)
57
+ crass (1.0.6)
58
+ date (3.4.1)
59
+ drb (2.2.1)
60
+ erb (5.0.1)
61
+ erubi (1.13.1)
62
+ globalid (1.2.1)
63
+ activesupport (>= 6.1)
64
+ i18n (1.14.7)
65
+ concurrent-ruby (~> 1.0)
66
+ io-console (0.8.0)
67
+ irb (1.15.2)
68
+ pp (>= 0.6.0)
69
+ rdoc (>= 4.0.0)
70
+ reline (>= 0.4.2)
71
+ logger (1.7.0)
72
+ loofah (2.24.1)
73
+ crass (~> 1.0.2)
74
+ nokogiri (>= 1.12.0)
75
+ minitest (5.25.5)
76
+ nokogiri (1.18.8-arm64-darwin)
77
+ racc (~> 1.4)
78
+ nokogiri (1.18.8-x86_64-linux-gnu)
79
+ racc (~> 1.4)
80
+ pp (0.6.2)
81
+ prettyprint
82
+ prettyprint (0.2.0)
83
+ psych (5.2.6)
84
+ date
85
+ stringio
86
+ racc (1.8.1)
87
+ rack (3.1.15)
88
+ rack-session (2.1.1)
89
+ base64 (>= 0.1.0)
90
+ rack (>= 3.0.0)
91
+ rack-test (2.2.0)
92
+ rack (>= 1.3)
93
+ rackup (2.2.1)
94
+ rack (>= 3)
95
+ rails-dom-testing (2.2.0)
96
+ activesupport (>= 5.0.0)
97
+ minitest
98
+ nokogiri (>= 1.6)
99
+ rails-html-sanitizer (1.6.2)
100
+ loofah (~> 2.21)
101
+ nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0)
102
+ railties (8.0.2)
103
+ actionpack (= 8.0.2)
104
+ activesupport (= 8.0.2)
105
+ irb (~> 1.13)
106
+ rackup (>= 1.0.0)
107
+ rake (>= 12.2)
108
+ thor (~> 1.0, >= 1.2.2)
109
+ zeitwerk (~> 2.6)
110
+ rake (13.2.1)
111
+ rdoc (6.14.0)
112
+ erb
113
+ psych (>= 4.0.0)
114
+ reline (0.6.1)
115
+ io-console (~> 0.5)
116
+ securerandom (0.4.1)
117
+ sqlite3 (2.7.0-arm64-darwin)
118
+ sqlite3 (2.7.0-x86_64-linux-gnu)
119
+ stringio (3.1.7)
120
+ thor (1.3.2)
121
+ timeout (0.4.3)
122
+ tzinfo (2.0.6)
123
+ concurrent-ruby (~> 1.0)
124
+ uri (1.0.3)
125
+ useragent (0.16.11)
126
+ zeitwerk (2.7.3)
127
+
128
+ PLATFORMS
129
+ arm64-darwin-24
130
+ x86_64-linux
131
+
132
+ DEPENDENCIES
133
+ irb
134
+ minitest (~> 5.16)
135
+ rake (~> 13.0)
136
+ solid_mcp!
137
+ sqlite3 (~> 2.0)
138
+
139
+ BUNDLED WITH
140
+ 2.6.9
data/README.md CHANGED
@@ -1,39 +1,328 @@
1
- # SolidMcp
1
+ # SolidMCP
2
2
 
3
- TODO: Delete this and the text below, and describe your gem
3
+ SolidMCP is a high-performance, database-backed pub/sub engine specifically designed for ActionMCP (Model Context Protocol for Rails). It provides reliable message delivery for MCP's Server-Sent Events (SSE) with support for SQLite, PostgreSQL, and MySQL.
4
4
 
5
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/solid_mcp`. To experiment with that code, run `bin/console` for an interactive prompt.
5
+ ## Features
6
+
7
+ - **Database-agnostic**: Works with SQLite, PostgreSQL, and MySQL
8
+ - **Session-based routing**: Optimized for MCP's point-to-point messaging pattern
9
+ - **Batched writes**: Handles SQLite's single-writer limitation efficiently
10
+ - **Automatic cleanup**: Configurable retention periods for delivered/undelivered messages
11
+ - **Thread-safe**: Dedicated writer thread with in-memory queuing
12
+ - **SSE resumability**: Supports reconnection with last-event-id
13
+ - **Rails Engine**: Seamless integration with Rails applications
14
+ - **Multiple backends**: Database backend by default, Redis backend coming soon
15
+
16
+ ## Requirements
17
+
18
+ - Ruby 3.0+
19
+ - Rails 8.0+
20
+ - ActiveRecord 8.0+
21
+ - SQLite, PostgreSQL, or MySQL database
6
22
 
7
23
  ## Installation
8
24
 
9
- TODO: Replace `UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG` with your gem name right after releasing it to RubyGems.org. Please do not do it earlier due to security reasons. Alternatively, replace this section with instructions to install your gem from git if you don't plan to release to RubyGems.org.
25
+ Add this line to your application's Gemfile:
26
+
27
+ ```ruby
28
+ gem 'solid_mcp'
29
+ ```
10
30
 
11
- Install the gem and add to the application's Gemfile by executing:
31
+ And then execute:
12
32
 
13
33
  ```bash
14
- bundle add UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG
34
+ bundle install
15
35
  ```
16
36
 
17
- If bundler is not being used to manage dependencies, install the gem by executing:
37
+ Run the installation generator:
18
38
 
19
39
  ```bash
20
- gem install UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG
40
+ bin/rails generate solid_mcp:install
41
+ bin/rails db:migrate
42
+ ```
43
+
44
+ This will:
45
+ - Create a migration for the `solid_mcp_messages` table
46
+ - Create an initializer with default configuration
47
+
48
+ ## Configuration
49
+
50
+ Configure SolidMCP in your Rails application:
51
+
52
+ ```ruby
53
+ # config/initializers/solid_mcp.rb
54
+ SolidMcp.configure do |config|
55
+ # Number of messages to write in a single batch
56
+ config.batch_size = 200
57
+
58
+ # Seconds between batch flushes
59
+ config.flush_interval = 0.05
60
+
61
+ # Polling interval for checking new messages
62
+ config.polling_interval = 0.1
63
+
64
+ # Maximum time to wait for messages before timeout
65
+ config.max_wait_time = 30
66
+
67
+ # How long to keep delivered messages
68
+ config.delivered_retention = 1.hour
69
+
70
+ # How long to keep undelivered messages
71
+ config.undelivered_retention = 24.hours
72
+ end
21
73
  ```
22
74
 
23
- ## Usage
75
+ ## Usage with ActionMCP
76
+
77
+ In your `config/mcp.yml`:
78
+
79
+ ```yaml
80
+ production:
81
+ adapter: solid_mcp
82
+ polling_interval: 0.5.seconds
83
+ batch_size: 200
84
+ flush_interval: 0.05
85
+ ```
86
+
87
+ ## Architecture
88
+
89
+ SolidMCP is implemented as a Rails Engine with the following components:
90
+
91
+ ### Core Components
92
+
93
+ 1. **SolidMCP::MessageWriter**: Singleton that handles batched writes to the database
94
+ - Non-blocking enqueue operation
95
+ - Dedicated writer thread per Rails process
96
+ - Automatic batching and flushing
97
+ - Graceful shutdown with pending message delivery
98
+
99
+ 2. **SolidMCP::PubSub**: Main interface for publishing and subscribing to messages
100
+ - Session-based subscriptions (not channel-based)
101
+ - Automatic listener management per session
102
+ - Thread-safe operations
103
+
104
+ 3. **SolidMCP::Subscriber**: Handles polling for new messages
105
+ - Efficient database queries using indexes
106
+ - Automatic message delivery tracking
107
+ - Configurable polling intervals
24
108
 
25
- TODO: Write usage instructions here
109
+ 4. **SolidMCP::Message**: ActiveRecord model for message storage
110
+ - Optimized indexes for polling and cleanup
111
+ - Scopes for message filtering
112
+ - Built-in cleanup methods
113
+
114
+ ### Message Flow
115
+
116
+ 1. Publisher calls `broadcast(session_id, event_type, data)`
117
+ 2. MessageWriter queues the message in memory
118
+ 3. Writer thread batches messages and writes to database
119
+ 4. Subscriber polls for new messages for its session
120
+ 5. Messages are marked as delivered after successful processing
121
+
122
+ ## Database Schema
123
+
124
+ The gem creates a `solid_mcp_messages` table:
125
+
126
+ ```ruby
127
+ create_table :solid_mcp_messages do |t|
128
+ t.string :session_id, null: false, limit: 36 # MCP session identifier
129
+ t.string :event_type, null: false, limit: 50 # SSE event type
130
+ t.text :data # Message payload (usually JSON)
131
+ t.datetime :created_at, null: false # Message creation time
132
+ t.datetime :delivered_at # Delivery timestamp
133
+
134
+ t.index [:session_id, :id], name: 'idx_solid_mcp_messages_on_session_and_id'
135
+ t.index [:delivered_at, :created_at], name: 'idx_solid_mcp_messages_on_delivered_and_created'
136
+ end
137
+ ```
138
+
139
+ ## Performance Considerations
140
+
141
+ ### SQLite
142
+ - Single writer thread prevents "database is locked" errors
143
+ - Batching reduces write frequency
144
+ - Consider WAL mode for better concurrency
145
+
146
+ ### PostgreSQL/MySQL
147
+ - Benefits from batching to reduce transaction overhead
148
+ - Can handle multiple writers but single writer is maintained for consistency
149
+ - Consider partitioning for high-volume applications
150
+
151
+ ## Maintenance
152
+
153
+ ### Automatic Cleanup
154
+
155
+ Old messages are automatically cleaned up based on retention settings:
156
+
157
+ ```ruby
158
+ # Run periodically (e.g., with whenever gem or solid_queue)
159
+ SolidMCP::CleanupJob.perform_later
160
+
161
+ # Or directly:
162
+ SolidMCP::Message.cleanup
163
+ ```
164
+
165
+ ### Manual Cleanup
166
+
167
+ ```ruby
168
+ # Clean up delivered messages older than 1 hour
169
+ SolidMCP::Message.old_delivered(1.hour).delete_all
170
+
171
+ # Clean up undelivered messages older than 24 hours
172
+ SolidMCP::Message.old_undelivered(24.hours).delete_all
173
+ ```
174
+
175
+ ### Monitoring
176
+
177
+ ```ruby
178
+ # Check message queue size
179
+ SolidMCP::Message.undelivered.count
180
+
181
+ # Check messages for a specific session
182
+ SolidMCP::Message.for_session(session_id).count
183
+
184
+ # Find stuck messages
185
+ SolidMCP::Message.undelivered.where('created_at < ?', 1.hour.ago)
186
+ ```
187
+
188
+ ## Testing
189
+
190
+ The gem includes a test implementation for use in test environments:
191
+
192
+ ```ruby
193
+ # In test environment, SolidMCP::PubSub automatically uses TestPubSub
194
+ # which provides immediate delivery without database persistence
195
+ ```
196
+
197
+ Run the test suite:
198
+
199
+ ```bash
200
+ bundle exec rake test
201
+ ```
202
+
203
+ ### Testing in Your Application
204
+
205
+ ```ruby
206
+ # test/test_helper.rb
207
+ class ActiveSupport::TestCase
208
+ setup do
209
+ SolidMCP::Message.delete_all
210
+ end
211
+ end
212
+
213
+ # In your tests
214
+ test "broadcasts message to session" do
215
+ pubsub = SolidMCP::PubSub.new
216
+ messages = []
217
+
218
+ pubsub.subscribe("test-session") do |msg|
219
+ messages << msg
220
+ end
221
+
222
+ pubsub.broadcast("test-session", "test_event", { data: "test" })
223
+
224
+ assert_equal 1, messages.size
225
+ assert_equal "test_event", messages.first[:event_type]
226
+ end
227
+ ```
228
+
229
+ ## SSE Integration
230
+
231
+ SolidMCP is designed to work seamlessly with Server-Sent Events:
232
+
233
+ ```ruby
234
+ # In your SSE controller
235
+ def sse_endpoint
236
+ response.headers['Content-Type'] = 'text/event-stream'
237
+
238
+ pubsub = SolidMCP::PubSub.new
239
+ last_event_id = request.headers['Last-Event-ID']
240
+
241
+ # Resume from last event if reconnecting
242
+ if last_event_id
243
+ missed_messages = SolidMCP::Message
244
+ .for_session(session_id)
245
+ .after_id(last_event_id)
246
+ .undelivered
247
+
248
+ missed_messages.each do |msg|
249
+ response.stream.write "id: #{msg.id}\n"
250
+ response.stream.write "event: #{msg.event_type}\n"
251
+ response.stream.write "data: #{msg.data}\n\n"
252
+ end
253
+ end
254
+
255
+ # Subscribe to new messages
256
+ pubsub.subscribe(session_id) do |message|
257
+ response.stream.write "id: #{message[:id]}\n"
258
+ response.stream.write "event: #{message[:event_type]}\n"
259
+ response.stream.write "data: #{message[:data]}\n\n"
260
+ end
261
+ ensure
262
+ pubsub&.unsubscribe(session_id)
263
+ response.stream.close
264
+ end
265
+ ```
26
266
 
27
267
  ## Development
28
268
 
29
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
269
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests.
270
+
271
+ ### Running Tests
272
+
273
+ ```bash
274
+ # Run all tests
275
+ bundle exec rake test
276
+
277
+ # Run specific test file
278
+ bundle exec ruby test/solid_mcp/message_test.rb
279
+ ```
280
+
281
+ ## Roadmap
282
+
283
+ ### Redis Backend (Coming Soon)
284
+
285
+ Future versions will support Redis as an alternative backend:
286
+
287
+ ```ruby
288
+ # config/initializers/solid_mcp.rb
289
+ SolidMCP.configure do |config|
290
+ config.backend = :redis
291
+ config.redis_url = ENV['REDIS_URL']
292
+ end
293
+ ```
30
294
 
31
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
295
+ This will provide:
296
+ - Lower latency for high-traffic applications
297
+ - Pub/Sub without polling
298
+ - Automatic expiration of old messages
299
+ - Better horizontal scaling
300
+
301
+ ## Comparison with Other Solutions
302
+
303
+ | Feature | SolidMCP | ActionCable + Redis | Custom Polling |
304
+ |---------|----------|-------------------|----------------|
305
+ | No Redis Required | ✅ | ❌ | ✅ |
306
+ | SSE Resumability | ✅ | ❌ | Manual |
307
+ | Horizontal Scaling | ✅ (with DB) | ✅ | ❌ |
308
+ | Message Persistence | ✅ | ❌ | Manual |
309
+ | Batch Writing | ✅ | N/A | ❌ |
310
+ | SQLite Support | ✅ | ❌ | ✅ |
32
311
 
33
312
  ## Contributing
34
313
 
35
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/solid_mcp.
314
+ Bug reports and pull requests are welcome on GitHub at https://github.com/seuros/solid_mcp.
315
+
316
+ ### Development Setup
317
+
318
+ 1. Fork the repository
319
+ 2. Clone your fork
320
+ 3. Install dependencies: `bundle install`
321
+ 4. Create a feature branch: `git checkout -b my-feature`
322
+ 5. Make your changes and add tests
323
+ 6. Run tests: `bundle exec rake test`
324
+ 7. Push to your fork and submit a pull request
36
325
 
37
326
  ## License
38
327
 
39
- The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
328
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SolidMCP
4
+ class Message < Record
5
+ self.table_name = "solid_mcp_messages"
6
+
7
+ scope :for_session, ->(session_id) { where(session_id: session_id) }
8
+ scope :undelivered, -> { where(delivered_at: nil) }
9
+ scope :delivered, -> { where.not(delivered_at: nil) }
10
+ scope :after_id, ->(id) { where("id > ?", id) }
11
+ scope :old_delivered, ->(age) { delivered.where("delivered_at < ?", age.ago) }
12
+ scope :old_undelivered, ->(age) { undelivered.where("created_at < ?", age.ago) }
13
+
14
+ # Mark messages as delivered
15
+ def self.mark_delivered(ids)
16
+ where(id: ids).update_all(delivered_at: Time.current)
17
+ end
18
+
19
+ # Cleanup old messages
20
+ def self.cleanup(delivered_retention: 1.hour, undelivered_retention: 24.hours)
21
+ old_delivered(delivered_retention).delete_all
22
+ old_undelivered(undelivered_retention).delete_all
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SolidMCP
4
+ class Record < ActiveRecord::Base
5
+ self.abstract_class = true
6
+
7
+ # Use primary database connection by default
8
+ # Can be overridden with connects_to in production if needed
9
+ end
10
+ end
data/bin/rails ADDED
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # This command will automatically be run when you run "rails" with Rails gems
5
+ # installed from the root of your application.
6
+
7
+ ENGINE_ROOT = File.expand_path('..', __dir__)
8
+ APP_PATH = File.expand_path('../test/dummy/config/application', __dir__)
9
+
10
+ # Set up gems listed in the Gemfile.
11
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
12
+ require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])
13
+
14
+ require 'rails/all'
15
+ require 'rails/engine/commands'
data/bin/test ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "bundler/setup"
5
+ require "minitest/autorun"
6
+
7
+ # Load all test files
8
+ Dir[File.expand_path("../test/**/*_test.rb", __dir__)].each { |f| require f }
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ class CreateSolidMCPMessages < ActiveRecord::Migration[7.0]
4
+ def change
5
+ create_table :solid_mcp_messages do |t|
6
+ # Session this message belongs to
7
+ t.string :session_id, null: false, limit: 36
8
+
9
+ # Type of event (e.g., 'message', 'ping', 'connection_closed')
10
+ t.string :event_type, null: false, limit: 50
11
+
12
+ # The actual data payload
13
+ t.text :data
14
+
15
+ # Timestamp when message was created
16
+ t.datetime :created_at, null: false
17
+
18
+ # Timestamp when message was delivered
19
+ t.datetime :delivered_at
20
+
21
+ # Composite index for efficient polling
22
+ t.index [:session_id, :id], name: 'idx_solid_mcp_messages_on_session_and_id'
23
+
24
+ # Index for cleanup
25
+ t.index [:delivered_at, :created_at], name: 'idx_solid_mcp_messages_on_delivered_and_created'
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/generators"
4
+ require "rails/generators/active_record"
5
+
6
+ module SolidMCP
7
+ module Generators
8
+ class InstallGenerator < Rails::Generators::Base
9
+ include ActiveRecord::Generators::Migration
10
+
11
+ source_root File.expand_path("templates", __dir__)
12
+
13
+ def create_migration_file
14
+ migration_template "create_solid_mcp_messages.rb.erb", "db/migrate/create_solid_mcp_messages.rb"
15
+ end
16
+
17
+ def add_initializer
18
+ template "solid_mcp.rb", "config/initializers/solid_mcp.rb"
19
+ end
20
+
21
+ private
22
+
23
+ def migration_version
24
+ "[#{ActiveRecord::VERSION::MAJOR}.#{ActiveRecord::VERSION::MINOR}]"
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,26 @@
1
+ class CreateSolidMCPMessages < ActiveRecord::Migration<%= migration_version %>
2
+ def change
3
+ create_table :solid_mcp_messages do |t|
4
+ # Session this message belongs to
5
+ t.string :session_id, null: false, limit: 36
6
+
7
+ # Type of event (e.g., 'message', 'ping', 'connection_closed')
8
+ t.string :event_type, null: false, limit: 50
9
+
10
+ # The actual data payload
11
+ t.text :data
12
+
13
+ # Timestamp when message was created
14
+ t.datetime :created_at, null: false
15
+
16
+ # Timestamp when message was delivered
17
+ t.datetime :delivered_at
18
+
19
+ # Composite index for efficient polling
20
+ t.index [:session_id, :id], name: 'idx_solid_mcp_messages_on_session_and_id'
21
+
22
+ # Index for cleanup
23
+ t.index [:delivered_at, :created_at], name: 'idx_solid_mcp_messages_on_delivered_and_created'
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Initialize SolidMCP message writer
4
+ Rails.application.config.to_prepare do
5
+ # Ensure the writer thread is started
6
+ SolidMCP::MessageWriter.instance
7
+ end
8
+
9
+ # Gracefully shutdown on exit
10
+ at_exit do
11
+ SolidMCP::MessageWriter.instance.shutdown if defined?(SolidMCP::MessageWriter)
12
+ end
13
+
14
+ # Configure SolidMCP
15
+ SolidMCP.configure do |config|
16
+ config.batch_size = 200
17
+ config.flush_interval = 0.05
18
+ config.delivered_retention = 1.hour
19
+ config.undelivered_retention = 24.hours
20
+ end