mcp_on_ruby 0.3.0 โ 1.0.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 +4 -4
- data/CHANGELOG.md +56 -28
- data/CODE_OF_CONDUCT.md +30 -58
- data/CONTRIBUTING.md +61 -67
- data/LICENSE.txt +2 -2
- data/README.md +159 -509
- data/bin/console +11 -0
- data/bin/setup +6 -0
- data/docs/advanced-usage.md +132 -0
- data/docs/api-reference.md +35 -0
- data/docs/testing.md +55 -0
- data/examples/claude/README.md +171 -0
- data/examples/claude/claude-bridge.js +122 -0
- data/lib/mcp_on_ruby/configuration.rb +74 -0
- data/lib/mcp_on_ruby/errors.rb +137 -0
- data/lib/mcp_on_ruby/generators/install_generator.rb +46 -0
- data/lib/mcp_on_ruby/generators/resource_generator.rb +63 -0
- data/lib/mcp_on_ruby/generators/templates/README +31 -0
- data/lib/mcp_on_ruby/generators/templates/application_resource.rb +20 -0
- data/lib/mcp_on_ruby/generators/templates/application_tool.rb +18 -0
- data/lib/mcp_on_ruby/generators/templates/initializer.rb +41 -0
- data/lib/mcp_on_ruby/generators/templates/resource.rb +50 -0
- data/lib/mcp_on_ruby/generators/templates/resource_spec.rb +67 -0
- data/lib/mcp_on_ruby/generators/templates/sample_resource.rb +57 -0
- data/lib/mcp_on_ruby/generators/templates/sample_tool.rb +59 -0
- data/lib/mcp_on_ruby/generators/templates/tool.rb +38 -0
- data/lib/mcp_on_ruby/generators/templates/tool_spec.rb +55 -0
- data/lib/mcp_on_ruby/generators/tool_generator.rb +51 -0
- data/lib/mcp_on_ruby/railtie.rb +108 -0
- data/lib/mcp_on_ruby/resource.rb +161 -0
- data/lib/mcp_on_ruby/server.rb +378 -0
- data/lib/mcp_on_ruby/tool.rb +134 -0
- data/lib/mcp_on_ruby/transport.rb +330 -0
- data/lib/mcp_on_ruby/version.rb +6 -0
- data/lib/mcp_on_ruby.rb +142 -0
- metadata +62 -173
- data/lib/ruby_mcp/client.rb +0 -43
- data/lib/ruby_mcp/configuration.rb +0 -90
- data/lib/ruby_mcp/errors.rb +0 -17
- data/lib/ruby_mcp/models/context.rb +0 -52
- data/lib/ruby_mcp/models/engine.rb +0 -31
- data/lib/ruby_mcp/models/message.rb +0 -60
- data/lib/ruby_mcp/providers/anthropic.rb +0 -269
- data/lib/ruby_mcp/providers/base.rb +0 -57
- data/lib/ruby_mcp/providers/openai.rb +0 -265
- data/lib/ruby_mcp/schemas.rb +0 -56
- data/lib/ruby_mcp/server/app.rb +0 -84
- data/lib/ruby_mcp/server/base_controller.rb +0 -49
- data/lib/ruby_mcp/server/content_controller.rb +0 -68
- data/lib/ruby_mcp/server/contexts_controller.rb +0 -67
- data/lib/ruby_mcp/server/controller.rb +0 -29
- data/lib/ruby_mcp/server/engines_controller.rb +0 -34
- data/lib/ruby_mcp/server/generate_controller.rb +0 -140
- data/lib/ruby_mcp/server/messages_controller.rb +0 -30
- data/lib/ruby_mcp/server/router.rb +0 -84
- data/lib/ruby_mcp/storage/active_record.rb +0 -414
- data/lib/ruby_mcp/storage/base.rb +0 -43
- data/lib/ruby_mcp/storage/error.rb +0 -8
- data/lib/ruby_mcp/storage/memory.rb +0 -69
- data/lib/ruby_mcp/storage/redis.rb +0 -197
- data/lib/ruby_mcp/storage_factory.rb +0 -43
- data/lib/ruby_mcp/validator.rb +0 -45
- data/lib/ruby_mcp/version.rb +0 -6
- data/lib/ruby_mcp.rb +0 -71
data/README.md
CHANGED
@@ -1,590 +1,240 @@
|
|
1
|
+
# MCP on Ruby
|
2
|
+
|
1
3
|
<div align="center">
|
2
4
|
|
3
|
-
# MCP on Ruby
|
4
5
|
[](https://badge.fury.io/rb/mcp_on_ruby)
|
5
|
-
[](https://github.com/nagstler/ruby_mcp/actions/workflows/build.yml)
|
6
6
|
[](https://opensource.org/licenses/MIT)
|
7
|
-
[](https://github.com/nagstler/ruby_mcp/actions/workflows/test.yml)
|
9
|
-
[](https://codecov.io/github/nagstler/ruby_mcp)
|
10
|
-
|
11
|
-
<strong> **Turn your Rails APIs into an MCP server.**</strong>
|
12
|
-
|
13
|
-
</div>
|
14
|
-
|
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.
|
17
|
-
|
18
|
-

|
7
|
+
[](https://www.ruby-lang.org/)
|
19
8
|
|
20
|
-
|
9
|
+
**Model Context Protocol (MCP) server for Rails applications**
|
21
10
|
|
22
|
-
|
11
|
+
Expose your Rails app as an AI accessible interface โ define tools and resources the Rails way.
|
23
12
|
|
24
|
-
|
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)
|
32
|
-
- [Creating a Context](#creating-a-context)
|
33
|
-
- [Adding a Message](#adding-a-message)
|
34
|
-
- [Generating a Response](#generating-a-response)
|
35
|
-
- [Streaming a Response](#streaming-a-response)
|
36
|
-
- [Uploading Content](#uploading-content)
|
37
|
-
- [Using Tool Calls](#using-tool-calls)
|
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)
|
13
|
+
[Documentation](https://rubydoc.info/gems/mcp_on_ruby) | [Contributing](#contributing)
|
45
14
|
|
46
|
-
|
15
|
+
</div>
|
47
16
|
|
48
|
-
|
17
|
+
---
|
49
18
|
|
50
|
-
|
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
|
19
|
+
## Features
|
58
20
|
|
59
|
-
|
21
|
+
๐ **Production-Ready** - Authentication, rate limiting, error handling, security
|
22
|
+
๐ง **Rails Integration** - Generators, autoloading, middleware, Railtie
|
23
|
+
๐ ๏ธ **Tools System** - Callable functions with JSON Schema validation
|
24
|
+
๐ **Resources System** - Data exposure with URI templating
|
25
|
+
๐ **Security** - DNS rebinding protection, CORS, token authentication
|
26
|
+
โก **Real-time** - Server Events (SSE) foundation (full implementation coming soon)
|
27
|
+
๐ฏ **Developer-Friendly** - Clean DSL, generators, testing support
|
60
28
|
|
61
|
-
##
|
29
|
+
## Installation
|
62
30
|
|
63
|
-
Add
|
31
|
+
Add to your `Gemfile`:
|
64
32
|
|
65
33
|
```ruby
|
66
34
|
gem 'mcp_on_ruby'
|
67
35
|
```
|
68
36
|
|
69
|
-
|
70
|
-
|
71
|
-
```
|
72
|
-
$ bundle install
|
73
|
-
```
|
74
|
-
|
75
|
-
Or install it yourself as:
|
76
|
-
|
77
|
-
```
|
78
|
-
$ gem install mcp_on_ruby
|
79
|
-
```
|
80
|
-
|
81
|
-
## ๐ Quick Start
|
82
|
-
|
83
|
-
Here's how to get a basic MCP server running:
|
84
|
-
|
85
|
-
```ruby
|
86
|
-
require 'ruby_mcp'
|
87
|
-
|
88
|
-
# Configure RubyMCP
|
89
|
-
RubyMCP.configure do |config|
|
90
|
-
config.providers = {
|
91
|
-
openai: { api_key: ENV['OPENAI_API_KEY'] },
|
92
|
-
anthropic: { api_key: ENV['ANTHROPIC_API_KEY'] }
|
93
|
-
}
|
94
|
-
end
|
95
|
-
|
96
|
-
# Start the MCP server
|
97
|
-
server = RubyMCP::Server::Controller.new
|
98
|
-
server.start
|
99
|
-
```
|
100
|
-
|
101
|
-
### ๐ฎ Interactive Demo
|
102
|
-
|
103
|
-
The repository includes an interactive demo that walks through all the key MCP concepts:
|
37
|
+
Then run:
|
104
38
|
|
105
39
|
```bash
|
106
|
-
|
107
|
-
|
108
|
-
ruby server.rb
|
109
|
-
|
110
|
-
# Terminal 2: Run the client
|
111
|
-
cd examples/simple_server
|
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
|
40
|
+
bundle install
|
41
|
+
rails generate mcp_on_ruby:install
|
118
42
|
```
|
119
43
|
|
120
|
-
|
44
|
+
## Quick Start
|
121
45
|
|
122
|
-
|
46
|
+
### 1. Install and Configure
|
123
47
|
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
RubyMCP.configure do |config|
|
128
|
-
# LLM Provider configurations
|
129
|
-
config.providers = {
|
130
|
-
openai: {
|
131
|
-
api_key: ENV['OPENAI_API_KEY'],
|
132
|
-
api_base: 'https://api.openai.com/v1' # Optional
|
133
|
-
},
|
134
|
-
anthropic: {
|
135
|
-
api_key: ENV['ANTHROPIC_API_KEY']
|
136
|
-
}
|
137
|
-
}
|
138
|
-
|
139
|
-
# Storage backend
|
140
|
-
|
141
|
-
# Option 1: Memory storage (default)
|
142
|
-
config.storage = :memory
|
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
|
-
|
164
|
-
# Server settings
|
165
|
-
config.server_port = 3000
|
166
|
-
config.server_host = "0.0.0.0"
|
167
|
-
|
168
|
-
# Authentication settings
|
169
|
-
config.auth_required = false
|
170
|
-
config.jwt_secret = ENV['JWT_SECRET']
|
171
|
-
config.token_expiry = 3600 # 1 hour
|
172
|
-
|
173
|
-
# Limits
|
174
|
-
config.max_contexts = 1000
|
175
|
-
end
|
176
|
-
```
|
177
|
-
|
178
|
-
## ๐ฃ๏ธ Server Endpoints
|
179
|
-
|
180
|
-
The MCP server provides the following RESTful endpoints:
|
181
|
-
|
182
|
-
### Engines
|
183
|
-
- `GET /engines` - List available language models
|
184
|
-
|
185
|
-
### Contexts
|
186
|
-
- `POST /contexts` - Create a new conversation context
|
187
|
-
- `GET /contexts` - List existing contexts
|
188
|
-
- `GET /contexts/:id` - Get details of a specific context
|
189
|
-
- `DELETE /contexts/:id` - Delete a context
|
190
|
-
|
191
|
-
### Messages
|
192
|
-
- `POST /messages` - Add a message to a context
|
193
|
-
|
194
|
-
### Generation
|
195
|
-
- `POST /generate` - Generate a response from a language model
|
196
|
-
- `POST /generate/stream` - Stream a response with incremental updates
|
197
|
-
|
198
|
-
### Content
|
199
|
-
- `POST /content` - Upload content (files)
|
200
|
-
- `GET /content/:context_id/:id` - Retrieve uploaded content
|
201
|
-
|
202
|
-
## ๐ Detailed Usage
|
203
|
-
|
204
|
-
### Creating a Context
|
205
|
-
|
206
|
-
```ruby
|
207
|
-
# Using the HTTP API
|
208
|
-
response = Faraday.post(
|
209
|
-
"http://localhost:3000/contexts",
|
210
|
-
{
|
211
|
-
messages: [
|
212
|
-
{
|
213
|
-
role: "system",
|
214
|
-
content: "You are a helpful assistant."
|
215
|
-
}
|
216
|
-
],
|
217
|
-
metadata: {
|
218
|
-
user_id: "user_123",
|
219
|
-
conversation_name: "Technical Support"
|
220
|
-
}
|
221
|
-
}.to_json,
|
222
|
-
"Content-Type" => "application/json"
|
223
|
-
)
|
224
|
-
|
225
|
-
context_id = JSON.parse(response.body)["id"]
|
226
|
-
```
|
227
|
-
|
228
|
-
### Adding a Message
|
229
|
-
|
230
|
-
```ruby
|
231
|
-
Faraday.post(
|
232
|
-
"http://localhost:3000/messages",
|
233
|
-
{
|
234
|
-
context_id: context_id,
|
235
|
-
role: "user",
|
236
|
-
content: "What is the capital of France?"
|
237
|
-
}.to_json,
|
238
|
-
"Content-Type" => "application/json"
|
239
|
-
)
|
240
|
-
```
|
48
|
+
```bash
|
49
|
+
# Generate MCP server files
|
50
|
+
rails generate mcp_on_ruby:install
|
241
51
|
|
242
|
-
|
52
|
+
# Create a tool
|
53
|
+
rails generate mcp_on_ruby:tool UserManager --description "Manage application users"
|
243
54
|
|
244
|
-
|
245
|
-
|
246
|
-
"http://localhost:3000/generate",
|
247
|
-
{
|
248
|
-
context_id: context_id,
|
249
|
-
engine_id: "anthropic/claude-3-sonnet-20240229",
|
250
|
-
max_tokens: 1000,
|
251
|
-
temperature: 0.7
|
252
|
-
}.to_json,
|
253
|
-
"Content-Type" => "application/json"
|
254
|
-
)
|
255
|
-
|
256
|
-
assistant_response = JSON.parse(response.body)["content"]
|
55
|
+
# Create a resource
|
56
|
+
rails generate mcp_on_ruby:resource UserStats --uri "users/{id}/stats" --template
|
257
57
|
```
|
258
58
|
|
259
|
-
###
|
59
|
+
### 2. Configure MCP Server
|
260
60
|
|
261
61
|
```ruby
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
62
|
+
# config/initializers/mcp_on_ruby.rb
|
63
|
+
McpOnRuby.configure do |config|
|
64
|
+
config.authentication_required = true
|
65
|
+
config.authentication_token = ENV['MCP_AUTH_TOKEN']
|
66
|
+
config.rate_limit_per_minute = 60
|
67
|
+
config.allowed_origins = [/\.yourdomain\.com$/]
|
266
68
|
end
|
267
69
|
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
engine_id: "openai/gpt-4",
|
273
|
-
temperature: 0.7
|
274
|
-
}.to_json
|
275
|
-
|
276
|
-
req.options.on_data = Proc.new do |chunk, size, total|
|
277
|
-
event_data = chunk.split("data: ").last.strip
|
278
|
-
next if event_data.empty? || event_data == "[DONE]"
|
279
|
-
|
280
|
-
event = JSON.parse(event_data)
|
281
|
-
if event["event"] == "generation.content" && event["content"]
|
282
|
-
print event["content"]
|
283
|
-
end
|
284
|
-
end
|
70
|
+
Rails.application.configure do
|
71
|
+
config.mcp.enabled = true
|
72
|
+
config.mcp.auto_register_tools = true
|
73
|
+
config.mcp.auto_register_resources = true
|
285
74
|
end
|
286
75
|
```
|
287
76
|
|
288
|
-
###
|
77
|
+
### 3. Create Tools
|
289
78
|
|
290
79
|
```ruby
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
content_type: "application/pdf",
|
300
|
-
file_data: file_data
|
301
|
-
}.to_json,
|
302
|
-
"Content-Type" => "application/json"
|
303
|
-
)
|
304
|
-
```
|
305
|
-
|
306
|
-
### Using Tool Calls
|
307
|
-
|
308
|
-
```ruby
|
309
|
-
tools = [
|
310
|
-
{
|
311
|
-
type: "function",
|
312
|
-
function: {
|
313
|
-
name: "get_weather",
|
314
|
-
description: "Get the current weather for a location",
|
315
|
-
parameters: {
|
316
|
-
type: "object",
|
80
|
+
# app/tools/user_manager_tool.rb
|
81
|
+
class UserManagerTool < ApplicationTool
|
82
|
+
def initialize
|
83
|
+
super(
|
84
|
+
name: 'user_manager',
|
85
|
+
description: 'Manage application users',
|
86
|
+
input_schema: {
|
87
|
+
type: 'object',
|
317
88
|
properties: {
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
}
|
89
|
+
action: { type: 'string', enum: ['create', 'update', 'delete'] },
|
90
|
+
user_id: { type: 'integer' },
|
91
|
+
attributes: { type: 'object' }
|
322
92
|
},
|
323
|
-
required: [
|
93
|
+
required: ['action']
|
324
94
|
}
|
325
|
-
|
326
|
-
|
327
|
-
]
|
328
|
-
|
329
|
-
response = Faraday.post(
|
330
|
-
"http://localhost:3000/generate",
|
331
|
-
{
|
332
|
-
context_id: context_id,
|
333
|
-
engine_id: "openai/gpt-4",
|
334
|
-
tools: tools
|
335
|
-
}.to_json,
|
336
|
-
"Content-Type" => "application/json"
|
337
|
-
)
|
338
|
-
|
339
|
-
if response.body["tool_calls"]
|
340
|
-
# Handle tool calls
|
341
|
-
tool_calls = response.body["tool_calls"]
|
342
|
-
# Process tool calls and add tool response message
|
343
|
-
end
|
344
|
-
```
|
345
|
-
|
346
|
-
## ๐ Rails Integration
|
347
|
-
|
348
|
-
For Rails applications, create an initializer at `config/initializers/ruby_mcp.rb`:
|
95
|
+
)
|
96
|
+
end
|
349
97
|
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
table_prefix: "mcp_#{Rails.env}_" # Environment-specific prefix
|
365
|
-
}
|
98
|
+
protected
|
99
|
+
|
100
|
+
def execute(arguments, context)
|
101
|
+
case arguments['action']
|
102
|
+
when 'create'
|
103
|
+
user = User.create!(arguments['attributes'])
|
104
|
+
{ success: true, user: user.as_json }
|
105
|
+
when 'update'
|
106
|
+
user = User.find(arguments['user_id'])
|
107
|
+
user.update!(arguments['attributes'])
|
108
|
+
{ success: true, user: user.as_json }
|
109
|
+
else
|
110
|
+
{ error: 'Unsupported action' }
|
111
|
+
end
|
366
112
|
end
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
config.jwt_secret = ENV["JWT_SECRET"]
|
113
|
+
|
114
|
+
def authorize(context)
|
115
|
+
# Add your authorization logic
|
116
|
+
context[:authenticated] == true
|
372
117
|
end
|
373
118
|
end
|
374
119
|
```
|
375
120
|
|
376
|
-
|
121
|
+
### 4. Create Resources
|
377
122
|
|
378
123
|
```ruby
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
124
|
+
# app/resources/user_stats_resource.rb
|
125
|
+
class UserStatsResource < ApplicationResource
|
126
|
+
def initialize
|
127
|
+
super(
|
128
|
+
uri: 'users/{id}/stats',
|
129
|
+
name: 'User Statistics',
|
130
|
+
description: 'Get detailed user statistics',
|
131
|
+
mime_type: 'application/json'
|
132
|
+
)
|
385
133
|
end
|
386
|
-
|
387
|
-
mount RubyMCP::Server::App.new.rack_app, at: mount_mcp_at
|
388
|
-
|
389
|
-
# Rest of your routes
|
390
|
-
# ...
|
391
|
-
end
|
392
|
-
```
|
393
|
-
|
394
|
-
## ๐พ Storage Backends
|
395
|
-
|
396
|
-
### Redis Storage
|
397
134
|
|
398
|
-
|
135
|
+
protected
|
399
136
|
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
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:
|
137
|
+
def fetch_content(params, context)
|
138
|
+
user = User.find(params['id'])
|
139
|
+
|
140
|
+
{
|
141
|
+
user_id: user.id,
|
142
|
+
statistics: {
|
143
|
+
posts_count: user.posts.count,
|
144
|
+
comments_count: user.comments.count,
|
145
|
+
last_login: user.last_login_at,
|
146
|
+
account_created: user.created_at
|
147
|
+
},
|
148
|
+
generated_at: Time.current.iso8601
|
149
|
+
}
|
150
|
+
end
|
427
151
|
|
428
|
-
|
429
|
-
#
|
430
|
-
|
431
|
-
|
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
|
-
}
|
152
|
+
def authorize(context)
|
153
|
+
# Check if user can access this data
|
154
|
+
context[:authenticated] == true
|
155
|
+
end
|
445
156
|
end
|
446
157
|
```
|
447
158
|
|
448
|
-
|
159
|
+
### 5. Start Your Server
|
449
160
|
|
450
|
-
```
|
451
|
-
|
452
|
-
|
453
|
-
config.storage = :active_record
|
454
|
-
config.active_record = {
|
455
|
-
table_prefix: "mcp_#{Rails.env}_" # Environment-specific prefix
|
456
|
-
}
|
457
|
-
end
|
161
|
+
```bash
|
162
|
+
rails server
|
163
|
+
# MCP server available at http://localhost:3000/mcp
|
458
164
|
```
|
459
165
|
|
460
|
-
|
461
|
-
|
462
|
-
### Custom storage
|
463
|
-
You can implement custom storage backends by extending the base storage class:
|
166
|
+
## Architecture
|
464
167
|
|
465
|
-
```ruby
|
466
|
-
class RedisStorage < RubyMCP::Storage::Base
|
467
|
-
def initialize(options = {})
|
468
|
-
super
|
469
|
-
@redis = Redis.new(options)
|
470
|
-
end
|
471
|
-
|
472
|
-
def create_context(context)
|
473
|
-
@redis.set("context:#{context.id}", JSON.dump(context.to_h))
|
474
|
-
context
|
475
|
-
end
|
476
|
-
|
477
|
-
def get_context(context_id)
|
478
|
-
data = @redis.get("context:#{context_id}")
|
479
|
-
raise RubyMCP::Errors::ContextError, "Context not found: #{context_id}" unless data
|
480
|
-
|
481
|
-
hash = JSON.parse(data, symbolize_names: true)
|
482
|
-
|
483
|
-
# Create message objects
|
484
|
-
messages = hash[:messages].map do |msg|
|
485
|
-
RubyMCP::Models::Message.new(
|
486
|
-
role: msg[:role],
|
487
|
-
content: msg[:content],
|
488
|
-
id: msg[:id],
|
489
|
-
metadata: msg[:metadata]
|
490
|
-
)
|
491
|
-
end
|
492
|
-
|
493
|
-
# Create the context
|
494
|
-
RubyMCP::Models::Context.new(
|
495
|
-
id: hash[:id],
|
496
|
-
messages: messages,
|
497
|
-
metadata: hash[:metadata]
|
498
|
-
)
|
499
|
-
end
|
500
|
-
|
501
|
-
# Implement other required methods...
|
502
|
-
end
|
503
|
-
|
504
|
-
# Configure RubyMCP to use your custom storage
|
505
|
-
RubyMCP.configure do |config|
|
506
|
-
config.storage = RedisStorage.new(url: ENV["REDIS_URL"])
|
507
|
-
end
|
508
168
|
```
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
169
|
+
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
170
|
+
โ Rails App โ
|
171
|
+
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
|
172
|
+
โ app/tools/ โ app/resources/ โ
|
173
|
+
โ โโโ application_tool.rb โโโ application_resource.rb โ
|
174
|
+
โ โโโ user_manager_tool.rb โโโ user_stats_resource.rb โ
|
175
|
+
โ โโโ ... โโโ ... โ
|
176
|
+
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
|
177
|
+
โ MCP Server Core โ
|
178
|
+
โ โโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโ โ
|
179
|
+
โ โ Tools โ โ Resources โ โ Transport โ โ
|
180
|
+
โ โ - Validation โ โ - Templating โ โ - HTTP โ โ
|
181
|
+
โ โ - Authorizationโ โ - Authorizationโ โ - SSE โ โ
|
182
|
+
โ โ - Execution โ โ - Content โ โ - Security โ โ
|
183
|
+
โ โโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโ โ
|
184
|
+
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
|
185
|
+
โ JSON-RPC Protocol โ
|
186
|
+
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
520
187
|
```
|
521
188
|
|
522
|
-
|
189
|
+
## Examples
|
523
190
|
|
524
|
-
|
525
|
-
# Generate a token
|
526
|
-
require 'jwt'
|
191
|
+
Connect your Rails MCP server with different AI clients:
|
527
192
|
|
528
|
-
|
529
|
-
sub: "user_123",
|
530
|
-
exp: Time.now.to_i + 3600
|
531
|
-
}
|
193
|
+
๐ **[Claude Desktop](examples/claude/)** - Complete setup guide with bridge script
|
532
194
|
|
533
|
-
|
195
|
+
## Documentation
|
534
196
|
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
f.response :json
|
539
|
-
f.adapter :net_http
|
540
|
-
end
|
541
|
-
|
542
|
-
conn.get("http://localhost:3000/contexts") do |req|
|
543
|
-
req.headers["Authorization"] = "Bearer #{token}"
|
544
|
-
end
|
545
|
-
```
|
197
|
+
๐ **[Advanced Usage](docs/advanced-usage.md)** - Custom authorization, caching, manual configuration
|
198
|
+
๐ **[Testing Guide](docs/testing.md)** - RSpec integration and testing patterns
|
199
|
+
๐ **[API Reference](docs/api-reference.md)** - Complete API documentation
|
546
200
|
|
547
|
-
## ๐ ๏ธ Development
|
548
201
|
|
549
|
-
|
202
|
+
## Requirements
|
550
203
|
|
551
|
-
|
204
|
+
- Ruby 2.7.0 or higher
|
205
|
+
- Rails 6.0 or higher (for full integration)
|
206
|
+
- JSON Schema validation support
|
552
207
|
|
553
|
-
|
554
|
-
bundle exec rspec
|
555
|
-
```
|
208
|
+
## Dependencies
|
556
209
|
|
557
|
-
|
210
|
+
Production dependencies (minimal footprint):
|
211
|
+
- `json-schema` (~> 3.0) - JSON Schema validation
|
212
|
+
- `rack` (~> 2.2) - HTTP transport layer
|
213
|
+
- `webrick` (~> 1.7) - HTTP server
|
558
214
|
|
559
|
-
|
560
|
-
bundle exec ruby examples/simple_server/server.rb
|
561
|
-
```
|
215
|
+
## Contributing
|
562
216
|
|
563
|
-
|
217
|
+
1. Fork the repository
|
218
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
219
|
+
3. Write tests for your changes
|
220
|
+
4. Ensure all tests pass (`bundle exec rspec`)
|
221
|
+
5. Commit your changes (`git commit -am 'Add some feature'`)
|
222
|
+
6. Push to the branch (`git push origin my-new-feature`)
|
223
|
+
7. Create a Pull Request
|
564
224
|
|
565
|
-
|
225
|
+
## License
|
566
226
|
|
567
|
-
- [
|
568
|
-
- [x] ActiveRecord storage backend
|
569
|
-
- [ ] Complete test coverage, including integration tests
|
570
|
-
- [ ] Improved error handling and recovery strategies
|
571
|
-
- [ ] Rate limiting for provider APIs
|
572
|
-
- [ ] Proper tokenization for context window management
|
573
|
-
- [ ] More robust streaming implementation
|
574
|
-
- [ ] Additional provider integrations
|
227
|
+
This project is licensed under the MIT License - see the [LICENSE](LICENSE.txt) file for details.
|
575
228
|
|
576
|
-
|
229
|
+
## ๐ Acknowledgments
|
577
230
|
|
578
|
-
|
231
|
+
- The [Model Context Protocol](https://modelcontextprotocol.io) team at Anthropic for creating the specification
|
232
|
+
- The Ruby on Rails community for inspiration and conventions
|
579
233
|
|
580
|
-
|
581
|
-
2. Create your feature branch (`git checkout -b feature/my-new-feature`)
|
582
|
-
3. Commit your changes (`git commit -am 'Add some feature'`)
|
583
|
-
4. Push to the branch (`git push origin feature/my-new-feature`)
|
584
|
-
5. Create a new Pull Request
|
234
|
+
---
|
585
235
|
|
586
|
-
|
236
|
+
<div align="center">
|
587
237
|
|
588
|
-
|
238
|
+
Made with โค๏ธ for the Ruby community
|
589
239
|
|
590
|
-
|
240
|
+
</div>
|