mcp_lite 2.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 +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +584 -0
- data/Rakefile +9 -0
- data/lib/mcp_lite/completion.rb +21 -0
- data/lib/mcp_lite/configuration.rb +22 -0
- data/lib/mcp_lite/executor/resource_reader.rb +70 -0
- data/lib/mcp_lite/executor/tool_executor.rb +102 -0
- data/lib/mcp_lite/message/audio.rb +22 -0
- data/lib/mcp_lite/message/image.rb +24 -0
- data/lib/mcp_lite/message/resource.rb +24 -0
- data/lib/mcp_lite/message/text.rb +20 -0
- data/lib/mcp_lite/prompt/base.rb +52 -0
- data/lib/mcp_lite/resource/base.rb +79 -0
- data/lib/mcp_lite/schema/base.rb +141 -0
- data/lib/mcp_lite/schema/method.rb +20 -0
- data/lib/mcp_lite/server/error_code.rb +14 -0
- data/lib/mcp_lite/server/fetcher.rb +55 -0
- data/lib/mcp_lite/server/method.rb +18 -0
- data/lib/mcp_lite/server/protocol_handler.rb +200 -0
- data/lib/mcp_lite/server/stdio_connection.rb +21 -0
- data/lib/mcp_lite/server.rb +81 -0
- data/lib/mcp_lite/tool/base.rb +68 -0
- data/lib/mcp_lite/version.rb +3 -0
- data/lib/mcp_lite.rb +21 -0
- metadata +78 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 577f4745501390e1f5c3bda2faa1fe07f75fe6bca6588f4d513ac8fac012f5a0
|
4
|
+
data.tar.gz: 7c39bf43bb1f21aee0786dc3e1c962f0d9d7f33c4b1d6e462b3ee26e90f7950b
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 1745e12fccb017eda42788736dd9776dc8e6bdd1ffa0743f5c7e3b20feee9344a9eb970156cd159c261569eab2f1bff06ea7c2a7c1ae8eff64e8f8462a3a01c5
|
7
|
+
data.tar.gz: 2f2aaf233e0838d656ace6b62a4442fbc75b57193072b80fa4ea5eb5cb24c41aff2b93b91b9e370f3850ed2374932007ee0e496da510b88fabf10c8c343d6d29
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2024 Moeki Kawakami
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,584 @@
|
|
1
|
+
<div align="center">
|
2
|
+
<img src="./website/public/logo.png" alt="MCP Lite" width="200"></i>
|
3
|
+
</div>
|
4
|
+
|
5
|
+
<div align="center">
|
6
|
+
|
7
|
+
<h1>MCP Lite</h1>
|
8
|
+
|
9
|
+
[](https://badge.fury.io/rb/mcp_lite)
|
10
|
+
[](LICENSE)
|
11
|
+
|
12
|
+
The Lightweight implementation of Model Context Protocol (MCP) in Ruby.
|
13
|
+
|
14
|
+
</div>
|
15
|
+
|
16
|
+
### Caution
|
17
|
+
|
18
|
+
This is an early version of MCP Lite. The API may change in future releases. Please check the [CHANGELOG](CHANGELOG.md) for updates.
|
19
|
+
|
20
|
+
[Active MCP](https://rubygems.org/gems/active_mcp) is deprecated. This library is a lightweight implementation of the Model Context Protocol (MCP) in Ruby, designed to be easy to use and integrate into your applications.
|
21
|
+
|
22
|
+
## ๐ Table of Contents
|
23
|
+
|
24
|
+
- [๐ Table of Contents](#-table-of-contents)
|
25
|
+
- [โจ Features](#-features)
|
26
|
+
- [๐ฆ Installation](#-installation)
|
27
|
+
- [๐ Setup](#-setup)
|
28
|
+
- [๐ MCP Connection](#-mcp-connection)
|
29
|
+
- [๐งฐ Creating MCP Tools](#-creating-mcp-tools)
|
30
|
+
- [๐ Input Schema](#-input-schema)
|
31
|
+
- [๐ Authorization \& Authentication](#-authorization--authentication)
|
32
|
+
- [Authorization for Tools](#authorization-for-tools)
|
33
|
+
- [Authentication Options](#authentication-options)
|
34
|
+
- [1. Server Configuration](#1-server-configuration)
|
35
|
+
- [2. Token Verification in Tools](#2-token-verification-in-tools)
|
36
|
+
- [๐ฆ MCP Resources](#-mcp-resources)
|
37
|
+
- [Creating Resources](#creating-resources)
|
38
|
+
- [Resource Types](#resource-types)
|
39
|
+
- [๐ฆ MCP Resource Templates](#-mcp-resource-templates)
|
40
|
+
- [Creating Resource Templates](#creating-resource-templates)
|
41
|
+
- [๐ฌ MCP Prompts](#-mcp-prompts)
|
42
|
+
- [Creating Prompt](#creating-prompt)
|
43
|
+
- [๐ก Best Practices](#-best-practices)
|
44
|
+
- [1. Create Specific Tool Classes](#1-create-specific-tool-classes)
|
45
|
+
- [2. Validate and Sanitize Inputs](#2-validate-and-sanitize-inputs)
|
46
|
+
- [3. Return Structured Responses](#3-return-structured-responses)
|
47
|
+
- [๐งช Development](#-development)
|
48
|
+
- [๐ฅ Contributing](#-contributing)
|
49
|
+
- [๐ License](#-license)
|
50
|
+
|
51
|
+
## ๐ฆ Installation
|
52
|
+
|
53
|
+
Add this line to your application's Gemfile:
|
54
|
+
|
55
|
+
```ruby
|
56
|
+
gem 'mcp_lite'
|
57
|
+
```
|
58
|
+
|
59
|
+
And then execute:
|
60
|
+
|
61
|
+
```bash
|
62
|
+
$ bundle install
|
63
|
+
```
|
64
|
+
|
65
|
+
Or install it yourself as:
|
66
|
+
|
67
|
+
```bash
|
68
|
+
$ gem install mcp_lite
|
69
|
+
```
|
70
|
+
|
71
|
+
## ๐ Setup
|
72
|
+
|
73
|
+
```ruby
|
74
|
+
class CreateNoteTool < McpLite::Tool::Base
|
75
|
+
tool_name "create_note"
|
76
|
+
|
77
|
+
description "Create Note"
|
78
|
+
|
79
|
+
argument :title, :string, required: true
|
80
|
+
argument :content, :string, required: true
|
81
|
+
argument :published_at, :string, required: true,
|
82
|
+
visible: ->(context) { context[:role] == "admin" }
|
83
|
+
|
84
|
+
def call(title:, content:, context:)
|
85
|
+
note = Note.create(title: title, content: content)
|
86
|
+
|
87
|
+
[{ type: "text", text: "Created note with ID: #{note.id}" }]
|
88
|
+
end
|
89
|
+
end
|
90
|
+
```
|
91
|
+
|
92
|
+
```ruby
|
93
|
+
class MySchema < McpLite::Schema::Base
|
94
|
+
tools CreateNoteTool
|
95
|
+
end
|
96
|
+
```
|
97
|
+
|
98
|
+
```ruby
|
99
|
+
class MyMcpController < McpLite::BaseController
|
100
|
+
def index
|
101
|
+
render json: MySchema.execute(param:, context:)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
```
|
105
|
+
|
106
|
+
```ruby
|
107
|
+
Rails.application.routes.draw do
|
108
|
+
post "/mcp", to: "my_mcp#index"
|
109
|
+
|
110
|
+
# Your other routes
|
111
|
+
end
|
112
|
+
```
|
113
|
+
|
114
|
+
## ๐ MCP Connection Methods
|
115
|
+
|
116
|
+
Start a dedicated MCP server that communicates with your Ruby app:
|
117
|
+
|
118
|
+
```ruby
|
119
|
+
# script/mcp_server.rb
|
120
|
+
server = McpLite::Server.new(
|
121
|
+
name: "My App MCP Server",
|
122
|
+
uri: 'https://your-app.example.com/mcp'
|
123
|
+
)
|
124
|
+
server.start
|
125
|
+
```
|
126
|
+
|
127
|
+
Then configure your MCP client:
|
128
|
+
|
129
|
+
```json
|
130
|
+
{
|
131
|
+
"mcpServers": {
|
132
|
+
"my-rails-app": {
|
133
|
+
"command": "/path/to/ruby",
|
134
|
+
"args": ["/path/to/script/mcp_server.rb"]
|
135
|
+
}
|
136
|
+
}
|
137
|
+
}
|
138
|
+
```
|
139
|
+
|
140
|
+
## ๐งฐ Creating MCP Tools
|
141
|
+
|
142
|
+
MCP tools are Ruby classes that inherit from `McpLite::Tool::Base` and define an interface for AI to interact with your application:
|
143
|
+
|
144
|
+
```ruby
|
145
|
+
class SearchUsersTool < McpLite::Tool::Base
|
146
|
+
tool_name "Search Users"
|
147
|
+
|
148
|
+
description 'Search users by criteria'
|
149
|
+
|
150
|
+
argument :email, :string, required: false, description: 'Email to search for'
|
151
|
+
argument :name, :string, required: false, description: 'Name to search for'
|
152
|
+
argument :limit, :integer, required: false, description: 'Maximum number of records to return'
|
153
|
+
|
154
|
+
def call(email: nil, name: nil, limit: 10, context: {})
|
155
|
+
criteria = {}
|
156
|
+
criteria[:email] = email if email.present?
|
157
|
+
criteria[:name] = name if name.present?
|
158
|
+
|
159
|
+
users = User.where(criteria).limit(limit)
|
160
|
+
|
161
|
+
[{ type: "text", text: users.attributes.to_json }]
|
162
|
+
end
|
163
|
+
end
|
164
|
+
```
|
165
|
+
|
166
|
+
## ๐ Input Schema
|
167
|
+
|
168
|
+
Define arguments for your tools using the `argument` method:
|
169
|
+
|
170
|
+
```ruby
|
171
|
+
argument :name, :string, required: true, description: 'User name'
|
172
|
+
argument :age, :integer, required: false, description: 'User age'
|
173
|
+
argument :addresses, :array, required: false, description: 'User addresses'
|
174
|
+
argument :preferences, :object, required: false, description: 'User preferences'
|
175
|
+
```
|
176
|
+
|
177
|
+
Supported types:
|
178
|
+
|
179
|
+
| Type | Description |
|
180
|
+
| ---------- | ------------------------------- |
|
181
|
+
| `:string` | Text values |
|
182
|
+
| `:integer` | Whole numbers |
|
183
|
+
| `:number` | Decimal numbers (float/decimal) |
|
184
|
+
| `:boolean` | True/false values |
|
185
|
+
| `:array` | Lists of values |
|
186
|
+
| `:object` | Hash/dictionary structures |
|
187
|
+
| `:null` | Null values |
|
188
|
+
|
189
|
+
## ๐ Authorization & Authentication
|
190
|
+
|
191
|
+
### Authorization for Tools
|
192
|
+
|
193
|
+
Control access to tools by overriding the `visible?` class method:
|
194
|
+
|
195
|
+
```ruby
|
196
|
+
class AdminOnlyTool < McpLite::Tool::Base
|
197
|
+
tool_name "admin_only_tool"
|
198
|
+
|
199
|
+
description "Admin-only tool"
|
200
|
+
|
201
|
+
argument :command, :string, required: true, description: "Admin command"
|
202
|
+
|
203
|
+
# Only allow admins to access this tool
|
204
|
+
def self.visible?(context:)
|
205
|
+
return false unless context
|
206
|
+
return false unless context[:current_user]
|
207
|
+
|
208
|
+
# Check if the token belongs to an admin
|
209
|
+
User.find_by_token(context[:current_user][:token])&.admin?
|
210
|
+
end
|
211
|
+
|
212
|
+
def call(command:, context: {})
|
213
|
+
# Tool implementation
|
214
|
+
end
|
215
|
+
end
|
216
|
+
```
|
217
|
+
|
218
|
+
### Authentication Options
|
219
|
+
|
220
|
+
#### 1. Server Configuration
|
221
|
+
|
222
|
+
```ruby
|
223
|
+
server = McpLite::Server.new(
|
224
|
+
name: "My Secure MCP Server",
|
225
|
+
uri: 'http://localhost:3000/mcp',
|
226
|
+
auth: {
|
227
|
+
type: :bearer,
|
228
|
+
token: ENV['MCP_AUTH_TOKEN']
|
229
|
+
}
|
230
|
+
)
|
231
|
+
server.start
|
232
|
+
```
|
233
|
+
|
234
|
+
#### 2. Token Verification in Tools
|
235
|
+
|
236
|
+
```ruby
|
237
|
+
def call(resource_id:, context: {})
|
238
|
+
# Check if authentication is provided
|
239
|
+
unless context[:current_user].present?
|
240
|
+
raise "Authentication required"
|
241
|
+
end
|
242
|
+
|
243
|
+
# Proceed with authenticated operation
|
244
|
+
# ...
|
245
|
+
end
|
246
|
+
```
|
247
|
+
|
248
|
+
## ๐ฆ MCP Resources
|
249
|
+
|
250
|
+
MCP Resources allow you to share data and files with AI assistants. Resources have a URI, MIME type, and can return either text or binary data.
|
251
|
+
|
252
|
+
### Creating Resources
|
253
|
+
|
254
|
+
Resources are Ruby classes `**Resource`:
|
255
|
+
|
256
|
+
```ruby
|
257
|
+
class UserResource < McpLite::Resource::Base
|
258
|
+
mime_type "application/json"
|
259
|
+
|
260
|
+
def initialize(id:)
|
261
|
+
@user = User.find(id)
|
262
|
+
end
|
263
|
+
|
264
|
+
def resource_name
|
265
|
+
@user.name
|
266
|
+
end
|
267
|
+
|
268
|
+
def uri
|
269
|
+
"data://localhost/users/#{@user.id}"
|
270
|
+
end
|
271
|
+
|
272
|
+
def description
|
273
|
+
@user.profile
|
274
|
+
end
|
275
|
+
|
276
|
+
def self.visible?(context:)
|
277
|
+
# Your logic...
|
278
|
+
end
|
279
|
+
|
280
|
+
def text
|
281
|
+
# Return JSON data
|
282
|
+
{
|
283
|
+
id: @user.id,
|
284
|
+
name: @user.name,
|
285
|
+
email: @user.email,
|
286
|
+
created_at: @user.created_at
|
287
|
+
}
|
288
|
+
end
|
289
|
+
end
|
290
|
+
```
|
291
|
+
|
292
|
+
```ruby
|
293
|
+
class MySchema < McpLite::Schema::Base
|
294
|
+
resource UserResource, items: User.all.each do |user|
|
295
|
+
{ id: user.id }
|
296
|
+
end
|
297
|
+
end
|
298
|
+
```
|
299
|
+
|
300
|
+
### Resource Types
|
301
|
+
|
302
|
+
Resources can return two types of content:
|
303
|
+
|
304
|
+
1. **Text Content** - Use the `text` method to return structured data:
|
305
|
+
|
306
|
+
```ruby
|
307
|
+
def text
|
308
|
+
# Return strings, arrays, hashes, or any JSON-serializable object
|
309
|
+
{ items: Product.all.map(&:attributes) }
|
310
|
+
end
|
311
|
+
```
|
312
|
+
|
313
|
+
2. **Binary Content** - Use the `blob` method to return binary files:
|
314
|
+
|
315
|
+
```ruby
|
316
|
+
class ImageResource < McpLite::Resource::Base
|
317
|
+
mime_type "image/png"
|
318
|
+
|
319
|
+
def resource_name
|
320
|
+
"profile_image"
|
321
|
+
end
|
322
|
+
|
323
|
+
def uri
|
324
|
+
"data://localhost/image"
|
325
|
+
end
|
326
|
+
|
327
|
+
def description
|
328
|
+
"Profile image"
|
329
|
+
end
|
330
|
+
|
331
|
+
def blob
|
332
|
+
# Return binary file content
|
333
|
+
File.read(Rails.root.join("public", "profile.png"))
|
334
|
+
end
|
335
|
+
end
|
336
|
+
```
|
337
|
+
|
338
|
+
Resources can be protected using the same authorization mechanism as tools:
|
339
|
+
|
340
|
+
```ruby
|
341
|
+
def visible?(context: {})
|
342
|
+
return false unless context
|
343
|
+
return false unless context[:current_user]
|
344
|
+
|
345
|
+
# Check if the token belongs to an admin
|
346
|
+
User.find_by_token(context[:current_user][:token])&.admin?
|
347
|
+
end
|
348
|
+
```
|
349
|
+
|
350
|
+
## ๐ฆ MCP Resource Templates
|
351
|
+
|
352
|
+
MCP Resource Teamplates allow you to define template of resources.
|
353
|
+
|
354
|
+
### Creating Resource Templates
|
355
|
+
|
356
|
+
Resource teamplates are Ruby classes `**Resource`:
|
357
|
+
|
358
|
+
```ruby
|
359
|
+
class UserResource < McpLite::Resource::Base
|
360
|
+
resource_template_name "users"
|
361
|
+
|
362
|
+
uri_template "data://localhost/users/{id}"
|
363
|
+
|
364
|
+
mime_type "application/json"
|
365
|
+
|
366
|
+
description "This is a test."
|
367
|
+
|
368
|
+
argument :id, complete: ->(value, context) do
|
369
|
+
User.all.pluck(:id).filter { _1.match(value) }
|
370
|
+
end
|
371
|
+
|
372
|
+
def self.visible?(context:)
|
373
|
+
# Your logic...
|
374
|
+
end
|
375
|
+
|
376
|
+
def initialize(id:)
|
377
|
+
@user = User.find(id)
|
378
|
+
end
|
379
|
+
|
380
|
+
def resource_name
|
381
|
+
@user.name
|
382
|
+
end
|
383
|
+
|
384
|
+
def description
|
385
|
+
@user.profile
|
386
|
+
end
|
387
|
+
|
388
|
+
def uri
|
389
|
+
"data://localhost/users/#{@user.name}"
|
390
|
+
end
|
391
|
+
|
392
|
+
def text
|
393
|
+
{ name: @user.name }
|
394
|
+
end
|
395
|
+
end
|
396
|
+
```
|
397
|
+
|
398
|
+
```ruby
|
399
|
+
class MySchema < McpLite::Schema::Base
|
400
|
+
resource UserResource, items: User.all.each do |user|
|
401
|
+
{ id: user.id }
|
402
|
+
end
|
403
|
+
end
|
404
|
+
```
|
405
|
+
|
406
|
+
## ๐ฌ MCP Prompts
|
407
|
+
|
408
|
+
MCP Prompts allow you to define prompt set.
|
409
|
+
|
410
|
+
### Creating Prompt
|
411
|
+
|
412
|
+
Resources are Ruby classes `**Prompt`:
|
413
|
+
|
414
|
+
```ruby
|
415
|
+
class HelloPrompt < McpLite::Prompt::Base
|
416
|
+
prompt_name "hello"
|
417
|
+
|
418
|
+
description "This is a test."
|
419
|
+
|
420
|
+
argument :name, required: true, description: "User name", complete: ->(value, context) do
|
421
|
+
User.all.pluck(:name).filter { _1.match(value) }
|
422
|
+
end
|
423
|
+
|
424
|
+
def self.visible?(context:)
|
425
|
+
# Your logic...
|
426
|
+
end
|
427
|
+
|
428
|
+
def messages(name:)
|
429
|
+
[
|
430
|
+
McpLite::Message::Text.new(
|
431
|
+
role: "user",
|
432
|
+
text: "Hello! #{name}"
|
433
|
+
),
|
434
|
+
McpLite::Message::Image.new(
|
435
|
+
role: "assistant",
|
436
|
+
data: File.read(file),
|
437
|
+
mime_type: "image/png"
|
438
|
+
),
|
439
|
+
McpLite::Message::Audio.new(
|
440
|
+
role: "user",
|
441
|
+
data: File.read(file),
|
442
|
+
mime_type: "audio/mpeg"
|
443
|
+
),
|
444
|
+
McpLite::Message::Resource.new(
|
445
|
+
role: "assistant",
|
446
|
+
resource: UserResource.new(name: @name)
|
447
|
+
)
|
448
|
+
]
|
449
|
+
end
|
450
|
+
end
|
451
|
+
```
|
452
|
+
|
453
|
+
```ruby
|
454
|
+
class MySchema < McpLite::Schema::Base
|
455
|
+
prompt HelloPrompt
|
456
|
+
end
|
457
|
+
```
|
458
|
+
|
459
|
+
## ๐ก Best Practices
|
460
|
+
|
461
|
+
### 1. Create Specific Tool Classes
|
462
|
+
|
463
|
+
Create dedicated tool classes for each model or operation instead of generic tools:
|
464
|
+
|
465
|
+
```ruby
|
466
|
+
# โ
GOOD: Specific tool for a single purpose
|
467
|
+
class SearchUsersTool < McpLite::Tool::Base
|
468
|
+
# ...specific implementation
|
469
|
+
end
|
470
|
+
|
471
|
+
# โ BAD: Generic tool that dynamically loads models
|
472
|
+
class GenericSearchTool < McpLite::Tool::Base
|
473
|
+
# Avoid this pattern - security and maintainability issues
|
474
|
+
end
|
475
|
+
```
|
476
|
+
|
477
|
+
### 2. Validate and Sanitize Inputs
|
478
|
+
|
479
|
+
Always validate and sanitize inputs in your tool implementations:
|
480
|
+
|
481
|
+
```ruby
|
482
|
+
def call(user_id:, context: {})
|
483
|
+
# Validate input
|
484
|
+
unless user_id.is_a?(Integer) || user_id.to_s.match?(/^\d+$/)
|
485
|
+
raise "Invalid user ID format"
|
486
|
+
end
|
487
|
+
|
488
|
+
# Proceed with validated data
|
489
|
+
user = User.find_by(id: user_id)
|
490
|
+
# ...
|
491
|
+
end
|
492
|
+
```
|
493
|
+
|
494
|
+
### 3. Return Structured Responses
|
495
|
+
|
496
|
+
Return structured responses that are easy for AI to parse:
|
497
|
+
|
498
|
+
```ruby
|
499
|
+
def call(query:, context: {})
|
500
|
+
results = User.search(query)
|
501
|
+
|
502
|
+
[{
|
503
|
+
type: "text",
|
504
|
+
text: {
|
505
|
+
content: results.to_json(only: [:id, :name, :email]),
|
506
|
+
metadata: {
|
507
|
+
count: results.size,
|
508
|
+
query: query
|
509
|
+
}
|
510
|
+
}.to_json
|
511
|
+
}]
|
512
|
+
end
|
513
|
+
```
|
514
|
+
|
515
|
+
## ๐งช Development
|
516
|
+
|
517
|
+
After checking out the repo, run `bundle install` to install dependencies. Then, run `bundle exec rake` to run the tests.
|
518
|
+
|
519
|
+
## ๐ฅ Contributing
|
520
|
+
|
521
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/moekiorg/mcp_lite. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/moekiorg/mcp_lite/blob/main/CODE_OF_CONDUCT.md).
|
522
|
+
|
523
|
+
## ๐ License
|
524
|
+
|
525
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
526
|
+
|
527
|
+
# MCP Lite
|
528
|
+
|
529
|
+
Model Context Protocol (MCP) implementation in Ruby.
|
530
|
+
|
531
|
+
## Installation
|
532
|
+
|
533
|
+
Add this line to your application's Gemfile:
|
534
|
+
|
535
|
+
```ruby
|
536
|
+
gem 'mcp_lite'
|
537
|
+
```
|
538
|
+
|
539
|
+
## Usage
|
540
|
+
|
541
|
+
### Basic Usage (Without Rails)
|
542
|
+
|
543
|
+
```ruby
|
544
|
+
require 'mcp_lite'
|
545
|
+
|
546
|
+
class MySchema < McpLite::Schema::Base
|
547
|
+
tool SearchTool
|
548
|
+
resource UserResource, items: [
|
549
|
+
{name: "UserA"},
|
550
|
+
{name: "UserB"}
|
551
|
+
]
|
552
|
+
prompt HelloPrompt
|
553
|
+
end
|
554
|
+
|
555
|
+
# Execute MCP request
|
556
|
+
result = MySchema.execute(
|
557
|
+
params: {
|
558
|
+
method: "tools/list",
|
559
|
+
params: {},
|
560
|
+
jsonrpc: "2.0"
|
561
|
+
},
|
562
|
+
context: {
|
563
|
+
current_user: User.find_by_token(token)
|
564
|
+
}
|
565
|
+
)
|
566
|
+
```
|
567
|
+
|
568
|
+
### Rails Integration
|
569
|
+
|
570
|
+
```ruby
|
571
|
+
# app/controllers/mcp_controller.rb
|
572
|
+
class McpController < McpLite::BaseController
|
573
|
+
def index
|
574
|
+
render json: MySchema.execute(param:, context:)
|
575
|
+
end
|
576
|
+
end
|
577
|
+
|
578
|
+
# config/routes.rb
|
579
|
+
Rails.application.routes.draw do
|
580
|
+
post "/mcp", to: "mcp#index"
|
581
|
+
end
|
582
|
+
```
|
583
|
+
|
584
|
+
// ...existing documentation...
|
data/Rakefile
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
module McpLite
|
2
|
+
class Completion
|
3
|
+
def complete(params: {}, context: {}, refs: [])
|
4
|
+
ref_name = params.dig(:ref, :name)
|
5
|
+
uri_template = params.dig(:ref, :uri)
|
6
|
+
arg_name = params.dig(:argument, :name)
|
7
|
+
value = params.dig(:argument, :value)
|
8
|
+
|
9
|
+
if uri_template
|
10
|
+
resource_class = refs.find { _1.uri_template_value == uri_template }
|
11
|
+
values = resource_class.arguments[arg_name.to_sym].call(value, context)
|
12
|
+
{values:, total: values.length}
|
13
|
+
elsif ref_name
|
14
|
+
prompt = refs.find { _1.prompt_name_value == ref_name }
|
15
|
+
values = prompt.arguments.find { _1[:name] == arg_name.to_sym }[:complete].call(value, context)
|
16
|
+
|
17
|
+
{values:, total: values.length}
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module McpLite
|
4
|
+
class Configuration
|
5
|
+
attr_accessor :server_name, :server_version
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@server_name = "MCP Server"
|
9
|
+
@server_version = "1.0.0"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class << self
|
14
|
+
def configure
|
15
|
+
yield config
|
16
|
+
end
|
17
|
+
|
18
|
+
def config
|
19
|
+
@config ||= Configuration.new
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|