mcp_on_ruby 0.2.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.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +59 -16
  3. data/CODE_OF_CONDUCT.md +30 -58
  4. data/CONTRIBUTING.md +61 -67
  5. data/LICENSE.txt +2 -2
  6. data/README.md +160 -442
  7. data/bin/console +11 -0
  8. data/bin/setup +6 -0
  9. data/docs/advanced-usage.md +132 -0
  10. data/docs/api-reference.md +35 -0
  11. data/docs/testing.md +55 -0
  12. data/examples/claude/README.md +171 -0
  13. data/examples/claude/claude-bridge.js +122 -0
  14. data/lib/mcp_on_ruby/configuration.rb +74 -0
  15. data/lib/mcp_on_ruby/errors.rb +137 -0
  16. data/lib/mcp_on_ruby/generators/install_generator.rb +46 -0
  17. data/lib/mcp_on_ruby/generators/resource_generator.rb +63 -0
  18. data/lib/mcp_on_ruby/generators/templates/README +31 -0
  19. data/lib/mcp_on_ruby/generators/templates/application_resource.rb +20 -0
  20. data/lib/mcp_on_ruby/generators/templates/application_tool.rb +18 -0
  21. data/lib/mcp_on_ruby/generators/templates/initializer.rb +41 -0
  22. data/lib/mcp_on_ruby/generators/templates/resource.rb +50 -0
  23. data/lib/mcp_on_ruby/generators/templates/resource_spec.rb +67 -0
  24. data/lib/mcp_on_ruby/generators/templates/sample_resource.rb +57 -0
  25. data/lib/mcp_on_ruby/generators/templates/sample_tool.rb +59 -0
  26. data/lib/mcp_on_ruby/generators/templates/tool.rb +38 -0
  27. data/lib/mcp_on_ruby/generators/templates/tool_spec.rb +55 -0
  28. data/lib/mcp_on_ruby/generators/tool_generator.rb +51 -0
  29. data/lib/mcp_on_ruby/railtie.rb +108 -0
  30. data/lib/mcp_on_ruby/resource.rb +161 -0
  31. data/lib/mcp_on_ruby/server.rb +378 -0
  32. data/lib/mcp_on_ruby/tool.rb +134 -0
  33. data/lib/mcp_on_ruby/transport.rb +330 -0
  34. data/lib/mcp_on_ruby/version.rb +6 -0
  35. data/lib/mcp_on_ruby.rb +142 -0
  36. metadata +64 -146
  37. data/lib/ruby_mcp/client.rb +0 -15
  38. data/lib/ruby_mcp/configuration.rb +0 -69
  39. data/lib/ruby_mcp/errors.rb +0 -17
  40. data/lib/ruby_mcp/models/context.rb +0 -51
  41. data/lib/ruby_mcp/models/engine.rb +0 -31
  42. data/lib/ruby_mcp/models/message.rb +0 -60
  43. data/lib/ruby_mcp/providers/anthropic.rb +0 -269
  44. data/lib/ruby_mcp/providers/base.rb +0 -57
  45. data/lib/ruby_mcp/providers/openai.rb +0 -265
  46. data/lib/ruby_mcp/schemas.rb +0 -56
  47. data/lib/ruby_mcp/server/app.rb +0 -84
  48. data/lib/ruby_mcp/server/base_controller.rb +0 -49
  49. data/lib/ruby_mcp/server/content_controller.rb +0 -68
  50. data/lib/ruby_mcp/server/contexts_controller.rb +0 -63
  51. data/lib/ruby_mcp/server/controller.rb +0 -29
  52. data/lib/ruby_mcp/server/engines_controller.rb +0 -34
  53. data/lib/ruby_mcp/server/generate_controller.rb +0 -140
  54. data/lib/ruby_mcp/server/messages_controller.rb +0 -30
  55. data/lib/ruby_mcp/server/router.rb +0 -84
  56. data/lib/ruby_mcp/storage/base.rb +0 -43
  57. data/lib/ruby_mcp/storage/error.rb +0 -8
  58. data/lib/ruby_mcp/storage/memory.rb +0 -69
  59. data/lib/ruby_mcp/storage/redis.rb +0 -197
  60. data/lib/ruby_mcp/storage_factory.rb +0 -32
  61. data/lib/ruby_mcp/validator.rb +0 -45
  62. data/lib/ruby_mcp/version.rb +0 -6
  63. data/lib/ruby_mcp.rb +0 -68
data/README.md CHANGED
@@ -1,522 +1,240 @@
1
+ # MCP on Ruby
2
+
1
3
  <div align="center">
2
4
 
3
- # MCP on Ruby
4
5
  [![Gem Version](https://badge.fury.io/rb/mcp_on_ruby.svg)](https://badge.fury.io/rb/mcp_on_ruby)
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
- [![RuboCop](https://github.com/nagstler/ruby_mcp/actions/workflows/rubocop.yml/badge.svg)](https://github.com/nagstler/ruby_mcp/actions/workflows/rubocop.yml)
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
- [![codecov](https://codecov.io/github/nagstler/ruby_mcp/graph/badge.svg?token=SG4EJEIHW3)](https://codecov.io/github/nagstler/ruby_mcp)
10
-
11
- <strong>The Ruby way to build MCP servers and clients.</strong>
12
- </div>
13
-
14
- ## ๐Ÿ” Introduction
15
-
16
- The [Model Context Protocol](https://modelcontextprotocol.io) provides a standardized way for applications to interact with language models. Similar to how REST standardized web APIs, MCP creates a consistent interface for working with providers like OpenAI and Anthropic.
7
+ [![Ruby Version](https://img.shields.io/badge/Ruby-2.7%2B-red.svg)](https://www.ruby-lang.org/)
17
8
 
18
- ![System Component Flow (Horizontal)](https://github.com/user-attachments/assets/085ad9b8-bee0-4d60-a4b7-ecf02d07f53c)
9
+ **Model Context Protocol (MCP) server for Rails applications**
19
10
 
20
- > ๐Ÿ“Œ If you find this useful, **give it a โญ on GitHub**
11
+ Expose your Rails app as an AI accessible interface โ€” define tools and resources the Rails way.
21
12
 
22
- ## ๐Ÿ“‹ Table of Contents
13
+ [Documentation](https://rubydoc.info/gems/mcp_on_ruby) | [Contributing](#contributing)
23
14
 
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)
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
- - [๐Ÿ’พ Custom 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?
15
+ </div>
47
16
 
48
- **MCP on Ruby** provides a comprehensive implementation of the Model Context Protocol with these features:
17
+ ---
49
18
 
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
19
+ ## Features
58
20
 
59
- The library is designed to be straightforward to use while maintaining full compatibility with the MCP specification.
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
- ## ๐Ÿ“ฆ Installation
29
+ ## Installation
62
30
 
63
- Add this line to your application's Gemfile:
31
+ Add to your `Gemfile`:
64
32
 
65
33
  ```ruby
66
34
  gem 'mcp_on_ruby'
67
35
  ```
68
36
 
69
- And then execute:
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
- # Terminal 1: Start the server
107
- cd examples/simple_server
108
- ruby server.rb
109
-
110
- # Terminal 2: Run the client
111
- cd examples/simple_server
112
- ruby client.rb
113
- ```
114
-
115
- 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
-
117
- ## โš™๏ธ Configuration Options
118
-
119
- RubyMCP offers several configuration options:
120
-
121
- ```ruby
122
- RubyMCP.configure do |config|
123
- # LLM Provider configurations
124
- config.providers = {
125
- openai: {
126
- api_key: ENV['OPENAI_API_KEY'],
127
- api_base: 'https://api.openai.com/v1' # Optional
128
- },
129
- anthropic: {
130
- api_key: ENV['ANTHROPIC_API_KEY']
131
- }
132
- }
133
-
134
- # Storage backend (:memory, :redis, :active_record, or custom)
135
- config.storage = :memory
136
-
137
- # Server settings
138
- config.server_port = 3000
139
- config.server_host = "0.0.0.0"
140
-
141
- # Authentication settings
142
- config.auth_required = false
143
- config.jwt_secret = ENV['JWT_SECRET']
144
- config.token_expiry = 3600 # 1 hour
145
-
146
- # Limits
147
- config.max_contexts = 1000
148
- end
40
+ bundle install
41
+ rails generate mcp_on_ruby:install
149
42
  ```
150
43
 
151
- ## ๐Ÿ›ฃ๏ธ Server Endpoints
152
-
153
- The MCP server provides the following RESTful endpoints:
154
-
155
- ### Engines
156
- - `GET /engines` - List available language models
157
-
158
- ### Contexts
159
- - `POST /contexts` - Create a new conversation context
160
- - `GET /contexts` - List existing contexts
161
- - `GET /contexts/:id` - Get details of a specific context
162
- - `DELETE /contexts/:id` - Delete a context
163
-
164
- ### Messages
165
- - `POST /messages` - Add a message to a context
166
-
167
- ### Generation
168
- - `POST /generate` - Generate a response from a language model
169
- - `POST /generate/stream` - Stream a response with incremental updates
170
-
171
- ### Content
172
- - `POST /content` - Upload content (files)
173
- - `GET /content/:context_id/:id` - Retrieve uploaded content
174
-
175
- ## ๐Ÿ“š Detailed Usage
44
+ ## Quick Start
176
45
 
177
- ### Creating a Context
46
+ ### 1. Install and Configure
178
47
 
179
- ```ruby
180
- # Using the HTTP API
181
- response = Faraday.post(
182
- "http://localhost:3000/contexts",
183
- {
184
- messages: [
185
- {
186
- role: "system",
187
- content: "You are a helpful assistant."
188
- }
189
- ],
190
- metadata: {
191
- user_id: "user_123",
192
- conversation_name: "Technical Support"
193
- }
194
- }.to_json,
195
- "Content-Type" => "application/json"
196
- )
197
-
198
- context_id = JSON.parse(response.body)["id"]
199
- ```
200
-
201
- ### Adding a Message
202
-
203
- ```ruby
204
- Faraday.post(
205
- "http://localhost:3000/messages",
206
- {
207
- context_id: context_id,
208
- role: "user",
209
- content: "What is the capital of France?"
210
- }.to_json,
211
- "Content-Type" => "application/json"
212
- )
213
- ```
48
+ ```bash
49
+ # Generate MCP server files
50
+ rails generate mcp_on_ruby:install
214
51
 
215
- ### Generating a Response
52
+ # Create a tool
53
+ rails generate mcp_on_ruby:tool UserManager --description "Manage application users"
216
54
 
217
- ```ruby
218
- response = Faraday.post(
219
- "http://localhost:3000/generate",
220
- {
221
- context_id: context_id,
222
- engine_id: "anthropic/claude-3-sonnet-20240229",
223
- max_tokens: 1000,
224
- temperature: 0.7
225
- }.to_json,
226
- "Content-Type" => "application/json"
227
- )
228
-
229
- assistant_response = JSON.parse(response.body)["content"]
55
+ # Create a resource
56
+ rails generate mcp_on_ruby:resource UserStats --uri "users/{id}/stats" --template
230
57
  ```
231
58
 
232
- ### Streaming a Response
59
+ ### 2. Configure MCP Server
233
60
 
234
61
  ```ruby
235
- conn = Faraday.new do |f|
236
- f.request :json
237
- f.response :json
238
- f.adapter :net_http
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$/]
239
68
  end
240
69
 
241
- conn.post("http://localhost:3000/generate/stream") do |req|
242
- req.headers["Content-Type"] = "application/json"
243
- req.body = {
244
- context_id: context_id,
245
- engine_id: "openai/gpt-4",
246
- temperature: 0.7
247
- }.to_json
248
-
249
- req.options.on_data = Proc.new do |chunk, size, total|
250
- event_data = chunk.split("data: ").last.strip
251
- next if event_data.empty? || event_data == "[DONE]"
252
-
253
- event = JSON.parse(event_data)
254
- if event["event"] == "generation.content" && event["content"]
255
- print event["content"]
256
- end
257
- 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
258
74
  end
259
75
  ```
260
76
 
261
- ### Uploading Content
77
+ ### 3. Create Tools
262
78
 
263
79
  ```ruby
264
- file_data = Base64.strict_encode64(File.read("example.pdf"))
265
-
266
- Faraday.post(
267
- "http://localhost:3000/content",
268
- {
269
- context_id: context_id,
270
- type: "file",
271
- filename: "example.pdf",
272
- content_type: "application/pdf",
273
- file_data: file_data
274
- }.to_json,
275
- "Content-Type" => "application/json"
276
- )
277
- ```
278
-
279
- ### Using Tool Calls
280
-
281
- ```ruby
282
- tools = [
283
- {
284
- type: "function",
285
- function: {
286
- name: "get_weather",
287
- description: "Get the current weather for a location",
288
- parameters: {
289
- 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',
290
88
  properties: {
291
- location: {
292
- type: "string",
293
- description: "City and state, e.g., San Francisco, CA"
294
- }
89
+ action: { type: 'string', enum: ['create', 'update', 'delete'] },
90
+ user_id: { type: 'integer' },
91
+ attributes: { type: 'object' }
295
92
  },
296
- required: ["location"]
93
+ required: ['action']
297
94
  }
298
- }
299
- }
300
- ]
301
-
302
- response = Faraday.post(
303
- "http://localhost:3000/generate",
304
- {
305
- context_id: context_id,
306
- engine_id: "openai/gpt-4",
307
- tools: tools
308
- }.to_json,
309
- "Content-Type" => "application/json"
310
- )
311
-
312
- if response.body["tool_calls"]
313
- # Handle tool calls
314
- tool_calls = response.body["tool_calls"]
315
- # Process tool calls and add tool response message
316
- end
317
- ```
318
-
319
- ## ๐Ÿš„ Rails Integration
320
-
321
- For Rails applications, create an initializer at `config/initializers/ruby_mcp.rb`:
95
+ )
96
+ end
322
97
 
323
- ```ruby
324
- RubyMCP.configure do |config|
325
- config.providers = {
326
- openai: { api_key: ENV['OPENAI_API_KEY'] },
327
- anthropic: { api_key: ENV['ANTHROPIC_API_KEY'] }
328
- }
329
-
330
- # Use memory storage in development, consider persistent storage in production
331
- if Rails.env.development? || Rails.env.test?
332
- config.storage = :memory
333
- else
334
- config.storage = :memory # Replace with persistent option when implemented
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
335
112
  end
336
-
337
- # Enable authentication in production
338
- if Rails.env.production?
339
- config.auth_required = true
340
- config.jwt_secret = ENV["JWT_SECRET"]
113
+
114
+ def authorize(context)
115
+ # Add your authorization logic
116
+ context[:authenticated] == true
341
117
  end
342
118
  end
343
119
  ```
344
120
 
345
- And mount the server in your `config/routes.rb` file:
121
+ ### 4. Create Resources
346
122
 
347
123
  ```ruby
348
- Rails.application.routes.draw do
349
- # Mount RubyMCP at /api/mcp
350
- mount_mcp_at = "/api/mcp"
351
-
352
- Rails.application.config.middleware.use Rack::Config do |env|
353
- env["SCRIPT_NAME"] = mount_mcp_at if env["PATH_INFO"].start_with?(mount_mcp_at)
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
+ )
354
133
  end
355
-
356
- mount RubyMCP::Server::App.new.rack_app, at: mount_mcp_at
357
-
358
- # Rest of your routes
359
- # ...
360
- end
361
- ```
362
-
363
- ## ๐Ÿ’พ Storage Backends
364
-
365
- ### Redis Storage
366
-
367
- MCP on Ruby supports Redis as a persistent storage backend:
368
134
 
369
- 1. Add the Redis gem to your Gemfile:
370
- ```ruby
371
- gem 'redis', '~> 5.0'
372
- ```
135
+ protected
373
136
 
374
- 2. Configure Redis storage:
375
- ```ruby
376
- RubyMCP.configure do |config|
377
- config.storage = :redis
378
- config.redis = {
379
- url: ENV.fetch('REDIS_URL', 'redis://localhost:6379/0'),
380
- namespace: "app_mcp_#{Rails.env}",
381
- ttl: 86400 # 1 day in seconds
382
- }
383
- end
384
- ```
385
-
386
- 3. Access the configured client:
387
- ```ruby
388
- client = RubyMCP.client
389
- ```
390
-
391
- For detailed integration examples, see the [[Redis Storage](https://github.com/nagstler/mcp_on_ruby/wiki/Redis-Storage)] wiki page.
392
-
393
-
394
- ### Custom storage
395
- You can implement custom storage backends by extending the base storage class:
396
-
397
- ```ruby
398
- class RedisStorage < RubyMCP::Storage::Base
399
- def initialize(options = {})
400
- super
401
- @redis = Redis.new(options)
402
- end
403
-
404
- def create_context(context)
405
- @redis.set("context:#{context.id}", JSON.dump(context.to_h))
406
- context
407
- end
408
-
409
- def get_context(context_id)
410
- data = @redis.get("context:#{context_id}")
411
- raise RubyMCP::Errors::ContextError, "Context not found: #{context_id}" unless data
137
+ def fetch_content(params, context)
138
+ user = User.find(params['id'])
412
139
 
413
- hash = JSON.parse(data, symbolize_names: true)
414
-
415
- # Create message objects
416
- messages = hash[:messages].map do |msg|
417
- RubyMCP::Models::Message.new(
418
- role: msg[:role],
419
- content: msg[:content],
420
- id: msg[:id],
421
- metadata: msg[:metadata]
422
- )
423
- end
424
-
425
- # Create the context
426
- RubyMCP::Models::Context.new(
427
- id: hash[:id],
428
- messages: messages,
429
- metadata: hash[:metadata]
430
- )
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
+ }
431
150
  end
432
-
433
- # Implement other required methods...
434
- end
435
151
 
436
- # Configure RubyMCP to use your custom storage
437
- RubyMCP.configure do |config|
438
- config.storage = RedisStorage.new(url: ENV["REDIS_URL"])
152
+ def authorize(context)
153
+ # Check if user can access this data
154
+ context[:authenticated] == true
155
+ end
439
156
  end
440
157
  ```
441
158
 
442
- ## ๐Ÿ”’ Authentication
159
+ ### 5. Start Your Server
443
160
 
444
- To enable JWT authentication:
445
-
446
- ```ruby
447
- RubyMCP.configure do |config|
448
- config.auth_required = true
449
- config.jwt_secret = ENV['JWT_SECRET']
450
- config.token_expiry = 3600 # 1 hour
451
- end
161
+ ```bash
162
+ rails server
163
+ # MCP server available at http://localhost:3000/mcp
452
164
  ```
453
165
 
454
- Then, create and use JWT tokens:
166
+ ## Architecture
455
167
 
456
- ```ruby
457
- # Generate a token
458
- require 'jwt'
168
+ ```
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
+ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
187
+ ```
459
188
 
460
- payload = {
461
- sub: "user_123",
462
- exp: Time.now.to_i + 3600
463
- }
189
+ ## Examples
464
190
 
465
- token = JWT.encode(payload, ENV['JWT_SECRET'], 'HS256')
191
+ Connect your Rails MCP server with different AI clients:
466
192
 
467
- # Use the token in requests
468
- conn = Faraday.new do |f|
469
- f.request :json
470
- f.response :json
471
- f.adapter :net_http
472
- end
193
+ ๐Ÿ‘‰ **[Claude Desktop](examples/claude/)** - Complete setup guide with bridge script
473
194
 
474
- conn.get("http://localhost:3000/contexts") do |req|
475
- req.headers["Authorization"] = "Bearer #{token}"
476
- end
477
- ```
195
+ ## Documentation
478
196
 
479
- ## ๐Ÿ› ๏ธ Development
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
480
200
 
481
- 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.
482
201
 
483
- ### Running Tests
202
+ ## Requirements
484
203
 
485
- ```
486
- bundle exec rspec
487
- ```
204
+ - Ruby 2.7.0 or higher
205
+ - Rails 6.0 or higher (for full integration)
206
+ - JSON Schema validation support
488
207
 
489
- ### Local Development Server
208
+ ## Dependencies
490
209
 
491
- ```
492
- bundle exec ruby examples/simple_server/server.rb
493
- ```
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
214
+
215
+ ## Contributing
494
216
 
495
- ## ๐Ÿ—บ๏ธ Roadmap
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
496
224
 
497
- While RubyMCP is functional for basic use cases, there are several areas planned for improvement:
225
+ ## License
498
226
 
499
- - [x] Redis persistent storage backend
500
- - [ ] ActiveRecord storage backend
501
- - [ ] Complete test coverage, including integration tests
502
- - [ ] Improved error handling and recovery strategies
503
- - [ ] Rate limiting for provider APIs
504
- - [ ] Proper tokenization for context window management
505
- - [ ] More robust streaming implementation
506
- - [ ] Additional provider integrations
227
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE.txt) file for details.
507
228
 
508
- :heart: Contributions in any of these areas are welcome!
229
+ ## ๐Ÿ™ Acknowledgments
509
230
 
510
- ## ๐Ÿ‘ฅ Contributing
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
511
233
 
512
- 1. Fork the repository
513
- 2. Create your feature branch (`git checkout -b feature/my-new-feature`)
514
- 3. Commit your changes (`git commit -am 'Add some feature'`)
515
- 4. Push to the branch (`git push origin feature/my-new-feature`)
516
- 5. Create a new Pull Request
234
+ ---
517
235
 
518
- Bug reports and pull requests are welcome on GitHub at https://github.com/nagstler/mcp_on_ruby.
236
+ <div align="center">
519
237
 
520
- ## ๐Ÿ“„ License
238
+ Made with โค๏ธ for the Ruby community
521
239
 
522
- The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
240
+ </div>