mcp-rb 0.1.0 → 0.2.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 +24 -0
- data/README.md +39 -18
- data/lib/mcp/app/resource.rb +57 -11
- data/lib/mcp/app/tool.rb +77 -12
- data/lib/mcp/server.rb +4 -4
- data/lib/mcp/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 28e6b1fc53252ecd7717e71d06f0c124c61a8fbb9e389fa9514f3249b056930e
|
4
|
+
data.tar.gz: 454af20d33b8cbe80dad61214b0ca3680a8715bef024d4d26dd77a5b800e37ba
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6aca66d612f5851304248561e0eb73402ef30d30da6fd45c35aea89b43d6499c29da58a37f6deae55931a3ede9eb56de4cf447595adaee8f227836e8923f1823
|
7
|
+
data.tar.gz: cde9c8f9b18b6945d5e5e478ea18e1592c372393b1263f329b35bc0510df58110feda73ae1fcd785d93af0e701fe6bfaab200296845d7b601ba33525337f654c
|
data/CHANGELOG.md
CHANGED
@@ -5,6 +5,30 @@ All notable changes to this project will be documented in this file.
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
7
7
|
|
8
|
+
## [0.2.0] - 2025-02-14
|
9
|
+
|
10
|
+
### Breaking Changes
|
11
|
+
- Unified DSL to block-based style for both tools and resources
|
12
|
+
- Example of new resource style:
|
13
|
+
```ruby
|
14
|
+
resource "uri" do
|
15
|
+
name "Resource Name"
|
16
|
+
description "Description"
|
17
|
+
mime_type "text/plain"
|
18
|
+
call { "content" }
|
19
|
+
end
|
20
|
+
```
|
21
|
+
- Example of new tool style:
|
22
|
+
```ruby
|
23
|
+
tool "greet" do
|
24
|
+
description "Greet someone"
|
25
|
+
argument :name, String, required: true, description: "Name to greet"
|
26
|
+
call do |args|
|
27
|
+
"Hello, #{args[:name]}!"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
```
|
31
|
+
|
8
32
|
## [0.1.0] - 2025-02-12
|
9
33
|
|
10
34
|
### Added
|
data/README.md
CHANGED
@@ -19,26 +19,20 @@ require 'mcp'
|
|
19
19
|
|
20
20
|
name "hello-world"
|
21
21
|
|
22
|
-
#
|
23
|
-
resource "hello://world"
|
24
|
-
name
|
25
|
-
description
|
26
|
-
"Hello, World!"
|
22
|
+
# Define a resource
|
23
|
+
resource "hello://world" do
|
24
|
+
name "Hello World"
|
25
|
+
description "A simple hello world message"
|
26
|
+
call { "Hello, World!" }
|
27
27
|
end
|
28
28
|
|
29
|
-
tool
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
description: "Name to greet"
|
37
|
-
}
|
38
|
-
},
|
39
|
-
required: [:name]
|
40
|
-
} do |args|
|
41
|
-
"Hello, #{args[:name]}!"
|
29
|
+
# Define a tool
|
30
|
+
tool "greet" do
|
31
|
+
description "Greet someone by name"
|
32
|
+
argument :name, String, required: true, description: "Name to greet"
|
33
|
+
call do |args|
|
34
|
+
"Hello, #{args[:name]}!"
|
35
|
+
end
|
42
36
|
end
|
43
37
|
```
|
44
38
|
|
@@ -65,3 +59,30 @@ Find broken using `hello_world.rb`
|
|
65
59
|
```bash
|
66
60
|
bundle exec standardrb --fix
|
67
61
|
```
|
62
|
+
|
63
|
+
## Release
|
64
|
+
|
65
|
+
To release a new version:
|
66
|
+
|
67
|
+
1. Update version in `lib/mcp/version.rb`
|
68
|
+
2. Update `CHANGELOG.md`
|
69
|
+
3. Create a git tag
|
70
|
+
|
71
|
+
```bash
|
72
|
+
git add .
|
73
|
+
git commit -m "Release vx.y.z"
|
74
|
+
git tag vx.y.z
|
75
|
+
git push --tags
|
76
|
+
```
|
77
|
+
|
78
|
+
1. Build and push to RubyGems
|
79
|
+
|
80
|
+
```bash
|
81
|
+
gem build mcp-rb.gemspec
|
82
|
+
gem push mcp-rb-*.gem
|
83
|
+
```
|
84
|
+
|
85
|
+
## Changelog
|
86
|
+
|
87
|
+
See [CHANGELOG.md](CHANGELOG.md)
|
88
|
+
|
data/lib/mcp/app/resource.rb
CHANGED
@@ -3,14 +3,64 @@
|
|
3
3
|
module MCP
|
4
4
|
class App
|
5
5
|
module Resource
|
6
|
-
def
|
7
|
-
|
8
|
-
|
6
|
+
def resources
|
7
|
+
@resources ||= {}
|
8
|
+
end
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
10
|
+
class ResourceBuilder
|
11
|
+
attr_reader :uri, :name, :description, :mime_type, :handler
|
12
|
+
|
13
|
+
def initialize(uri)
|
14
|
+
raise ArgumentError, "Resource URI cannot be nil or empty" if uri.nil? || uri.empty?
|
15
|
+
@uri = uri
|
16
|
+
@name = ""
|
17
|
+
@description = ""
|
18
|
+
@mime_type = "text/plain"
|
19
|
+
@handler = nil
|
20
|
+
end
|
21
|
+
|
22
|
+
# standard:disable Lint/DuplicateMethods,Style/TrivialAccessors
|
23
|
+
def name(value)
|
24
|
+
@name = value
|
25
|
+
end
|
26
|
+
# standard:enable Lint/DuplicateMethods,Style/TrivialAccessors
|
27
|
+
|
28
|
+
# standard:disable Lint/DuplicateMethods,Style/TrivialAccessors
|
29
|
+
def description(text)
|
30
|
+
@description = text
|
31
|
+
end
|
32
|
+
# standard:enable Lint/DuplicateMethods,Style/TrivialAccessors
|
33
|
+
|
34
|
+
# standard:disable Lint/DuplicateMethods,Style/TrivialAccessors
|
35
|
+
def mime_type(value)
|
36
|
+
@mime_type = value
|
37
|
+
end
|
38
|
+
# standard:enable Lint/DuplicateMethods,Style/TrivialAccessors
|
39
|
+
|
40
|
+
def call(&block)
|
41
|
+
@handler = block
|
42
|
+
end
|
43
|
+
|
44
|
+
def to_resource_hash
|
45
|
+
raise ArgumentError, "Handler must be provided" unless @handler
|
46
|
+
raise ArgumentError, "Name must be provided" if @name.empty?
|
47
|
+
|
48
|
+
{
|
49
|
+
uri: @uri,
|
50
|
+
name: @name,
|
51
|
+
mime_type: @mime_type,
|
52
|
+
description: @description,
|
53
|
+
handler: @handler
|
54
|
+
}
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def register_resource(uri, &block)
|
59
|
+
builder = ResourceBuilder.new(uri)
|
60
|
+
builder.instance_eval(&block)
|
61
|
+
resource_hash = builder.to_resource_hash
|
62
|
+
resources[uri] = resource_hash
|
63
|
+
resource_hash
|
14
64
|
end
|
15
65
|
|
16
66
|
def list_resources(cursor: nil, page_size: nil)
|
@@ -52,10 +102,6 @@ module MCP
|
|
52
102
|
|
53
103
|
private
|
54
104
|
|
55
|
-
def resources
|
56
|
-
@resources ||= {}
|
57
|
-
end
|
58
|
-
|
59
105
|
def format_resource(resource)
|
60
106
|
{
|
61
107
|
uri: resource[:uri],
|
data/lib/mcp/app/tool.rb
CHANGED
@@ -3,16 +3,74 @@
|
|
3
3
|
module MCP
|
4
4
|
class App
|
5
5
|
module Tool
|
6
|
-
def
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
6
|
+
def tools
|
7
|
+
@tools ||= {}
|
8
|
+
end
|
9
|
+
|
10
|
+
class ToolBuilder
|
11
|
+
attr_reader :name, :description, :arguments, :handler
|
12
|
+
|
13
|
+
def initialize(name)
|
14
|
+
raise ArgumentError, "Tool name cannot be nil or empty" if name.nil? || name.empty?
|
15
|
+
@name = name
|
16
|
+
@description = ""
|
17
|
+
@arguments = {}
|
18
|
+
@required_arguments = []
|
19
|
+
@handler = nil
|
20
|
+
end
|
21
|
+
|
22
|
+
# standard:disable Lint/DuplicateMethods
|
23
|
+
def description(text = nil)
|
24
|
+
return @description if text.nil?
|
25
|
+
@description = text
|
26
|
+
end
|
27
|
+
# standard:enable Lint/DuplicateMethods
|
28
|
+
|
29
|
+
def argument(name, type, required: false, description: "")
|
30
|
+
@arguments[name] = {
|
31
|
+
type: ruby_type_to_schema_type(type),
|
32
|
+
description: description
|
33
|
+
}
|
34
|
+
@required_arguments << name if required
|
35
|
+
end
|
36
|
+
|
37
|
+
def call(&block)
|
38
|
+
@handler = block if block_given?
|
39
|
+
end
|
40
|
+
|
41
|
+
def to_tool_hash
|
42
|
+
raise ArgumentError, "Handler must be provided" unless @handler
|
43
|
+
{
|
44
|
+
name: @name,
|
45
|
+
description: @description,
|
46
|
+
input_schema: {
|
47
|
+
type: :object,
|
48
|
+
properties: @arguments,
|
49
|
+
required: @required_arguments
|
50
|
+
},
|
51
|
+
handler: @handler
|
52
|
+
}
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def ruby_type_to_schema_type(type)
|
58
|
+
case type.to_s
|
59
|
+
when "String" then :string
|
60
|
+
when "Integer" then :integer
|
61
|
+
when "Float" then :number
|
62
|
+
when "TrueClass", "FalseClass", "Boolean" then :boolean
|
63
|
+
else :object
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def register_tool(name, &block)
|
69
|
+
builder = ToolBuilder.new(name)
|
70
|
+
builder.instance_eval(&block)
|
71
|
+
tool_hash = builder.to_tool_hash
|
72
|
+
tools[name] = tool_hash
|
73
|
+
tool_hash
|
16
74
|
end
|
17
75
|
|
18
76
|
def list_tools(cursor: nil, page_size: 10)
|
@@ -32,6 +90,7 @@ module MCP
|
|
32
90
|
raise ArgumentError, "Tool not found: #{name}" unless tool
|
33
91
|
|
34
92
|
begin
|
93
|
+
validate_arguments(tool[:input_schema], arguments)
|
35
94
|
result = tool[:handler].call(arguments)
|
36
95
|
{
|
37
96
|
content: [
|
@@ -57,8 +116,14 @@ module MCP
|
|
57
116
|
|
58
117
|
private
|
59
118
|
|
60
|
-
def
|
61
|
-
|
119
|
+
def validate_arguments(schema, arguments)
|
120
|
+
return unless schema[:required]
|
121
|
+
|
122
|
+
schema[:required].each do |required_arg|
|
123
|
+
unless arguments.key?(required_arg)
|
124
|
+
raise ArgumentError, "missing keyword: :#{required_arg}"
|
125
|
+
end
|
126
|
+
end
|
62
127
|
end
|
63
128
|
|
64
129
|
def format_tool(tool)
|
data/lib/mcp/server.rb
CHANGED
@@ -23,12 +23,12 @@ module MCP
|
|
23
23
|
@name = value
|
24
24
|
end
|
25
25
|
|
26
|
-
def tool(name,
|
27
|
-
@app.register_tool(name,
|
26
|
+
def tool(name, &block)
|
27
|
+
@app.register_tool(name, &block)
|
28
28
|
end
|
29
29
|
|
30
|
-
def resource(uri,
|
31
|
-
@app.register_resource(uri,
|
30
|
+
def resource(uri, &block)
|
31
|
+
@app.register_resource(uri, &block)
|
32
32
|
end
|
33
33
|
|
34
34
|
def run
|
data/lib/mcp/version.rb
CHANGED
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mcp-rb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- funwarioisii
|
8
8
|
bindir: bin
|
9
9
|
cert_chain: []
|
10
|
-
date: 2025-02-
|
10
|
+
date: 2025-02-14 00:00:00.000000000 Z
|
11
11
|
dependencies: []
|
12
12
|
description: MCP-RB is a Ruby framework that provides a Sinatra-like DSL for implementing
|
13
13
|
Model Context Protocol servers.
|