model-context-protocol-rb 0.3.1 → 0.3.2
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 +8 -1
- data/README.md +105 -56
- data/lib/model_context_protocol/server/completion.rb +45 -0
- data/lib/model_context_protocol/server/prompt.rb +65 -10
- data/lib/model_context_protocol/server/registry.rb +22 -0
- data/lib/model_context_protocol/server/resource.rb +29 -6
- data/lib/model_context_protocol/server/resource_template.rb +93 -0
- data/lib/model_context_protocol/server/tool.rb +22 -4
- data/lib/model_context_protocol/server.rb +36 -2
- data/lib/model_context_protocol/version.rb +1 -1
- data/lib/model_context_protocol.rb +1 -1
- data/tasks/templates/dev.erb +4 -0
- metadata +18 -2
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 99ee11ebae0c9c984a15954b386e89489f6715a1d371b288ece0438d066436d7
         | 
| 4 | 
            +
              data.tar.gz: cdf41e8742941e9a0a41c714127d02f5a189d901a95a35e6f61a16f1f7b8a704
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: aad64bd6e42b2ecea2b742bb23b902ea1bfae3e77cffc5009b0a83712df7efac417b680bb460649bb73fff31d2d554d33a17d6fe96adb35f3cc9d0addbbcf9be
         | 
| 7 | 
            +
              data.tar.gz: 6fa834a1c2bf4494748474dc26a29bede650b1a1913c7c543a7c195fd24fe99eda5f1610c40a63067f454b50f669b1fb47030e106fa6ba80cbde522bccfb9518
         | 
    
        data/CHANGELOG.md
    CHANGED
    
    | @@ -1,5 +1,11 @@ | |
| 1 1 | 
             
            ## [Unreleased]
         | 
| 2 2 |  | 
| 3 | 
            +
            ## [0.3.2] - 2025-05-10
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            - Added resource template support.
         | 
| 6 | 
            +
            - Added completion support for prompts and resources.
         | 
| 7 | 
            +
            - Improved metadata definition for prompts, resources, and tools using simple DSL.
         | 
| 8 | 
            +
             | 
| 3 9 | 
             
            ## [0.3.1] - 2025-04-04
         | 
| 4 10 |  | 
| 5 11 | 
             
            - Added support for environment variables to MCP servers (thanks @hmk):
         | 
| @@ -31,7 +37,8 @@ | |
| 31 37 |  | 
| 32 38 | 
             
            - Initial release
         | 
| 33 39 |  | 
| 34 | 
            -
            [Unreleased]: https://github.com/dickdavis/model-context-protocol-rb/compare/v0.3. | 
| 40 | 
            +
            [Unreleased]: https://github.com/dickdavis/model-context-protocol-rb/compare/v0.3.2...HEAD
         | 
| 41 | 
            +
            [0.3.1]: https://github.com/dickdavis/model-context-protocol-rb/compare/v0.3.1...v0.3.2
         | 
| 35 42 | 
             
            [0.3.1]: https://github.com/dickdavis/model-context-protocol-rb/compare/v0.3.0...v0.3.1
         | 
| 36 43 | 
             
            [0.3.0]: https://github.com/dickdavis/model-context-protocol-rb/compare/v0.2.0...v0.3.0
         | 
| 37 44 | 
             
            [0.2.0]: https://github.com/dickdavis/model-context-protocol-rb/compare/v0.1.0...v0.2.0
         | 
    
        data/README.md
    CHANGED
    
    | @@ -8,13 +8,10 @@ You are welcome to contribute. | |
| 8 8 |  | 
| 9 9 | 
             
            TODO's:
         | 
| 10 10 |  | 
| 11 | 
            -
            * [Completion](https://spec.modelcontextprotocol.io/specification/2024-11-05/server/utilities/completion/)
         | 
| 12 | 
            -
            * [Logging](https://spec.modelcontextprotocol.io/specification/2024-11-05/server/utilities/logging/)
         | 
| 13 11 | 
             
            * [Pagination](https://spec.modelcontextprotocol.io/specification/2024-11-05/server/utilities/pagination/)
         | 
| 14 12 | 
             
            * [Prompt list changed notifications](https://spec.modelcontextprotocol.io/specification/2024-11-05/server/prompts/#list-changed-notification)
         | 
| 15 13 | 
             
            * [Resource list changed notifications](https://spec.modelcontextprotocol.io/specification/2024-11-05/server/resources/#list-changed-notification)
         | 
| 16 14 | 
             
            * [Resource subscriptions](https://spec.modelcontextprotocol.io/specification/2024-11-05/server/resources/#subscriptions)
         | 
| 17 | 
            -
            * [Resource templates](https://spec.modelcontextprotocol.io/specification/2024-11-05/server/resources/#resource-templates)
         | 
| 18 15 | 
             
            * [Tool list changed notifications](https://spec.modelcontextprotocol.io/specification/2024-11-05/server/tools/#list-changed-notification)
         | 
| 19 16 |  | 
| 20 17 | 
             
            ## Usage
         | 
| @@ -27,7 +24,7 @@ require 'model_context_protocol' | |
| 27 24 |  | 
| 28 25 | 
             
            ### Building an MCP Server
         | 
| 29 26 |  | 
| 30 | 
            -
            Build a simple MCP server by registering your prompts, resources, and tools. Then, configure and run the server.
         | 
| 27 | 
            +
            Build a simple MCP server by registering your prompts, resources, resource templates, and tools. Then, configure and run the server.
         | 
| 31 28 |  | 
| 32 29 | 
             
            ```ruby
         | 
| 33 30 | 
             
            server = ModelContextProtocol::Server.new do |config|
         | 
| @@ -51,6 +48,10 @@ server = ModelContextProtocol::Server.new do |config| | |
| 51 48 | 
             
                  register TestResource
         | 
| 52 49 | 
             
                end
         | 
| 53 50 |  | 
| 51 | 
            +
                resource_templates do
         | 
| 52 | 
            +
                  register TestResourceTemplate
         | 
| 53 | 
            +
                end
         | 
| 54 | 
            +
             | 
| 54 55 | 
             
                tools list_changed: true do
         | 
| 55 56 | 
             
                  register TestTool
         | 
| 56 57 | 
             
                end
         | 
| @@ -62,10 +63,12 @@ server.start | |
| 62 63 |  | 
| 63 64 | 
             
            Messages from the MCP client will be routed to the appropriate custom handler. This SDK provides several classes that should be used to build your handlers.
         | 
| 64 65 |  | 
| 65 | 
            -
            ####  | 
| 66 | 
            +
            #### Prompts
         | 
| 66 67 |  | 
| 67 68 | 
             
            The `ModelContextProtocol::Server::Prompt` base class allows subclasses to define a prompt that the MCP client can use. Define the [appropriate metadata](https://spec.modelcontextprotocol.io/specification/2024-11-05/server/prompts/) in the `with_metadata` block.
         | 
| 68 69 |  | 
| 70 | 
            +
            Define any arguments using the `with_argument` block. You can mark an argument as required, and you can optionally provide the class name of a service object that provides completions. See [Completions](#completions) for more information.
         | 
| 71 | 
            +
             | 
| 69 72 | 
             
            Then implement the `call` method to build your prompt. Use the `respond_with` instance method to ensure your prompt responds with appropriately formatted response data.
         | 
| 70 73 |  | 
| 71 74 | 
             
            This is an example prompt that returns a properly formatted response:
         | 
| @@ -73,22 +76,21 @@ This is an example prompt that returns a properly formatted response: | |
| 73 76 | 
             
            ```ruby
         | 
| 74 77 | 
             
            class TestPrompt < ModelContextProtocol::Server::Prompt
         | 
| 75 78 | 
             
              with_metadata do
         | 
| 76 | 
            -
                 | 
| 77 | 
            -
             | 
| 78 | 
            -
             | 
| 79 | 
            -
             | 
| 80 | 
            -
             | 
| 81 | 
            -
             | 
| 82 | 
            -
             | 
| 83 | 
            -
             | 
| 84 | 
            -
             | 
| 85 | 
            -
             | 
| 86 | 
            -
             | 
| 87 | 
            -
             | 
| 88 | 
            -
             | 
| 89 | 
            -
             | 
| 90 | 
            -
             | 
| 91 | 
            -
                }
         | 
| 79 | 
            +
                name "test_prompt"
         | 
| 80 | 
            +
                description "A test prompt"
         | 
| 81 | 
            +
              end
         | 
| 82 | 
            +
             | 
| 83 | 
            +
              with_argument do
         | 
| 84 | 
            +
                name "message"
         | 
| 85 | 
            +
                description "The thing to do"
         | 
| 86 | 
            +
                required true
         | 
| 87 | 
            +
                completion TestCompletion
         | 
| 88 | 
            +
              end
         | 
| 89 | 
            +
             | 
| 90 | 
            +
              with_argument do
         | 
| 91 | 
            +
                name "other"
         | 
| 92 | 
            +
                description "Another thing to do"
         | 
| 93 | 
            +
                required false
         | 
| 92 94 | 
             
              end
         | 
| 93 95 |  | 
| 94 96 | 
             
              def call
         | 
| @@ -107,7 +109,7 @@ class TestPrompt < ModelContextProtocol::Server::Prompt | |
| 107 109 | 
             
            end
         | 
| 108 110 | 
             
            ```
         | 
| 109 111 |  | 
| 110 | 
            -
            ####  | 
| 112 | 
            +
            #### Resources
         | 
| 111 113 |  | 
| 112 114 | 
             
            The `ModelContextProtocol::Server::Resource` base class allows subclasses to define a resource that the MCP client can use. Define the [appropriate metadata](https://spec.modelcontextprotocol.io/specification/2024-11-05/server/resources/) in the `with_metadata` block.
         | 
| 113 115 |  | 
| @@ -118,12 +120,10 @@ This is an example resource that returns a text response: | |
| 118 120 | 
             
            ```ruby
         | 
| 119 121 | 
             
            class TestResource < ModelContextProtocol::Server::Resource
         | 
| 120 122 | 
             
              with_metadata do
         | 
| 121 | 
            -
                 | 
| 122 | 
            -
             | 
| 123 | 
            -
             | 
| 124 | 
            -
             | 
| 125 | 
            -
                  uri: "resource://test-resource"
         | 
| 126 | 
            -
                }
         | 
| 123 | 
            +
                name "Test Resource"
         | 
| 124 | 
            +
                description "A test resource"
         | 
| 125 | 
            +
                mime_type "text/plain"
         | 
| 126 | 
            +
                uri "resource://test-resource"
         | 
| 127 127 | 
             
              end
         | 
| 128 128 |  | 
| 129 129 | 
             
              def call
         | 
| @@ -137,12 +137,10 @@ This is an example resource that returns binary data: | |
| 137 137 | 
             
            ```ruby
         | 
| 138 138 | 
             
            class TestBinaryResource < ModelContextProtocol::Server::Resource
         | 
| 139 139 | 
             
              with_metadata do
         | 
| 140 | 
            -
                 | 
| 141 | 
            -
             | 
| 142 | 
            -
             | 
| 143 | 
            -
             | 
| 144 | 
            -
                  uri: "resource://project-logo"
         | 
| 145 | 
            -
                }
         | 
| 140 | 
            +
                name "Project Logo"
         | 
| 141 | 
            +
                description "The logo for the project"
         | 
| 142 | 
            +
                mime_type "image/jpeg"
         | 
| 143 | 
            +
                uri "resource://project-logo"
         | 
| 146 144 | 
             
              end
         | 
| 147 145 |  | 
| 148 146 | 
             
              def call
         | 
| @@ -153,7 +151,37 @@ class TestBinaryResource < ModelContextProtocol::Server::Resource | |
| 153 151 | 
             
            end
         | 
| 154 152 | 
             
            ```
         | 
| 155 153 |  | 
| 156 | 
            -
            ####  | 
| 154 | 
            +
            #### Resource Templates
         | 
| 155 | 
            +
             | 
| 156 | 
            +
            The `ModelContextProtocol::Server::ResourceTemplate` base class allows subclasses to define a resource template that the MCP client can use. Define the [appropriate metadata](https://modelcontextprotocol.io/specification/2024-11-05/server/resources#resource-templates) in the `with_metadata` block.
         | 
| 157 | 
            +
             | 
| 158 | 
            +
            This is an example resource template that provides a completion for a parameter of the URI template:
         | 
| 159 | 
            +
             | 
| 160 | 
            +
            ```ruby
         | 
| 161 | 
            +
            class TestResourceTemplateCompletion < ModelContextProtocol::Server::Completion
         | 
| 162 | 
            +
              def call
         | 
| 163 | 
            +
                hints = {
         | 
| 164 | 
            +
                  "name" => ["test-resource", "project-logo"]
         | 
| 165 | 
            +
                }
         | 
| 166 | 
            +
                values = hints[argument_name].grep(/#{argument_value}/)
         | 
| 167 | 
            +
             | 
| 168 | 
            +
                respond_with values:
         | 
| 169 | 
            +
              end
         | 
| 170 | 
            +
            end
         | 
| 171 | 
            +
             | 
| 172 | 
            +
            class TestResourceTemplate < ModelContextProtocol::Server::ResourceTemplate
         | 
| 173 | 
            +
              with_metadata do
         | 
| 174 | 
            +
                name "Test Resource Template"
         | 
| 175 | 
            +
                description "A test resource template"
         | 
| 176 | 
            +
                mime_type "text/plain"
         | 
| 177 | 
            +
                uri_template "resource://{name}" do
         | 
| 178 | 
            +
                  completion :name, TestResourceTemplateCompletion
         | 
| 179 | 
            +
                end
         | 
| 180 | 
            +
              end
         | 
| 181 | 
            +
            end
         | 
| 182 | 
            +
            ```
         | 
| 183 | 
            +
             | 
| 184 | 
            +
            #### Tools
         | 
| 157 185 |  | 
| 158 186 | 
             
            The `ModelContextProtocol::Server::Tool` base class allows subclasses to define a tool that the MCP client can use. Define the [appropriate metadata](https://spec.modelcontextprotocol.io/specification/2024-11-05/server/tools/) in the `with_metadata` block.
         | 
| 159 187 |  | 
| @@ -164,19 +192,19 @@ This is an example tool that returns a text response: | |
| 164 192 | 
             
            ```ruby
         | 
| 165 193 | 
             
            class TestToolWithTextResponse < ModelContextProtocol::Server::Tool
         | 
| 166 194 | 
             
              with_metadata do
         | 
| 167 | 
            -
                 | 
| 168 | 
            -
             | 
| 169 | 
            -
             | 
| 170 | 
            -
                   | 
| 195 | 
            +
                name "double"
         | 
| 196 | 
            +
                description "Doubles the provided number"
         | 
| 197 | 
            +
                input_schema do
         | 
| 198 | 
            +
                  {
         | 
| 171 199 | 
             
                    type: "object",
         | 
| 172 200 | 
             
                    properties: {
         | 
| 173 201 | 
             
                      number: {
         | 
| 174 | 
            -
                        type: "string" | 
| 202 | 
            +
                        type: "string"
         | 
| 175 203 | 
             
                      }
         | 
| 176 204 | 
             
                    },
         | 
| 177 205 | 
             
                    required: ["number"]
         | 
| 178 206 | 
             
                  }
         | 
| 179 | 
            -
                 | 
| 207 | 
            +
                end
         | 
| 180 208 | 
             
              end
         | 
| 181 209 |  | 
| 182 210 | 
             
              def call
         | 
| @@ -192,10 +220,10 @@ This is an example of a tool that returns an image: | |
| 192 220 | 
             
            ```ruby
         | 
| 193 221 | 
             
            class TestToolWithImageResponse < ModelContextProtocol::Server::Tool
         | 
| 194 222 | 
             
              with_metadata do
         | 
| 195 | 
            -
                 | 
| 196 | 
            -
             | 
| 197 | 
            -
             | 
| 198 | 
            -
                   | 
| 223 | 
            +
                name "custom-chart-generator"
         | 
| 224 | 
            +
                description "Generates a chart in various formats"
         | 
| 225 | 
            +
                input_schema do
         | 
| 226 | 
            +
                  {
         | 
| 199 227 | 
             
                    type: "object",
         | 
| 200 228 | 
             
                    properties: {
         | 
| 201 229 | 
             
                      chart_type: {
         | 
| @@ -209,7 +237,7 @@ class TestToolWithImageResponse < ModelContextProtocol::Server::Tool | |
| 209 237 | 
             
                    },
         | 
| 210 238 | 
             
                    required: ["chart_type", "format"]
         | 
| 211 239 | 
             
                  }
         | 
| 212 | 
            -
                 | 
| 240 | 
            +
                end
         | 
| 213 241 | 
             
              end
         | 
| 214 242 |  | 
| 215 243 | 
             
              def call
         | 
| @@ -236,10 +264,10 @@ If you don't provide a mime type, it will default to `image/png`. | |
| 236 264 | 
             
            ```ruby
         | 
| 237 265 | 
             
            class TestToolWithImageResponseDefaultMimeType < ModelContextProtocol::Server::Tool
         | 
| 238 266 | 
             
              with_metadata do
         | 
| 239 | 
            -
                 | 
| 240 | 
            -
             | 
| 241 | 
            -
             | 
| 242 | 
            -
                   | 
| 267 | 
            +
                name "other-custom-chart-generator"
         | 
| 268 | 
            +
                description "Generates a chart"
         | 
| 269 | 
            +
                input_schema do
         | 
| 270 | 
            +
                  {
         | 
| 243 271 | 
             
                    type: "object",
         | 
| 244 272 | 
             
                    properties: {
         | 
| 245 273 | 
             
                      chart_type: {
         | 
| @@ -249,7 +277,7 @@ class TestToolWithImageResponseDefaultMimeType < ModelContextProtocol::Server::T | |
| 249 277 | 
             
                    },
         | 
| 250 278 | 
             
                    required: ["chart_type"]
         | 
| 251 279 | 
             
                  }
         | 
| 252 | 
            -
                 | 
| 280 | 
            +
                end
         | 
| 253 281 | 
             
              end
         | 
| 254 282 |  | 
| 255 283 | 
             
              def call
         | 
| @@ -266,10 +294,10 @@ This is an example of a tool that returns a resource response: | |
| 266 294 | 
             
            ```ruby
         | 
| 267 295 | 
             
            class TestToolWithResourceResponse < ModelContextProtocol::Server::Tool
         | 
| 268 296 | 
             
              with_metadata do
         | 
| 269 | 
            -
                 | 
| 270 | 
            -
             | 
| 271 | 
            -
             | 
| 272 | 
            -
                   | 
| 297 | 
            +
                name "document-finder"
         | 
| 298 | 
            +
                description "Finds a the document with the given title"
         | 
| 299 | 
            +
                input_schema do
         | 
| 300 | 
            +
                  {
         | 
| 273 301 | 
             
                    type: "object",
         | 
| 274 302 | 
             
                    properties: {
         | 
| 275 303 | 
             
                      title: {
         | 
| @@ -279,7 +307,7 @@ class TestToolWithResourceResponse < ModelContextProtocol::Server::Tool | |
| 279 307 | 
             
                    },
         | 
| 280 308 | 
             
                    required: ["title"]
         | 
| 281 309 | 
             
                  }
         | 
| 282 | 
            -
                 | 
| 310 | 
            +
                end
         | 
| 283 311 | 
             
              end
         | 
| 284 312 |  | 
| 285 313 | 
             
              def call
         | 
| @@ -291,6 +319,27 @@ class TestToolWithResourceResponse < ModelContextProtocol::Server::Tool | |
| 291 319 | 
             
            end
         | 
| 292 320 | 
             
            ```
         | 
| 293 321 |  | 
| 322 | 
            +
            ### Completions
         | 
| 323 | 
            +
             | 
| 324 | 
            +
            The `ModelContextProtocol::Server::Completion` base class allows subclasses to define a completion that the MCP client can use to obtain hints or suggestions for arguments to prompts and resources.
         | 
| 325 | 
            +
             | 
| 326 | 
            +
            implement the `call` method to build your completion. Use the `respond_with` instance method to ensure your completion responds with appropriately formatted response data.
         | 
| 327 | 
            +
             | 
| 328 | 
            +
            This is an example completion that returns an array of values in the response:
         | 
| 329 | 
            +
             | 
| 330 | 
            +
            ```ruby
         | 
| 331 | 
            +
            class TestCompletion < ModelContextProtocol::Server::Completion
         | 
| 332 | 
            +
              def call
         | 
| 333 | 
            +
                hints = {
         | 
| 334 | 
            +
                  "message" => ["hello", "world", "foo", "bar"]
         | 
| 335 | 
            +
                }
         | 
| 336 | 
            +
                values = hints[argument_name].grep(/#{argument_value}/)
         | 
| 337 | 
            +
             | 
| 338 | 
            +
                respond_with values:
         | 
| 339 | 
            +
              end
         | 
| 340 | 
            +
            end
         | 
| 341 | 
            +
            ```
         | 
| 342 | 
            +
             | 
| 294 343 | 
             
            ## Installation
         | 
| 295 344 |  | 
| 296 345 | 
             
            Add this line to your application's Gemfile:
         | 
| @@ -0,0 +1,45 @@ | |
| 1 | 
            +
            module ModelContextProtocol
         | 
| 2 | 
            +
              class Server::Completion
         | 
| 3 | 
            +
                attr_reader :argument_name, :argument_value
         | 
| 4 | 
            +
             | 
| 5 | 
            +
                def initialize(argument_name, argument_value)
         | 
| 6 | 
            +
                  @argument_name = argument_name
         | 
| 7 | 
            +
                  @argument_value = argument_value
         | 
| 8 | 
            +
                end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                def call
         | 
| 11 | 
            +
                  raise NotImplementedError, "Subclasses must implement the call method"
         | 
| 12 | 
            +
                end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                def self.call(...)
         | 
| 15 | 
            +
                  new(...).call
         | 
| 16 | 
            +
                end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                private
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                Response = Data.define(:values, :total, :hasMore) do
         | 
| 21 | 
            +
                  def serialized
         | 
| 22 | 
            +
                    {completion: {values:, total:, hasMore:}}
         | 
| 23 | 
            +
                  end
         | 
| 24 | 
            +
                end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                def respond_with(values:)
         | 
| 27 | 
            +
                  values_to_return = values.take(100)
         | 
| 28 | 
            +
                  total = values.size
         | 
| 29 | 
            +
                  has_more = values_to_return.size != total
         | 
| 30 | 
            +
                  Response[values:, total:, hasMore: has_more]
         | 
| 31 | 
            +
                end
         | 
| 32 | 
            +
              end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
              class Server::NullCompletion
         | 
| 35 | 
            +
                Response = Data.define(:values, :total, :hasMore) do
         | 
| 36 | 
            +
                  def serialized
         | 
| 37 | 
            +
                    {completion: {values:, total:, hasMore:}}
         | 
| 38 | 
            +
                  end
         | 
| 39 | 
            +
                end
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                def self.call(_argument_name, _argument_value)
         | 
| 42 | 
            +
                  Response[values: [], total: 0, hasMore: false]
         | 
| 43 | 
            +
                end
         | 
| 44 | 
            +
              end
         | 
| 45 | 
            +
            end
         | 
| @@ -1,10 +1,9 @@ | |
| 1 1 | 
             
            module ModelContextProtocol
         | 
| 2 2 | 
             
              class Server::Prompt
         | 
| 3 | 
            -
                attr_reader :params | 
| 3 | 
            +
                attr_reader :params
         | 
| 4 4 |  | 
| 5 5 | 
             
                def initialize(params)
         | 
| 6 6 | 
             
                  validate!(params)
         | 
| 7 | 
            -
                  @description = self.class.description
         | 
| 8 7 | 
             
                  @params = params
         | 
| 9 8 | 
             
                end
         | 
| 10 9 |  | 
| @@ -12,15 +11,15 @@ module ModelContextProtocol | |
| 12 11 | 
             
                  raise NotImplementedError, "Subclasses must implement the call method"
         | 
| 13 12 | 
             
                end
         | 
| 14 13 |  | 
| 15 | 
            -
                Response = Data.define(:messages, : | 
| 14 | 
            +
                Response = Data.define(:messages, :description) do
         | 
| 16 15 | 
             
                  def serialized
         | 
| 17 | 
            -
                    {description | 
| 16 | 
            +
                    {description:, messages:}
         | 
| 18 17 | 
             
                  end
         | 
| 19 18 | 
             
                end
         | 
| 20 19 | 
             
                private_constant :Response
         | 
| 21 20 |  | 
| 22 21 | 
             
                private def respond_with(messages:)
         | 
| 23 | 
            -
                  Response[messages:,  | 
| 22 | 
            +
                  Response[messages:, description: self.class.description]
         | 
| 24 23 | 
             
                end
         | 
| 25 24 |  | 
| 26 25 | 
             
                private def validate!(params = {})
         | 
| @@ -45,17 +44,33 @@ module ModelContextProtocol | |
| 45 44 | 
             
                  attr_reader :name, :description, :arguments
         | 
| 46 45 |  | 
| 47 46 | 
             
                  def with_metadata(&block)
         | 
| 48 | 
            -
                     | 
| 47 | 
            +
                    @arguments ||= []
         | 
| 49 48 |  | 
| 50 | 
            -
                     | 
| 51 | 
            -
                     | 
| 52 | 
            -
             | 
| 49 | 
            +
                    metadata_dsl = MetadataDSL.new
         | 
| 50 | 
            +
                    metadata_dsl.instance_eval(&block)
         | 
| 51 | 
            +
             | 
| 52 | 
            +
                    @name = metadata_dsl.name
         | 
| 53 | 
            +
                    @description = metadata_dsl.description
         | 
| 54 | 
            +
                  end
         | 
| 55 | 
            +
             | 
| 56 | 
            +
                  def with_argument(&block)
         | 
| 57 | 
            +
                    @arguments ||= []
         | 
| 58 | 
            +
             | 
| 59 | 
            +
                    argument_dsl = ArgumentDSL.new
         | 
| 60 | 
            +
                    argument_dsl.instance_eval(&block)
         | 
| 61 | 
            +
             | 
| 62 | 
            +
                    @arguments << {
         | 
| 63 | 
            +
                      name: argument_dsl.name,
         | 
| 64 | 
            +
                      description: argument_dsl.description,
         | 
| 65 | 
            +
                      required: argument_dsl.required,
         | 
| 66 | 
            +
                      completion: argument_dsl.completion
         | 
| 67 | 
            +
                    }
         | 
| 53 68 | 
             
                  end
         | 
| 54 69 |  | 
| 55 70 | 
             
                  def inherited(subclass)
         | 
| 56 71 | 
             
                    subclass.instance_variable_set(:@name, @name)
         | 
| 57 72 | 
             
                    subclass.instance_variable_set(:@description, @description)
         | 
| 58 | 
            -
                    subclass.instance_variable_set(:@arguments, @arguments)
         | 
| 73 | 
            +
                    subclass.instance_variable_set(:@arguments, @arguments&.dup)
         | 
| 59 74 | 
             
                  end
         | 
| 60 75 |  | 
| 61 76 | 
             
                  def call(params)
         | 
| @@ -67,6 +82,46 @@ module ModelContextProtocol | |
| 67 82 | 
             
                  def metadata
         | 
| 68 83 | 
             
                    {name: @name, description: @description, arguments: @arguments}
         | 
| 69 84 | 
             
                  end
         | 
| 85 | 
            +
             | 
| 86 | 
            +
                  def complete_for(arg_name, value)
         | 
| 87 | 
            +
                    arg = @arguments&.find { |a| a[:name] == arg_name.to_s }
         | 
| 88 | 
            +
                    completion = (arg && arg[:completion]) ? arg[:completion] : ModelContextProtocol::Server::NullCompletion
         | 
| 89 | 
            +
                    completion.call(arg_name.to_s, value)
         | 
| 90 | 
            +
                  end
         | 
| 91 | 
            +
                end
         | 
| 92 | 
            +
             | 
| 93 | 
            +
                class MetadataDSL
         | 
| 94 | 
            +
                  def name(value = nil)
         | 
| 95 | 
            +
                    @name = value if value
         | 
| 96 | 
            +
                    @name
         | 
| 97 | 
            +
                  end
         | 
| 98 | 
            +
             | 
| 99 | 
            +
                  def description(value = nil)
         | 
| 100 | 
            +
                    @description = value if value
         | 
| 101 | 
            +
                    @description
         | 
| 102 | 
            +
                  end
         | 
| 103 | 
            +
                end
         | 
| 104 | 
            +
             | 
| 105 | 
            +
                class ArgumentDSL
         | 
| 106 | 
            +
                  def name(value = nil)
         | 
| 107 | 
            +
                    @name = value if value
         | 
| 108 | 
            +
                    @name
         | 
| 109 | 
            +
                  end
         | 
| 110 | 
            +
             | 
| 111 | 
            +
                  def description(value = nil)
         | 
| 112 | 
            +
                    @description = value if value
         | 
| 113 | 
            +
                    @description
         | 
| 114 | 
            +
                  end
         | 
| 115 | 
            +
             | 
| 116 | 
            +
                  def required(value = nil)
         | 
| 117 | 
            +
                    @required = value unless value.nil?
         | 
| 118 | 
            +
                    @required
         | 
| 119 | 
            +
                  end
         | 
| 120 | 
            +
             | 
| 121 | 
            +
                  def completion(klass = nil)
         | 
| 122 | 
            +
                    @completion = klass unless klass.nil?
         | 
| 123 | 
            +
                    @completion
         | 
| 124 | 
            +
                  end
         | 
| 70 125 | 
             
                end
         | 
| 71 126 | 
             
              end
         | 
| 72 127 | 
             
            end
         | 
| @@ -12,6 +12,7 @@ module ModelContextProtocol | |
| 12 12 | 
             
                def initialize
         | 
| 13 13 | 
             
                  @prompts = []
         | 
| 14 14 | 
             
                  @resources = []
         | 
| 15 | 
            +
                  @resource_templates = []
         | 
| 15 16 | 
             
                  @tools = []
         | 
| 16 17 | 
             
                  @prompts_options = {}
         | 
| 17 18 | 
             
                  @resources_options = {}
         | 
| @@ -28,6 +29,10 @@ module ModelContextProtocol | |
| 28 29 | 
             
                  instance_eval(&block) if block
         | 
| 29 30 | 
             
                end
         | 
| 30 31 |  | 
| 32 | 
            +
                def resource_templates(&block)
         | 
| 33 | 
            +
                  instance_eval(&block) if block
         | 
| 34 | 
            +
                end
         | 
| 35 | 
            +
             | 
| 31 36 | 
             
                def tools(options = {}, &block)
         | 
| 32 37 | 
             
                  @tools_options = options
         | 
| 33 38 | 
             
                  instance_eval(&block) if block
         | 
| @@ -42,6 +47,8 @@ module ModelContextProtocol | |
| 42 47 | 
             
                    @prompts << entry
         | 
| 43 48 | 
             
                  when ->(ancestors) { ancestors.include?(ModelContextProtocol::Server::Resource) }
         | 
| 44 49 | 
             
                    @resources << entry
         | 
| 50 | 
            +
                  when ->(ancestors) { ancestors.include?(ModelContextProtocol::Server::ResourceTemplate) }
         | 
| 51 | 
            +
                    @resource_templates << entry
         | 
| 45 52 | 
             
                  when ->(ancestors) { ancestors.include?(ModelContextProtocol::Server::Tool) }
         | 
| 46 53 | 
             
                    @tools << entry
         | 
| 47 54 | 
             
                  else
         | 
| @@ -58,6 +65,11 @@ module ModelContextProtocol | |
| 58 65 | 
             
                  entry ? entry[:klass] : nil
         | 
| 59 66 | 
             
                end
         | 
| 60 67 |  | 
| 68 | 
            +
                def find_resource_template(uri)
         | 
| 69 | 
            +
                  entry = @resource_templates.find { |r| uri == r[:uriTemplate] }
         | 
| 70 | 
            +
                  entry ? entry[:klass] : nil
         | 
| 71 | 
            +
                end
         | 
| 72 | 
            +
             | 
| 61 73 | 
             
                def find_tool(name)
         | 
| 62 74 | 
             
                  find_by_name(@tools, name)
         | 
| 63 75 | 
             
                end
         | 
| @@ -70,6 +82,10 @@ module ModelContextProtocol | |
| 70 82 | 
             
                  ResourcesData[resources: @resources.map { |entry| entry.except(:klass) }]
         | 
| 71 83 | 
             
                end
         | 
| 72 84 |  | 
| 85 | 
            +
                def resource_templates_data
         | 
| 86 | 
            +
                  ResourceTemplatesData[resource_templates: @resource_templates.map { |entry| entry.except(:klass, :completions) }]
         | 
| 87 | 
            +
                end
         | 
| 88 | 
            +
             | 
| 73 89 | 
             
                def tools_data
         | 
| 74 90 | 
             
                  ToolsData[tools: @tools.map { |entry| entry.except(:klass) }]
         | 
| 75 91 | 
             
                end
         | 
| @@ -88,6 +104,12 @@ module ModelContextProtocol | |
| 88 104 | 
             
                  end
         | 
| 89 105 | 
             
                end
         | 
| 90 106 |  | 
| 107 | 
            +
                ResourceTemplatesData = Data.define(:resource_templates) do
         | 
| 108 | 
            +
                  def serialized
         | 
| 109 | 
            +
                    {resourceTemplates: resource_templates}
         | 
| 110 | 
            +
                  end
         | 
| 111 | 
            +
                end
         | 
| 112 | 
            +
             | 
| 91 113 | 
             
                ToolsData = Data.define(:tools) do
         | 
| 92 114 | 
             
                  def serialized
         | 
| 93 115 | 
             
                    {tools:}
         | 
| @@ -40,12 +40,13 @@ module ModelContextProtocol | |
| 40 40 | 
             
                  attr_reader :name, :description, :mime_type, :uri
         | 
| 41 41 |  | 
| 42 42 | 
             
                  def with_metadata(&block)
         | 
| 43 | 
            -
                     | 
| 43 | 
            +
                    metadata_dsl = MetadataDSL.new
         | 
| 44 | 
            +
                    metadata_dsl.instance_eval(&block)
         | 
| 44 45 |  | 
| 45 | 
            -
                    @name =  | 
| 46 | 
            -
                    @description =  | 
| 47 | 
            -
                    @mime_type =  | 
| 48 | 
            -
                    @uri =  | 
| 46 | 
            +
                    @name = metadata_dsl.name
         | 
| 47 | 
            +
                    @description = metadata_dsl.description
         | 
| 48 | 
            +
                    @mime_type = metadata_dsl.mime_type
         | 
| 49 | 
            +
                    @uri = metadata_dsl.uri
         | 
| 49 50 | 
             
                  end
         | 
| 50 51 |  | 
| 51 52 | 
             
                  def inherited(subclass)
         | 
| @@ -60,7 +61,29 @@ module ModelContextProtocol | |
| 60 61 | 
             
                  end
         | 
| 61 62 |  | 
| 62 63 | 
             
                  def metadata
         | 
| 63 | 
            -
                    {name: @name, description: @description,  | 
| 64 | 
            +
                    {name: @name, description: @description, mimeType: @mime_type, uri: @uri}
         | 
| 65 | 
            +
                  end
         | 
| 66 | 
            +
                end
         | 
| 67 | 
            +
             | 
| 68 | 
            +
                class MetadataDSL
         | 
| 69 | 
            +
                  def name(value = nil)
         | 
| 70 | 
            +
                    @name = value if value
         | 
| 71 | 
            +
                    @name
         | 
| 72 | 
            +
                  end
         | 
| 73 | 
            +
             | 
| 74 | 
            +
                  def description(value = nil)
         | 
| 75 | 
            +
                    @description = value if value
         | 
| 76 | 
            +
                    @description
         | 
| 77 | 
            +
                  end
         | 
| 78 | 
            +
             | 
| 79 | 
            +
                  def mime_type(value = nil)
         | 
| 80 | 
            +
                    @mime_type = value if value
         | 
| 81 | 
            +
                    @mime_type
         | 
| 82 | 
            +
                  end
         | 
| 83 | 
            +
             | 
| 84 | 
            +
                  def uri(value = nil)
         | 
| 85 | 
            +
                    @uri = value if value
         | 
| 86 | 
            +
                    @uri
         | 
| 64 87 | 
             
                  end
         | 
| 65 88 | 
             
                end
         | 
| 66 89 | 
             
              end
         | 
| @@ -0,0 +1,93 @@ | |
| 1 | 
            +
            module ModelContextProtocol
         | 
| 2 | 
            +
              class Server::ResourceTemplate
         | 
| 3 | 
            +
                class << self
         | 
| 4 | 
            +
                  attr_reader :name, :description, :mime_type, :uri_template, :completions
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                  def with_metadata(&block)
         | 
| 7 | 
            +
                    metadata_dsl = MetadataDSL.new
         | 
| 8 | 
            +
                    metadata_dsl.instance_eval(&block)
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                    @name = metadata_dsl.name
         | 
| 11 | 
            +
                    @description = metadata_dsl.description
         | 
| 12 | 
            +
                    @mime_type = metadata_dsl.mime_type
         | 
| 13 | 
            +
                    @uri_template = metadata_dsl.uri_template
         | 
| 14 | 
            +
                    @completions = metadata_dsl.completions
         | 
| 15 | 
            +
                  end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                  def inherited(subclass)
         | 
| 18 | 
            +
                    subclass.instance_variable_set(:@name, @name)
         | 
| 19 | 
            +
                    subclass.instance_variable_set(:@description, @description)
         | 
| 20 | 
            +
                    subclass.instance_variable_set(:@mime_type, @mime_type)
         | 
| 21 | 
            +
                    subclass.instance_variable_set(:@uri_template, @uri_template)
         | 
| 22 | 
            +
                    subclass.instance_variable_set(:@completions, @completions&.dup)
         | 
| 23 | 
            +
                  end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                  def complete_for(param_name, value)
         | 
| 26 | 
            +
                    completion = if @completions && @completions[param_name.to_s]
         | 
| 27 | 
            +
                      @completions[param_name.to_s]
         | 
| 28 | 
            +
                    else
         | 
| 29 | 
            +
                      ModelContextProtocol::Server::NullCompletion
         | 
| 30 | 
            +
                    end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                    completion.call(param_name.to_s, value)
         | 
| 33 | 
            +
                  end
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                  def metadata
         | 
| 36 | 
            +
                    {
         | 
| 37 | 
            +
                      name: @name,
         | 
| 38 | 
            +
                      description: @description,
         | 
| 39 | 
            +
                      mimeType: @mime_type,
         | 
| 40 | 
            +
                      uriTemplate: @uri_template,
         | 
| 41 | 
            +
                      completions: @completions&.transform_keys(&:to_s)
         | 
| 42 | 
            +
                    }
         | 
| 43 | 
            +
                  end
         | 
| 44 | 
            +
                end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                class MetadataDSL
         | 
| 47 | 
            +
                  attr_reader :completions
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                  def initialize
         | 
| 50 | 
            +
                    @completions = {}
         | 
| 51 | 
            +
                  end
         | 
| 52 | 
            +
             | 
| 53 | 
            +
                  def name(value = nil)
         | 
| 54 | 
            +
                    @name = value if value
         | 
| 55 | 
            +
                    @name
         | 
| 56 | 
            +
                  end
         | 
| 57 | 
            +
             | 
| 58 | 
            +
                  def description(value = nil)
         | 
| 59 | 
            +
                    @description = value if value
         | 
| 60 | 
            +
                    @description
         | 
| 61 | 
            +
                  end
         | 
| 62 | 
            +
             | 
| 63 | 
            +
                  def mime_type(value = nil)
         | 
| 64 | 
            +
                    @mime_type = value if value
         | 
| 65 | 
            +
                    @mime_type
         | 
| 66 | 
            +
                  end
         | 
| 67 | 
            +
             | 
| 68 | 
            +
                  def uri_template(value = nil, &block)
         | 
| 69 | 
            +
                    @uri_template = value if value
         | 
| 70 | 
            +
             | 
| 71 | 
            +
                    if block_given?
         | 
| 72 | 
            +
                      completion_dsl = CompletionDSL.new
         | 
| 73 | 
            +
                      completion_dsl.instance_eval(&block)
         | 
| 74 | 
            +
                      @completions = completion_dsl.completions
         | 
| 75 | 
            +
                    end
         | 
| 76 | 
            +
             | 
| 77 | 
            +
                    @uri_template
         | 
| 78 | 
            +
                  end
         | 
| 79 | 
            +
                end
         | 
| 80 | 
            +
             | 
| 81 | 
            +
                class CompletionDSL
         | 
| 82 | 
            +
                  attr_reader :completions
         | 
| 83 | 
            +
             | 
| 84 | 
            +
                  def initialize
         | 
| 85 | 
            +
                    @completions = {}
         | 
| 86 | 
            +
                  end
         | 
| 87 | 
            +
             | 
| 88 | 
            +
                  def completion(param_name, completion_class)
         | 
| 89 | 
            +
                    @completions[param_name.to_s] = completion_class
         | 
| 90 | 
            +
                  end
         | 
| 91 | 
            +
                end
         | 
| 92 | 
            +
              end
         | 
| 93 | 
            +
            end
         | 
| @@ -76,11 +76,12 @@ module ModelContextProtocol | |
| 76 76 | 
             
                  attr_reader :name, :description, :input_schema
         | 
| 77 77 |  | 
| 78 78 | 
             
                  def with_metadata(&block)
         | 
| 79 | 
            -
                     | 
| 79 | 
            +
                    metadata_dsl = MetadataDSL.new
         | 
| 80 | 
            +
                    metadata_dsl.instance_eval(&block)
         | 
| 80 81 |  | 
| 81 | 
            -
                    @name =  | 
| 82 | 
            -
                    @description =  | 
| 83 | 
            -
                    @input_schema =  | 
| 82 | 
            +
                    @name = metadata_dsl.name
         | 
| 83 | 
            +
                    @description = metadata_dsl.description
         | 
| 84 | 
            +
                    @input_schema = metadata_dsl.input_schema
         | 
| 84 85 | 
             
                  end
         | 
| 85 86 |  | 
| 86 87 | 
             
                  def inherited(subclass)
         | 
| @@ -103,5 +104,22 @@ module ModelContextProtocol | |
| 103 104 | 
             
                    {name: @name, description: @description, inputSchema: @input_schema}
         | 
| 104 105 | 
             
                  end
         | 
| 105 106 | 
             
                end
         | 
| 107 | 
            +
             | 
| 108 | 
            +
                class MetadataDSL
         | 
| 109 | 
            +
                  def name(value = nil)
         | 
| 110 | 
            +
                    @name = value if value
         | 
| 111 | 
            +
                    @name
         | 
| 112 | 
            +
                  end
         | 
| 113 | 
            +
             | 
| 114 | 
            +
                  def description(value = nil)
         | 
| 115 | 
            +
                    @description = value if value
         | 
| 116 | 
            +
                    @description
         | 
| 117 | 
            +
                  end
         | 
| 118 | 
            +
             | 
| 119 | 
            +
                  def input_schema(&block)
         | 
| 120 | 
            +
                    @input_schema = instance_eval(&block) if block_given?
         | 
| 121 | 
            +
                    @input_schema
         | 
| 122 | 
            +
                  end
         | 
| 123 | 
            +
                end
         | 
| 106 124 | 
             
              end
         | 
| 107 125 | 
             
            end
         | 
| @@ -60,12 +60,45 @@ module ModelContextProtocol | |
| 60 60 | 
             
                    PingResponse[]
         | 
| 61 61 | 
             
                  end
         | 
| 62 62 |  | 
| 63 | 
            +
                  router.map("completion/complete") do |message|
         | 
| 64 | 
            +
                    type = message["params"]["ref"]["type"]
         | 
| 65 | 
            +
             | 
| 66 | 
            +
                    completion_source = case type
         | 
| 67 | 
            +
                    when "ref/prompt"
         | 
| 68 | 
            +
                      name = message["params"]["ref"]["name"]
         | 
| 69 | 
            +
                      configuration.registry.find_prompt(name)
         | 
| 70 | 
            +
                    when "ref/resource"
         | 
| 71 | 
            +
                      uri = message["params"]["ref"]["uri"]
         | 
| 72 | 
            +
                      configuration.registry.find_resource_template(uri)
         | 
| 73 | 
            +
                    else
         | 
| 74 | 
            +
                      raise ModelContextProtocol::Server::ParameterValidationError, "ref/type invalid"
         | 
| 75 | 
            +
                    end
         | 
| 76 | 
            +
             | 
| 77 | 
            +
                    arg_name, arg_value = message["params"]["argument"].values_at("name", "value")
         | 
| 78 | 
            +
             | 
| 79 | 
            +
                    if completion_source
         | 
| 80 | 
            +
                      completion_source.complete_for(arg_name, arg_value)
         | 
| 81 | 
            +
                    else
         | 
| 82 | 
            +
                      ModelContextProtocol::Server::NullCompletion.call(arg_name, arg_value)
         | 
| 83 | 
            +
                    end
         | 
| 84 | 
            +
                  end
         | 
| 85 | 
            +
             | 
| 63 86 | 
             
                  router.map("resources/list") do
         | 
| 64 87 | 
             
                    configuration.registry.resources_data
         | 
| 65 88 | 
             
                  end
         | 
| 66 89 |  | 
| 67 90 | 
             
                  router.map("resources/read") do |message|
         | 
| 68 | 
            -
                     | 
| 91 | 
            +
                    uri = message["params"]["uri"]
         | 
| 92 | 
            +
                    resource = configuration.registry.find_resource(uri)
         | 
| 93 | 
            +
                    unless resource
         | 
| 94 | 
            +
                      raise ModelContextProtocol::Server::ParameterValidationError, "resource not found for #{uri}"
         | 
| 95 | 
            +
                    end
         | 
| 96 | 
            +
             | 
| 97 | 
            +
                    resource.call
         | 
| 98 | 
            +
                  end
         | 
| 99 | 
            +
             | 
| 100 | 
            +
                  router.map("resources/templates/list") do |message|
         | 
| 101 | 
            +
                    configuration.registry.resource_templates_data
         | 
| 69 102 | 
             
                  end
         | 
| 70 103 |  | 
| 71 104 | 
             
                  router.map("prompts/list") do
         | 
| @@ -87,6 +120,7 @@ module ModelContextProtocol | |
| 87 120 |  | 
| 88 121 | 
             
                def build_capabilities
         | 
| 89 122 | 
             
                  {}.tap do |capabilities|
         | 
| 123 | 
            +
                    capabilities[:completions] = {}
         | 
| 90 124 | 
             
                    capabilities[:logging] = {} if configuration.logging_enabled?
         | 
| 91 125 |  | 
| 92 126 | 
             
                    registry = configuration.registry
         | 
| @@ -94,7 +128,7 @@ module ModelContextProtocol | |
| 94 128 | 
             
                    if registry.prompts_options.any? && !registry.instance_variable_get(:@prompts).empty?
         | 
| 95 129 | 
             
                      capabilities[:prompts] = {
         | 
| 96 130 | 
             
                        listChanged: registry.prompts_options[:list_changed]
         | 
| 97 | 
            -
                      }.compact
         | 
| 131 | 
            +
                      }.except(:completions).compact
         | 
| 98 132 | 
             
                    end
         | 
| 99 133 |  | 
| 100 134 | 
             
                    if registry.resources_options.any? && !registry.instance_variable_get(:@resources).empty?
         | 
    
        data/tasks/templates/dev.erb
    CHANGED
    
    | @@ -19,6 +19,10 @@ server = ModelContextProtocol::Server.new do |config| | |
| 19 19 | 
             
                  register TestBinaryResource
         | 
| 20 20 | 
             
                end
         | 
| 21 21 |  | 
| 22 | 
            +
                resource_templates do
         | 
| 23 | 
            +
                  register TestResourceTemplate
         | 
| 24 | 
            +
                end
         | 
| 25 | 
            +
             | 
| 22 26 | 
             
                tools list_changed: true do
         | 
| 23 27 | 
             
                  register TestToolWithTextResponse
         | 
| 24 28 | 
             
                  register TestToolWithImageResponse
         | 
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: model-context-protocol-rb
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0.3. | 
| 4 | 
            +
              version: 0.3.2
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Dick Davis
         | 
| 8 8 | 
             
            autorequire:
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2025- | 
| 11 | 
            +
            date: 2025-05-10 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: json-schema
         | 
| @@ -24,6 +24,20 @@ dependencies: | |
| 24 24 | 
             
                - - "~>"
         | 
| 25 25 | 
             
                  - !ruby/object:Gem::Version
         | 
| 26 26 | 
             
                    version: '5.1'
         | 
| 27 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 28 | 
            +
              name: addressable
         | 
| 29 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 30 | 
            +
                requirements:
         | 
| 31 | 
            +
                - - "~>"
         | 
| 32 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 33 | 
            +
                    version: '2.8'
         | 
| 34 | 
            +
              type: :runtime
         | 
| 35 | 
            +
              prerelease: false
         | 
| 36 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 37 | 
            +
                requirements:
         | 
| 38 | 
            +
                - - "~>"
         | 
| 39 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 40 | 
            +
                    version: '2.8'
         | 
| 27 41 | 
             
            description:
         | 
| 28 42 | 
             
            email:
         | 
| 29 43 | 
             
            - dick@hey.com
         | 
| @@ -42,10 +56,12 @@ files: | |
| 42 56 | 
             
            - Rakefile
         | 
| 43 57 | 
             
            - lib/model_context_protocol.rb
         | 
| 44 58 | 
             
            - lib/model_context_protocol/server.rb
         | 
| 59 | 
            +
            - lib/model_context_protocol/server/completion.rb
         | 
| 45 60 | 
             
            - lib/model_context_protocol/server/configuration.rb
         | 
| 46 61 | 
             
            - lib/model_context_protocol/server/prompt.rb
         | 
| 47 62 | 
             
            - lib/model_context_protocol/server/registry.rb
         | 
| 48 63 | 
             
            - lib/model_context_protocol/server/resource.rb
         | 
| 64 | 
            +
            - lib/model_context_protocol/server/resource_template.rb
         | 
| 49 65 | 
             
            - lib/model_context_protocol/server/router.rb
         | 
| 50 66 | 
             
            - lib/model_context_protocol/server/stdio_transport.rb
         | 
| 51 67 | 
             
            - lib/model_context_protocol/server/tool.rb
         |