active_mcp 0.9.2 → 0.10.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/README.md +38 -25
- data/app/controllers/concerns/active_mcp/request_handlable.rb +12 -12
- data/app/controllers/concerns/active_mcp/resource_readable.rb +1 -1
- data/app/controllers/concerns/active_mcp/tool_executable.rb +1 -1
- data/app/views/active_mcp/prompts_get.json.jbuilder +2 -2
- data/app/views/active_mcp/prompts_list.json.jbuilder +1 -1
- data/app/views/active_mcp/resources_read.json.jbuilder +9 -7
- data/lib/active_mcp/schema/base.rb +13 -33
- data/lib/active_mcp/server/protocol_handler.rb +1 -1
- data/lib/active_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: 40c074a297950ebddab382dabdb7e373e3aeebf5e11017bd40f6dea597ca7215
         | 
| 4 | 
            +
              data.tar.gz: 72ac9984228f99aa5a787e09af86b144a1f66837b1eadb38c6b857be8d455416
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 984057ffb2c91a788e0c69e19101a98aae9a6b526471e346cb4fc5151f0a978aaa454eb1ab6ed4e4c9e598c55e074027212214e19c37187c288a2d35621a84c5
         | 
| 7 | 
            +
              data.tar.gz: c046c53ec3523d3f800fbd8350fe44233ddd13218ff72022f5367e0b15062774e40de789644f609a56cc5e1e163f9a1d8ceb80d915d695dd96fec183f1bd9857
         | 
    
        data/README.md
    CHANGED
    
    | @@ -95,7 +95,7 @@ $ rails generate active_mcp:tool create_note | |
| 95 95 | 
             
            ```ruby
         | 
| 96 96 | 
             
            class CreateNoteTool < ActiveMcp::Tool::Base
         | 
| 97 97 | 
             
              def tool_name
         | 
| 98 | 
            -
                " | 
| 98 | 
            +
                "create_note"
         | 
| 99 99 | 
             
              end
         | 
| 100 100 |  | 
| 101 101 | 
             
              def description
         | 
| @@ -117,7 +117,11 @@ end | |
| 117 117 |  | 
| 118 118 | 
             
            ```ruby
         | 
| 119 119 | 
             
            class MySchema < ActiveMcp::Schema::Base
         | 
| 120 | 
            -
               | 
| 120 | 
            +
              def tools
         | 
| 121 | 
            +
                [
         | 
| 122 | 
            +
                  CreateNoteTool.new
         | 
| 123 | 
            +
                ]
         | 
| 124 | 
            +
              end
         | 
| 121 125 | 
             
            end
         | 
| 122 126 | 
             
            ```
         | 
| 123 127 |  | 
| @@ -125,6 +129,9 @@ end | |
| 125 129 |  | 
| 126 130 | 
             
            ```ruby
         | 
| 127 131 | 
             
            class MyMcpController < ActiveMcp::BaseController
         | 
| 132 | 
            +
             | 
| 133 | 
            +
              private
         | 
| 134 | 
            +
             | 
| 128 135 | 
             
              def schema
         | 
| 129 136 | 
             
                MySchema.new(context:)
         | 
| 130 137 | 
             
              end
         | 
| @@ -271,7 +278,7 @@ Control access to tools by overriding the `visible?` class method: | |
| 271 278 | 
             
            ```ruby
         | 
| 272 279 | 
             
            class AdminOnlyTool < ActiveMcp::Tool::Base
         | 
| 273 280 | 
             
              def tool_name
         | 
| 274 | 
            -
                " | 
| 281 | 
            +
                "admin_only_tool"
         | 
| 275 282 | 
             
              end
         | 
| 276 283 |  | 
| 277 284 | 
             
              def description
         | 
| @@ -380,8 +387,10 @@ end | |
| 380 387 |  | 
| 381 388 | 
             
            ```ruby
         | 
| 382 389 | 
             
            class MySchema < ActiveMcp::Schema::Base
         | 
| 383 | 
            -
               | 
| 384 | 
            -
                 | 
| 390 | 
            +
              def resources
         | 
| 391 | 
            +
                User.all.each do |user|
         | 
| 392 | 
            +
                  UserResource.new(id: user.id)
         | 
| 393 | 
            +
                end
         | 
| 385 394 | 
             
              end
         | 
| 386 395 | 
             
            end
         | 
| 387 396 | 
             
            ```
         | 
| @@ -500,8 +509,10 @@ end | |
| 500 509 |  | 
| 501 510 | 
             
            ```ruby
         | 
| 502 511 | 
             
            class MySchema < ActiveMcp::Schema::Base
         | 
| 503 | 
            -
               | 
| 504 | 
            -
                 | 
| 512 | 
            +
              def resources
         | 
| 513 | 
            +
                User.all.each do |user|
         | 
| 514 | 
            +
                  UserResource.new(id: user.id)
         | 
| 515 | 
            +
                end
         | 
| 505 516 | 
             
              end
         | 
| 506 517 | 
             
            end
         | 
| 507 518 | 
             
            ```
         | 
| @@ -516,33 +527,31 @@ Resources are Ruby classes `**Prompt`: | |
| 516 527 |  | 
| 517 528 | 
             
            ```ruby
         | 
| 518 529 | 
             
            class HelloPrompt < ActiveMcp::Prompt::Base
         | 
| 519 | 
            -
               | 
| 520 | 
            -
                 | 
| 521 | 
            -
             | 
| 522 | 
            -
                end
         | 
| 530 | 
            +
              argument :name, ->(value) do
         | 
| 531 | 
            +
                User.all.pluck(:name).filter { _1.match(value) }
         | 
| 532 | 
            +
              end
         | 
| 523 533 |  | 
| 524 | 
            -
             | 
| 525 | 
            -
             | 
| 526 | 
            -
             | 
| 534 | 
            +
              def initialize(greeting:)
         | 
| 535 | 
            +
                @greeting = greeting
         | 
| 536 | 
            +
              end
         | 
| 527 537 |  | 
| 528 | 
            -
             | 
| 529 | 
            -
             | 
| 530 | 
            -
                end
         | 
| 538 | 
            +
              def prompt_name
         | 
| 539 | 
            +
                "hello"
         | 
| 531 540 | 
             
              end
         | 
| 532 541 |  | 
| 533 | 
            -
               | 
| 534 | 
            -
                 | 
| 542 | 
            +
              def description
         | 
| 543 | 
            +
                "This is a test."
         | 
| 535 544 | 
             
              end
         | 
| 536 545 |  | 
| 537 | 
            -
              def  | 
| 538 | 
            -
                 | 
| 546 | 
            +
              def visible?(context:)
         | 
| 547 | 
            +
                # Your logic...
         | 
| 539 548 | 
             
              end
         | 
| 540 549 |  | 
| 541 | 
            -
              def messages
         | 
| 550 | 
            +
              def messages(name:)
         | 
| 542 551 | 
             
                [
         | 
| 543 552 | 
             
                  ActiveMcp::Message::Text.new(
         | 
| 544 553 | 
             
                    role: "user",
         | 
| 545 | 
            -
                    text: " | 
| 554 | 
            +
                    text: "#{@greeting} #{name}"
         | 
| 546 555 | 
             
                  ),
         | 
| 547 556 | 
             
                  ActiveMcp::Message::Image.new(
         | 
| 548 557 | 
             
                    role: "assistant",
         | 
| @@ -565,7 +574,11 @@ end | |
| 565 574 |  | 
| 566 575 | 
             
            ```ruby
         | 
| 567 576 | 
             
            class MySchema < ActiveMcp::Schema::Base
         | 
| 568 | 
            -
               | 
| 577 | 
            +
              def prompts
         | 
| 578 | 
            +
                [
         | 
| 579 | 
            +
                  HelloPrompt.new(greeting: "Hello!")
         | 
| 580 | 
            +
                ]
         | 
| 581 | 
            +
              end
         | 
| 569 582 | 
             
            end
         | 
| 570 583 | 
             
            ```
         | 
| 571 584 |  | 
| @@ -624,7 +637,7 @@ end | |
| 624 637 |  | 
| 625 638 | 
             
            ## 🧪 Development
         | 
| 626 639 |  | 
| 627 | 
            -
            After checking out the repo, run `bundle install` to install dependencies. Then, run `bundle exec rake` to run the tests. | 
| 640 | 
            +
            After checking out the repo, run `bundle install` to install dependencies. Then, run `bundle exec rake` to run the tests.
         | 
| 628 641 |  | 
| 629 642 | 
             
            ## 👥 Contributing
         | 
| 630 643 |  | 
| @@ -21,11 +21,11 @@ module ActiveMcp | |
| 21 21 | 
             
                  when Method::CANCELLED
         | 
| 22 22 | 
             
                    render "active_mcp/cancelled", formats: :json
         | 
| 23 23 | 
             
                  when Method::RESOURCES_LIST
         | 
| 24 | 
            -
                    @resources = schema. | 
| 24 | 
            +
                    @resources = schema.visible_resources
         | 
| 25 25 | 
             
                    @format = :jsonrpc
         | 
| 26 26 | 
             
                    render "active_mcp/resources_list", formats: :json
         | 
| 27 27 | 
             
                  when Method::RESOURCES_TEMPLATES_LIST
         | 
| 28 | 
            -
                    @resource_templates = schema. | 
| 28 | 
            +
                    @resource_templates = schema.visible_resource_templates
         | 
| 29 29 | 
             
                    @format = :jsonrpc
         | 
| 30 30 | 
             
                    render "active_mcp/resource_templates_list", formats: :json
         | 
| 31 31 | 
             
                  when Method::RESOURCES_READ
         | 
| @@ -33,7 +33,7 @@ module ActiveMcp | |
| 33 33 | 
             
                    @format = :jsonrpc
         | 
| 34 34 | 
             
                    render "active_mcp/resources_read", formats: :json
         | 
| 35 35 | 
             
                  when Method::TOOLS_LIST
         | 
| 36 | 
            -
                    @tools = schema. | 
| 36 | 
            +
                    @tools = schema.visible_tools
         | 
| 37 37 | 
             
                    @format = :jsonrpc
         | 
| 38 38 | 
             
                    render "active_mcp/tools_list", formats: :json
         | 
| 39 39 | 
             
                  when Method::TOOLS_CALL
         | 
| @@ -42,15 +42,15 @@ module ActiveMcp | |
| 42 42 | 
             
                    render "active_mcp/tools_call", formats: :json
         | 
| 43 43 | 
             
                  when Method::COMPLETION_COMPLETE
         | 
| 44 44 | 
             
                    type = params.dig(:params, :ref, :type)
         | 
| 45 | 
            -
                    @completion = ActiveMcp::Completion.new.complete(params: params[:params], context:, refs: (type === "ref/resource") ? schema. | 
| 45 | 
            +
                    @completion = ActiveMcp::Completion.new.complete(params: params[:params], context:, refs: (type === "ref/resource") ? schema.visible_resource_templates : schema.visible_prompts)
         | 
| 46 46 | 
             
                    @format = :jsonrpc
         | 
| 47 47 | 
             
                    render "active_mcp/completion_complete", formats: :json
         | 
| 48 48 | 
             
                  when Method::PROMPTS_LIST
         | 
| 49 | 
            -
                    @prompts = schema. | 
| 49 | 
            +
                    @prompts = schema.visible_prompts
         | 
| 50 50 | 
             
                    @format = :jsonrpc
         | 
| 51 51 | 
             
                    render "active_mcp/prompts_list", formats: :json
         | 
| 52 52 | 
             
                  when Method::PROMPTS_GET
         | 
| 53 | 
            -
                    @prompt = schema. | 
| 53 | 
            +
                    @prompt = schema.visible_prompts.find { _1.prompt_name == params[:params][:name] }
         | 
| 54 54 | 
             
                    @format = :jsonrpc
         | 
| 55 55 | 
             
                    render "active_mcp/prompts_get", formats: :json
         | 
| 56 56 | 
             
                  else
         | 
| @@ -62,7 +62,7 @@ module ActiveMcp | |
| 62 62 | 
             
                def handle_mcp_server_request
         | 
| 63 63 | 
             
                  case params[:method]
         | 
| 64 64 | 
             
                  when Method::RESOURCES_LIST
         | 
| 65 | 
            -
                    @resources = schema. | 
| 65 | 
            +
                    @resources = schema.visible_resources
         | 
| 66 66 | 
             
                    @format = :json
         | 
| 67 67 | 
             
                    render "active_mcp/resources_list", formats: :json
         | 
| 68 68 | 
             
                  when Method::RESOURCES_READ
         | 
| @@ -70,11 +70,11 @@ module ActiveMcp | |
| 70 70 | 
             
                    @format = :json
         | 
| 71 71 | 
             
                    render "active_mcp/resources_read", formats: :json
         | 
| 72 72 | 
             
                  when Method::RESOURCES_TEMPLATES_LIST
         | 
| 73 | 
            -
                    @resource_templates = schema. | 
| 73 | 
            +
                    @resource_templates = schema.visible_resource_templates
         | 
| 74 74 | 
             
                    @format = :json
         | 
| 75 75 | 
             
                    render "active_mcp/resource_templates_list", formats: :json
         | 
| 76 76 | 
             
                  when Method::TOOLS_LIST
         | 
| 77 | 
            -
                    @tools = schema. | 
| 77 | 
            +
                    @tools = schema.visible_tools
         | 
| 78 78 | 
             
                    @format = :json
         | 
| 79 79 | 
             
                    render "active_mcp/tools_list", formats: :json
         | 
| 80 80 | 
             
                  when Method::TOOLS_CALL
         | 
| @@ -83,15 +83,15 @@ module ActiveMcp | |
| 83 83 | 
             
                    render "active_mcp/tools_call", formats: :json
         | 
| 84 84 | 
             
                  when Method::COMPLETION_COMPLETE
         | 
| 85 85 | 
             
                    type = params.dig(:params, :ref, :type)
         | 
| 86 | 
            -
                    @completion = ActiveMcp::Completion.new.complete(params: params[:params], context:, refs: (type == "ref/resource") ? schema. | 
| 86 | 
            +
                    @completion = ActiveMcp::Completion.new.complete(params: params[:params], context:, refs: (type == "ref/resource") ? schema.visible_resource_templates : schema.visible_prompts)
         | 
| 87 87 | 
             
                    @format = :json
         | 
| 88 88 | 
             
                    render "active_mcp/completion_complete", formats: :json
         | 
| 89 89 | 
             
                  when Method::PROMPTS_LIST
         | 
| 90 | 
            -
                    @prompts = schema. | 
| 90 | 
            +
                    @prompts = schema.visible_prompts
         | 
| 91 91 | 
             
                    @format = :json
         | 
| 92 92 | 
             
                    render "active_mcp/prompts_list", formats: :json
         | 
| 93 93 | 
             
                  when Method::PROMPTS_GET
         | 
| 94 | 
            -
                    @prompt = schema. | 
| 94 | 
            +
                    @prompt = schema.visible_prompts&.find { _1.prompt_name == params[:params][:name] }
         | 
| 95 95 | 
             
                    @format = :json
         | 
| 96 96 | 
             
                    render "active_mcp/prompts_get", formats: :json
         | 
| 97 97 | 
             
                  else
         | 
| @@ -2,6 +2,6 @@ json.jsonrpc ActiveMcp::JSON_RPC_VERSION if @format == :jsonrpc | |
| 2 2 | 
             
            json.id @id if @format == :jsonrpc && @id.present?
         | 
| 3 3 |  | 
| 4 4 | 
             
            json.result do
         | 
| 5 | 
            -
              json.description @prompt. | 
| 6 | 
            -
              json.messages @prompt.messages.map(&:to_h)
         | 
| 5 | 
            +
              json.description @prompt.description
         | 
| 6 | 
            +
              json.messages @prompt.messages(**params[:params][:arguments].permit!.to_h.symbolize_keys).map(&:to_h)
         | 
| 7 7 | 
             
            end
         | 
| @@ -6,7 +6,7 @@ json.result do | |
| 6 6 | 
             
                json.array!(@prompts) do |prompt|
         | 
| 7 7 | 
             
                  json.name prompt.prompt_name
         | 
| 8 8 | 
             
                  json.description prompt.description
         | 
| 9 | 
            -
                  json.arguments prompt.arguments.map { _1.except(:complete) }
         | 
| 9 | 
            +
                  json.arguments prompt.class.arguments.map { _1.except(:complete) }
         | 
| 10 10 | 
             
                end
         | 
| 11 11 | 
             
              end
         | 
| 12 12 | 
             
            end
         | 
| @@ -1,12 +1,14 @@ | |
| 1 1 | 
             
            json.jsonrpc ActiveMcp::JSON_RPC_VERSION if @format == :jsonrpc
         | 
| 2 2 | 
             
            json.id @id if @format == :jsonrpc && @id.present?
         | 
| 3 3 |  | 
| 4 | 
            -
            json. | 
| 5 | 
            -
            json. | 
| 6 | 
            -
              json. | 
| 7 | 
            -
                json. | 
| 8 | 
            -
             | 
| 9 | 
            -
             | 
| 10 | 
            -
             | 
| 4 | 
            +
            json.result do
         | 
| 5 | 
            +
              json.isError @resource[:isError] if @resource[:isError]
         | 
| 6 | 
            +
              json.contents do
         | 
| 7 | 
            +
                json.array!(@resource[:contents]) do |content|
         | 
| 8 | 
            +
                  json.uri content[:uri]
         | 
| 9 | 
            +
                  json.mimeType raw content[:mimeType]
         | 
| 10 | 
            +
                  json.text raw content[:text] if content[:text]
         | 
| 11 | 
            +
                  json.blob content[:blob] if content[:blob]
         | 
| 12 | 
            +
                end
         | 
| 11 13 | 
             
              end
         | 
| 12 14 | 
             
            end
         | 
| @@ -1,54 +1,34 @@ | |
| 1 1 | 
             
            module ActiveMcp
         | 
| 2 2 | 
             
              module Schema
         | 
| 3 3 | 
             
                class Base
         | 
| 4 | 
            -
                   | 
| 5 | 
            -
                    attr_reader :resources, :resource_templates, :tools, :prompts
         | 
| 6 | 
            -
             | 
| 7 | 
            -
                    def resource(klass)
         | 
| 8 | 
            -
                      @resources ||= []
         | 
| 9 | 
            -
                      @resources << klass
         | 
| 10 | 
            -
             | 
| 11 | 
            -
                      if klass.class.respond_to?(:uri_template)
         | 
| 12 | 
            -
                        @resource_templates ||= []
         | 
| 13 | 
            -
                        @resource_templates << klass.class unless klass.class.in?(@resource_templates)
         | 
| 14 | 
            -
                      end
         | 
| 15 | 
            -
                    end
         | 
| 16 | 
            -
             | 
| 17 | 
            -
                    def tool(klass)
         | 
| 18 | 
            -
                      @tools ||= []
         | 
| 19 | 
            -
                      @tools << klass
         | 
| 20 | 
            -
                    end
         | 
| 21 | 
            -
             | 
| 22 | 
            -
                    def prompt(klass)
         | 
| 23 | 
            -
                      @prompts ||= []
         | 
| 24 | 
            -
                      @prompts << klass
         | 
| 25 | 
            -
                    end
         | 
| 26 | 
            -
                  end
         | 
| 4 | 
            +
                  attr_reader :context
         | 
| 27 5 |  | 
| 28 6 | 
             
                  def initialize(context: {})
         | 
| 29 7 | 
             
                    @context = context
         | 
| 30 8 | 
             
                  end
         | 
| 31 9 |  | 
| 32 | 
            -
                  def  | 
| 33 | 
            -
                     | 
| 34 | 
            -
                      !resource.respond_to?(:visible?) || resource.visible?(context: @context)
         | 
| 10 | 
            +
                  def visible_resources
         | 
| 11 | 
            +
                    resources&.filter do |resource|
         | 
| 12 | 
            +
                      !resource.class.respond_to?(:uri_template) && !resource.respond_to?(:visible?) || resource.visible?(context: @context)
         | 
| 35 13 | 
             
                    end
         | 
| 36 14 | 
             
                  end
         | 
| 37 15 |  | 
| 38 | 
            -
                  def  | 
| 39 | 
            -
                     | 
| 40 | 
            -
                      ! | 
| 16 | 
            +
                  def visible_resource_templates
         | 
| 17 | 
            +
                    resource_instances = resources&.filter do |resource|
         | 
| 18 | 
            +
                      resource.class.respond_to?(:uri_template) && (!resource.respond_to?(:visible?) || resource.visible?(context: @context))
         | 
| 41 19 | 
             
                    end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                    resource_instances.map(&:class)
         | 
| 42 22 | 
             
                  end
         | 
| 43 23 |  | 
| 44 | 
            -
                  def  | 
| 45 | 
            -
                     | 
| 24 | 
            +
                  def visible_tools
         | 
| 25 | 
            +
                    tools&.filter do |tool|
         | 
| 46 26 | 
             
                      !tool.respond_to?(:visible?) || tool.visible?(context: @context)
         | 
| 47 27 | 
             
                    end
         | 
| 48 28 | 
             
                  end
         | 
| 49 29 |  | 
| 50 | 
            -
                  def  | 
| 51 | 
            -
                     | 
| 30 | 
            +
                  def visible_prompts
         | 
| 31 | 
            +
                    prompts&.filter do |resource|
         | 
| 52 32 | 
             
                      !resource.respond_to?(:visible?) || resource.visible?(context: @context)
         | 
| 53 33 | 
             
                    end
         | 
| 54 34 | 
             
                  end
         | 
| @@ -174,7 +174,7 @@ module ActiveMcp | |
| 174 174 | 
             
                    arguments = request.dig(:params, :arguments)
         | 
| 175 175 | 
             
                    result = @server.fetch(params: {method: Method::PROMPTS_GET, params: {name:, arguments:}})
         | 
| 176 176 |  | 
| 177 | 
            -
                    success_response(request[:id], result)
         | 
| 177 | 
            +
                    success_response(request[:id], result[:result])
         | 
| 178 178 | 
             
                  end
         | 
| 179 179 |  | 
| 180 180 | 
             
                  def success_response(id, result)
         | 
    
        data/lib/active_mcp/version.rb
    CHANGED
    
    
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: active_mcp
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0. | 
| 4 | 
            +
              version: 0.10.0
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Moeki Kawakami
         | 
| 8 8 | 
             
            autorequire:
         | 
| 9 9 | 
             
            bindir: exe
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2025-04- | 
| 11 | 
            +
            date: 2025-04-09 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: rails
         |