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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 610a73e9025b6400f091beeec7e0e0b9b51e917ba57b068f7132fd2dad3fa207
4
- data.tar.gz: 8a5533dd1abdb1fbdde067facfe0ceeeb50d9fac332ba4ec4c4815a9b8f1a199
3
+ metadata.gz: 28e6b1fc53252ecd7717e71d06f0c124c61a8fbb9e389fa9514f3249b056930e
4
+ data.tar.gz: 454af20d33b8cbe80dad61214b0ca3680a8715bef024d4d26dd77a5b800e37ba
5
5
  SHA512:
6
- metadata.gz: be76a1399e5121d0e0886489630fe7695b9fba3cea55835d6da2d67d5b74d3a714f68c354dbf447e8953f965c0c65e416e12417ee109fe4695f47cc4c940bdc6
7
- data.tar.gz: d0ec9f439c4bc497c264241000269b7c5928167f0623a3a34335e6c28b597c95967b38819051a954f96323e861ea6553d218bc639df7b52697185463da1ac158
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: "Hello World",
25
- description: "A simple hello world message" do
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 "greet",
30
- description: "Greet someone by name",
31
- input_schema: {
32
- type: :object,
33
- properties: {
34
- name: {
35
- type: :string,
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
+
@@ -3,14 +3,64 @@
3
3
  module MCP
4
4
  class App
5
5
  module Resource
6
- def register_resource(uri, name:, mime_type: "text/plain", description: "", &block)
7
- raise ArgumentError, "Resource name cannot be nil or empty" if uri.nil? || uri.empty?
8
- raise ArgumentError, "Block must be provided" unless block_given?
6
+ def resources
7
+ @resources ||= {}
8
+ end
9
9
 
10
- resources[uri] = {
11
- uri:, name:, mime_type:, description:,
12
- handler: block
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 register_tool(name, description: "", input_schema: {}, &block)
7
- raise ArgumentError, "Tool name cannot be nil or empty" if name.nil? || name.empty?
8
- raise ArgumentError, "Block must be provided" unless block_given?
9
-
10
- tools[name] = {
11
- name: name,
12
- description: description,
13
- input_schema: input_schema,
14
- handler: block
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 tools
61
- @tools ||= {}
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, description: "", input_schema: {}, &block)
27
- @app.register_tool(name, description: description, input_schema: input_schema, &block)
26
+ def tool(name, &block)
27
+ @app.register_tool(name, &block)
28
28
  end
29
29
 
30
- def resource(uri, name:, mime_type: "text/plain", description: "", &block)
31
- @app.register_resource(uri, name: name, mime_type: mime_type, description: description, &block)
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
@@ -2,5 +2,5 @@
2
2
 
3
3
  module MCP
4
4
  PROTOCOL_VERSION = "2024-11-05"
5
- VERSION = "0.1.0"
5
+ VERSION = "0.2.0"
6
6
  end
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.1.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-12 00:00:00.000000000 Z
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.