mcp_on_ruby 0.1.0 → 0.3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cc959666bde188d8d9642e81879d3e16436b592a36e503e7c3d6f23dd040810b
4
- data.tar.gz: ce86ed0d4ce97276435ad7192133dc8a6b613cc4974996cdd41cbabae1f15ae7
3
+ metadata.gz: 04166e9711a0a9c233c43a2f1bba53b27d0a716a7cc996c52f597433e559909d
4
+ data.tar.gz: 588bbbd27e9bc620e4cf4ea14b97b4e8c5cd869b672f8956a2a17b16b179afdb
5
5
  SHA512:
6
- metadata.gz: a41b4314669cf296ff64d5d71524472da25de3ca43e8b27bfab3d1b5fdf5e2969f208c11c5b094849b648f7e1bc53ce3b51bf7c4917e4322542d026d53488d28
7
- data.tar.gz: 541c892381b491280fa0c74f168782afcba411d43657686880cabd67a560a1fc34b7f8529ce0049cf3ac477209b52e134f60dcd3083aab10faa3dee311341803
6
+ metadata.gz: c22a5a6e40162c8754975bb89288ee5147314e41564a97ea25ab7b85fae03eecfcdc7246a0567520d6813ead8bc22e88ffcfa265ccf16653c2da8f06da8adb28
7
+ data.tar.gz: e16b57bd9c57d50f1f9f46328d29b94986e54785b166cbf321db1d06366fcd0fa2d43dd7206468ac3671219be7800c8a1f8ccbaaea2eaa77ca4e95217c32da2f
data/CHANGELOG.md CHANGED
@@ -1,5 +1,33 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.3.0] - 2023-05-01
4
+
5
+ ### Added
6
+ - ActiveRecord storage backend for database persistence
7
+ - Support for Rails integration with ActiveRecord storage
8
+ - Auto-creation of database tables with configurable prefixes
9
+ - Proper handling of different data types (text, binary, JSON)
10
+ - Symbolization of hash keys for consistent API
11
+ - Comprehensive test suite for ActiveRecord storage
12
+
13
+ ### Changed
14
+ - Enhanced `StorageFactory` to support ActiveRecord backend
15
+ - Updated configuration system with ActiveRecord options
16
+ - Improved documentation with ActiveRecord storage examples
17
+
18
+ ## [0.2.0] - 2025-04-21
19
+
20
+ ### Added
21
+ - Redis storage backend with comprehensive test coverage
22
+ - Configurable TTL and namespace support for Redis keys
23
+ - Rails integration with Redis storage examples
24
+ - Wiki documentation for Redis storage setup and usage
25
+
26
+ ### Changed
27
+ - Enhanced storage factory to support different backend types
28
+ - Improved configuration API for more intuitive setup
29
+ - Updated README with Redis storage documentation
30
+
3
31
  ## [0.1.0] - 2025-04-18
4
32
 
5
33
  Initial release of version 0.1.0 of the Ruby Gem.
data/README.md CHANGED
@@ -1,61 +1,64 @@
1
1
  <div align="center">
2
2
 
3
- # RubyMCP
4
-
3
+ # MCP on Ruby
4
+ [![Gem Version](https://badge.fury.io/rb/mcp_on_ruby.svg)](https://badge.fury.io/rb/mcp_on_ruby)
5
5
  [![Build](https://github.com/nagstler/ruby_mcp/actions/workflows/build.yml/badge.svg)](https://github.com/nagstler/ruby_mcp/actions/workflows/build.yml)
6
6
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
7
  [![RuboCop](https://github.com/nagstler/ruby_mcp/actions/workflows/rubocop.yml/badge.svg)](https://github.com/nagstler/ruby_mcp/actions/workflows/rubocop.yml)
8
8
  [![Test](https://github.com/nagstler/ruby_mcp/actions/workflows/test.yml/badge.svg)](https://github.com/nagstler/ruby_mcp/actions/workflows/test.yml)
9
9
  [![codecov](https://codecov.io/github/nagstler/ruby_mcp/graph/badge.svg?token=SG4EJEIHW3)](https://codecov.io/github/nagstler/ruby_mcp)
10
10
 
11
- <strong>The Ruby way to build MCP servers and clients.</strong>
11
+ <strong> **Turn your Rails APIs into an MCP server.**</strong>
12
+
12
13
  </div>
13
14
 
14
- ## Introduction
15
+ ## 🔍 Introduction
16
+ The [Model Context Protocol](https://modelcontextprotocol.io) standardizes how applications interact with AI models, serving as the "REST for LLMs." **MCP on Ruby** brings this standard to the Ruby ecosystem. Create contexts, manage conversations, connect to multiple providers, and handle streaming responses with clean, Ruby code.
15
17
 
16
- The [Model Context Protocol (MCP)](https://modelcontextprotocol.io) provides a standardized way for applications to interact with various language model providers (like OpenAI, Anthropic, etc.) through a consistent interface.
18
+ ![System Component Flow (Horizontal)](https://github.com/user-attachments/assets/085ad9b8-bee0-4d60-a4b7-ecf02d07f53c)
17
19
 
18
- ![design-1](https://github.com/user-attachments/assets/c1d76dc9-6aea-4cbb-a779-f0f7d85e71fb)
20
+ > 📌 If you find this useful, **give it a ⭐ on GitHub**
19
21
 
20
- ## Table of Contents
22
+ ## 📋 Table of Contents
21
23
 
22
- - [Introduction](#introduction)
23
- - [Why RubyMCP?](#why-rubymcp)
24
- - [Installation](#installation)
25
- - [Quick Start](#quick-start)
26
- - [Interactive Demo](#interactive-demo)
27
- - [Configuration Options](#configuration-options)
28
- - [Server Endpoints](#server-endpoints)
29
- - [Detailed Usage](#detailed-usage)
24
+ - [🔍 Introduction](#-introduction)
25
+ - [🌟 Why MCP on Ruby?](#-why-mcp-on-ruby)
26
+ - [📦 Installation](#-installation)
27
+ - [🚀 Quick Start](#-quick-start)
28
+ - [🎮 Interactive Demo](#-interactive-demo)
29
+ - [⚙️ Configuration Options](#️-configuration-options)
30
+ - [🛣️ Server Endpoints](#️-server-endpoints)
31
+ - [📚 Detailed Usage](#-detailed-usage)
30
32
  - [Creating a Context](#creating-a-context)
31
33
  - [Adding a Message](#adding-a-message)
32
34
  - [Generating a Response](#generating-a-response)
33
35
  - [Streaming a Response](#streaming-a-response)
34
36
  - [Uploading Content](#uploading-content)
35
37
  - [Using Tool Calls](#using-tool-calls)
36
- - [Rails Integration](#rails-integration)
37
- - [Custom Storage Backend](#custom-storage-backend)
38
- - [Authentication](#authentication)
39
- - [Development](#development)
40
- - [Roadmap](#roadmap)
41
- - [Contributing](#contributing)
42
- - [License](#license)
43
-
44
- ## Why RubyMCP?
45
-
46
- RubyMCP provides a Ruby implementation of the Model Context Protocol:
47
-
48
- - Standard API for multiple LLM providers
49
- - Context management for conversations
50
- - Support for streaming responses
51
- - File handling capabilities
52
- - Tool calling support
53
- - Authentication
54
- - Schema validation using dry-schema
38
+ - [🚄 Rails Integration](#-rails-integration)
39
+ - [💾 Storage Backend](#-storage-backends)
40
+ - [🔒 Authentication](#-authentication)
41
+ - [🛠️ Development](#️-development)
42
+ - [🗺️ Roadmap](#️-roadmap)
43
+ - [👥 Contributing](#-contributing)
44
+ - [📄 License](#-license)
45
+
46
+ ## 🌟 Why MCP on Ruby?
47
+
48
+ **MCP on Ruby** provides a comprehensive implementation of the Model Context Protocol with these features:
49
+
50
+ - **Provider-Ready:** Pre-built adapters for OpenAI and Anthropic - just add your API key
51
+ - **Complete Protocol Implementation:** Fully implements the MCP specification for compatibility
52
+ - **Conversation Management:** Context handling for multi-turn conversations
53
+ - **Flexible Storage:** Extensible storage backends
54
+ - **Streaming Support:** Real-time response streaming for dynamic UIs
55
+ - **File Handling:** Upload and reference files in conversations
56
+ - **Tool Calling:** Support for LLM function calling capabilities
57
+ - **Battle-Tested:** Comprehensive test suite ensures reliability
55
58
 
56
59
  The library is designed to be straightforward to use while maintaining full compatibility with the MCP specification.
57
60
 
58
- ## Installation
61
+ ## 📦 Installation
59
62
 
60
63
  Add this line to your application's Gemfile:
61
64
 
@@ -75,7 +78,7 @@ Or install it yourself as:
75
78
  $ gem install mcp_on_ruby
76
79
  ```
77
80
 
78
- ## Quick Start
81
+ ## 🚀 Quick Start
79
82
 
80
83
  Here's how to get a basic MCP server running:
81
84
 
@@ -92,29 +95,31 @@ end
92
95
 
93
96
  # Start the MCP server
94
97
  server = RubyMCP::Server::Controller.new
95
- server.start # This will block the current thread
98
+ server.start
96
99
  ```
97
100
 
98
- ### Interactive Demo
101
+ ### 🎮 Interactive Demo
99
102
 
100
103
  The repository includes an interactive demo that walks through all the key MCP concepts:
101
104
 
102
- First, start the example server:
103
-
104
105
  ```bash
106
+ # Terminal 1: Start the server
105
107
  cd examples/simple_server
106
108
  ruby server.rb
107
- ```
108
-
109
- Then, in a separate terminal, run the client:
110
109
 
111
- ```bash
110
+ # Terminal 2: Run the client
112
111
  cd examples/simple_server
113
112
  ruby client.rb
113
+
114
+ # ActiveRecord Storage Demo
115
+ # Demonstrates database storage with SQLite
116
+ cd examples/simple_server
117
+ ruby activerecord_demo.rb
114
118
  ```
119
+
115
120
  This demo provides a guided tour of the MCP functionality, showing each step of creating contexts, adding messages, and generating responses with detailed explanations.
116
121
 
117
- ## Configuration Options
122
+ ## ⚙️ Configuration Options
118
123
 
119
124
  RubyMCP offers several configuration options:
120
125
 
@@ -131,9 +136,31 @@ RubyMCP.configure do |config|
131
136
  }
132
137
  }
133
138
 
134
- # Storage backend (:memory, :redis, :active_record, or custom)
139
+ # Storage backend
140
+
141
+ # Option 1: Memory storage (default)
135
142
  config.storage = :memory
136
143
 
144
+ # Option 2: Redis storage
145
+ config.storage = :redis
146
+ config.redis = {
147
+ url: ENV.fetch('REDIS_URL', 'redis://localhost:6379/0'),
148
+ namespace: 'my_app_mcp',
149
+ ttl: 86400 # 1 day in seconds
150
+ }
151
+
152
+ # Option 3: ActiveRecord storage
153
+ config.storage = :active_record
154
+ config.active_record = {
155
+ # Connection settings (not needed in Rails)
156
+ connection: {
157
+ adapter: 'sqlite3',
158
+ database: 'db/mcp.sqlite3'
159
+ },
160
+ # Table prefix to avoid name collisions
161
+ table_prefix: 'mcp_'
162
+ }
163
+
137
164
  # Server settings
138
165
  config.server_port = 3000
139
166
  config.server_host = "0.0.0.0"
@@ -148,9 +175,9 @@ RubyMCP.configure do |config|
148
175
  end
149
176
  ```
150
177
 
151
- ## Server Endpoints
178
+ ## 🛣️ Server Endpoints
152
179
 
153
- The MCP server provides the following endpoints:
180
+ The MCP server provides the following RESTful endpoints:
154
181
 
155
182
  ### Engines
156
183
  - `GET /engines` - List available language models
@@ -172,7 +199,7 @@ The MCP server provides the following endpoints:
172
199
  - `POST /content` - Upload content (files)
173
200
  - `GET /content/:context_id/:id` - Retrieve uploaded content
174
201
 
175
- ## Detailed Usage
202
+ ## 📚 Detailed Usage
176
203
 
177
204
  ### Creating a Context
178
205
 
@@ -316,7 +343,7 @@ if response.body["tool_calls"]
316
343
  end
317
344
  ```
318
345
 
319
- ## Rails Integration
346
+ ## 🚄 Rails Integration
320
347
 
321
348
  For Rails applications, create an initializer at `config/initializers/ruby_mcp.rb`:
322
349
 
@@ -331,7 +358,11 @@ RubyMCP.configure do |config|
331
358
  if Rails.env.development? || Rails.env.test?
332
359
  config.storage = :memory
333
360
  else
334
- config.storage = :memory # Replace with persistent option when implemented
361
+ # Use ActiveRecord for production (uses your Rails database)
362
+ config.storage = :active_record
363
+ config.active_record = {
364
+ table_prefix: "mcp_#{Rails.env}_" # Environment-specific prefix
365
+ }
335
366
  end
336
367
 
337
368
  # Enable authentication in production
@@ -360,8 +391,75 @@ Rails.application.routes.draw do
360
391
  end
361
392
  ```
362
393
 
363
- ## Custom Storage Backend
394
+ ## 💾 Storage Backends
395
+
396
+ ### Redis Storage
397
+
398
+ MCP on Ruby supports Redis as a persistent storage backend:
399
+
400
+ 1. Add the Redis gem to your Gemfile:
401
+ ```ruby
402
+ gem 'redis', '~> 5.0'
403
+ ```
404
+
405
+ 2. Configure Redis storage:
406
+ ```ruby
407
+ RubyMCP.configure do |config|
408
+ config.storage = :redis
409
+ config.redis = {
410
+ url: ENV.fetch('REDIS_URL', 'redis://localhost:6379/0'),
411
+ namespace: "app_mcp_#{Rails.env}",
412
+ ttl: 86400 # 1 day in seconds
413
+ }
414
+ end
415
+ ```
416
+
417
+ 3. Access the configured client:
418
+ ```ruby
419
+ client = RubyMCP.client
420
+ ```
421
+
422
+ For detailed integration examples, see the [[Redis Storage](https://github.com/nagstler/mcp_on_ruby/wiki/Redis-Storage)] wiki page.
423
+
424
+ ### ActiveRecord Storage
425
+
426
+ For integration with Rails or any app needing database storage:
427
+
428
+ ```ruby
429
+ # Add to Gemfile
430
+ gem 'activerecord', '~> 6.1'
431
+ gem 'sqlite3', '~> 1.4' # or pg, mysql2, etc.
432
+
433
+ # Configure RubyMCP
434
+ RubyMCP.configure do |config|
435
+ config.storage = :active_record
436
+ config.active_record = {
437
+ # Connection (not needed in Rails)
438
+ connection: {
439
+ adapter: 'sqlite3',
440
+ database: 'db/mcp.sqlite3'
441
+ },
442
+ # Table prefix to avoid name collisions
443
+ table_prefix: 'mcp_'
444
+ }
445
+ end
446
+ ```
447
+
448
+ In Rails applications, it uses your app's database connection automatically:
449
+
450
+ ```ruby
451
+ # config/initializers/ruby_mcp.rb
452
+ RubyMCP.configure do |config|
453
+ config.storage = :active_record
454
+ config.active_record = {
455
+ table_prefix: "mcp_#{Rails.env}_" # Environment-specific prefix
456
+ }
457
+ end
458
+ ```
459
+
460
+ The ActiveRecord adapter automatically creates the necessary tables with appropriate indexes, and handles different types of data (text, binary, JSON) appropriately.
364
461
 
462
+ ### Custom storage
365
463
  You can implement custom storage backends by extending the base storage class:
366
464
 
367
465
  ```ruby
@@ -409,7 +507,7 @@ RubyMCP.configure do |config|
409
507
  end
410
508
  ```
411
509
 
412
- ## Authentication
510
+ ## 🔒 Authentication
413
511
 
414
512
  To enable JWT authentication:
415
513
 
@@ -446,7 +544,7 @@ conn.get("http://localhost:3000/contexts") do |req|
446
544
  end
447
545
  ```
448
546
 
449
- ## Development
547
+ ## 🛠️ Development
450
548
 
451
549
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
452
550
 
@@ -462,11 +560,12 @@ bundle exec rspec
462
560
  bundle exec ruby examples/simple_server/server.rb
463
561
  ```
464
562
 
465
- ## Roadmap
563
+ ## 🗺️ Roadmap
466
564
 
467
565
  While RubyMCP is functional for basic use cases, there are several areas planned for improvement:
468
566
 
469
- - [ ] Persistent storage backends (Redis, ActiveRecord)
567
+ - [x] Redis persistent storage backend
568
+ - [x] ActiveRecord storage backend
470
569
  - [ ] Complete test coverage, including integration tests
471
570
  - [ ] Improved error handling and recovery strategies
472
571
  - [ ] Rate limiting for provider APIs
@@ -476,7 +575,7 @@ While RubyMCP is functional for basic use cases, there are several areas planned
476
575
 
477
576
  :heart: Contributions in any of these areas are welcome!
478
577
 
479
- ## Contributing
578
+ ## 👥 Contributing
480
579
 
481
580
  1. Fork the repository
482
581
  2. Create your feature branch (`git checkout -b feature/my-new-feature`)
@@ -486,6 +585,6 @@ While RubyMCP is functional for basic use cases, there are several areas planned
486
585
 
487
586
  Bug reports and pull requests are welcome on GitHub at https://github.com/nagstler/mcp_on_ruby.
488
587
 
489
- ## License
588
+ ## 📄 License
490
589
 
491
590
  The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
@@ -0,0 +1,43 @@
1
+ # lib/ruby_mcp/client.rb
2
+ # frozen_string_literal: true
3
+
4
+ module RubyMCP
5
+ class Client
6
+ attr_reader :storage
7
+
8
+ def initialize(storage)
9
+ @storage = storage
10
+ end
11
+
12
+ def create_context(messages = [], metadata = {})
13
+ context = RubyMCP::Models::Context.new(messages: messages, metadata: metadata)
14
+ storage.create_context(context)
15
+ end
16
+
17
+ def list_contexts(limit: 50, offset: 0)
18
+ storage.list_contexts(limit: limit, offset: offset)
19
+ end
20
+
21
+ def get_context(context_id)
22
+ storage.get_context(context_id)
23
+ end
24
+
25
+ def delete_context(context_id)
26
+ storage.delete_context(context_id)
27
+ end
28
+
29
+ def add_message(context_id, role, content, metadata: {})
30
+ message = RubyMCP::Models::Message.new(role: role, content: content, metadata: metadata)
31
+ storage.add_message(context_id, message)
32
+ end
33
+
34
+ def add_content(context_id, content_data, content_id = nil)
35
+ content_id ||= "cnt_#{SecureRandom.hex(10)}"
36
+ storage.add_content(context_id, content_id, content_data)
37
+ end
38
+
39
+ def get_content(context_id, content_id)
40
+ storage.get_content(context_id, content_id)
41
+ end
42
+ end
43
+ end
@@ -3,7 +3,8 @@
3
3
  module RubyMCP
4
4
  class Configuration
5
5
  attr_accessor :providers, :storage, :server_port, :server_host,
6
- :auth_required, :jwt_secret, :token_expiry, :max_contexts
6
+ :auth_required, :jwt_secret, :token_expiry, :max_contexts,
7
+ :redis, :active_record
7
8
 
8
9
  def initialize
9
10
  @providers = {}
@@ -14,6 +15,28 @@ module RubyMCP
14
15
  @jwt_secret = nil
15
16
  @token_expiry = 3600 # 1 hour
16
17
  @max_contexts = 1000
18
+ @redis = {} # Default empty Redis config
19
+ @active_record = {} # Default empty ActiveRecord config
20
+ end
21
+
22
+ def storage_config
23
+ case @storage
24
+ when :redis
25
+ {
26
+ type: :redis,
27
+ connection: redis_connection_config,
28
+ namespace: @redis[:namespace] || 'ruby_mcp',
29
+ ttl: @redis[:ttl] || 86_400
30
+ }
31
+ when :active_record
32
+ {
33
+ type: :active_record,
34
+ connection: @active_record[:connection],
35
+ table_prefix: @active_record[:table_prefix] || 'mcp_'
36
+ }
37
+ else
38
+ { type: @storage }
39
+ end
17
40
  end
18
41
 
19
42
  def storage_instance
@@ -21,19 +44,47 @@ module RubyMCP
21
44
  when :memory
22
45
  RubyMCP::Storage::Memory.new
23
46
  when :redis
24
- # Future implementation
25
- raise RubyMCP::Errors::ConfigurationError, 'Redis storage not yet implemented'
47
+ begin
48
+ require 'redis'
49
+ require_relative 'storage/redis'
50
+ RubyMCP::Storage::Redis.new(storage_config)
51
+ rescue LoadError
52
+ raise RubyMCP::Errors::ConfigurationError,
53
+ "Redis storage requires the redis gem. Add it to your Gemfile with:
54
+ gem 'redis', '~> 5.0'"
55
+ end
26
56
  when :active_record
27
- # Future implementation
28
- raise RubyMCP::Errors::ConfigurationError, 'ActiveRecord storage not yet implemented'
57
+ begin
58
+ require 'active_record'
59
+ require_relative 'storage/active_record'
60
+ RubyMCP::Storage::ActiveRecord.new(storage_config)
61
+ rescue LoadError
62
+ raise RubyMCP::Errors::ConfigurationError,
63
+ "ActiveRecord storage requires the activerecord gem. Add it to your Gemfile with:
64
+ gem 'activerecord', '~> 6.0'"
65
+ end
29
66
  else
30
67
  unless @storage.is_a?(RubyMCP::Storage::Base)
31
68
  raise RubyMCP::Errors::ConfigurationError, "Unknown storage type: #{@storage}"
32
69
  end
33
70
 
34
71
  @storage # Allow custom storage instance
35
-
36
72
  end
37
73
  end
74
+
75
+ private
76
+
77
+ def redis_connection_config
78
+ if @redis[:url]
79
+ { url: @redis[:url] }
80
+ else
81
+ {
82
+ host: @redis[:host] || 'localhost',
83
+ port: @redis[:port] || 6379,
84
+ db: @redis[:db] || 0,
85
+ password: @redis[:password]
86
+ }.compact
87
+ end
88
+ end
38
89
  end
39
90
  end
@@ -37,6 +37,7 @@ module RubyMCP
37
37
  {
38
38
  id: @id,
39
39
  messages: @messages.map(&:to_h),
40
+ content_map: @content_map,
40
41
  created_at: @created_at.iso8601,
41
42
  updated_at: @updated_at.iso8601,
42
43
  metadata: @metadata
@@ -53,10 +53,14 @@ module RubyMCP
53
53
  end
54
54
 
55
55
  def destroy
56
- context = storage.delete_context(params[:id])
57
- ok(context.to_h)
58
- rescue RubyMCP::Errors::ContextError => e
59
- not_found(e.message)
56
+ context_id = params[:id]
57
+
58
+ begin
59
+ storage.delete_context(context_id)
60
+ ok({ success: true })
61
+ rescue RubyMCP::Errors::ContextError => e
62
+ not_found("Context not found: #{e.message}")
63
+ end
60
64
  end
61
65
  end
62
66
  end