From ef5c76373b988017f476049b7fa805f8fb24e9d0 Mon Sep 17 00:00:00 2001 From: Koichi ITO Date: Sat, 28 Feb 2026 02:51:31 +0900 Subject: [PATCH] Fix `Prompt#validate_arguments!` crash when arguments are `nil` `Prompt#validate_arguments!` called `required_args` which does `arguments_value.filter_map`, crashing with `NoMethodError` when `arguments_value` is `nil` (the default for prompts without declared arguments). Additionally, passing `nil` as args caused a crash on `args.keys`. Fix by defaulting `arguments_value` to `[]` and guarding against `nil` args. --- lib/mcp/prompt.rb | 7 +++--- test/mcp/prompt_test.rb | 47 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 50 insertions(+), 4 deletions(-) diff --git a/lib/mcp/prompt.rb b/lib/mcp/prompt.rb index 128ee47..3253faa 100644 --- a/lib/mcp/prompt.rb +++ b/lib/mcp/prompt.rb @@ -21,7 +21,7 @@ def to_h title: title_value, description: description_value, icons: icons_value&.then { |icons| icons.empty? ? nil : icons.map(&:to_h) }, - arguments: arguments_value&.map(&:to_h), + arguments: arguments_value.empty? ? nil : arguments_value.map(&:to_h), _meta: meta_value, }.compact end @@ -32,7 +32,7 @@ def inherited(subclass) subclass.instance_variable_set(:@title_value, nil) subclass.instance_variable_set(:@description_value, nil) subclass.instance_variable_set(:@icons_value, nil) - subclass.instance_variable_set(:@arguments_value, nil) + subclass.instance_variable_set(:@arguments_value, []) subclass.instance_variable_set(:@meta_value, nil) end @@ -76,7 +76,7 @@ def arguments(value = NOT_SET) if value == NOT_SET @arguments_value else - @arguments_value = value + @arguments_value = Array(value) end end @@ -103,6 +103,7 @@ def define(name: nil, title: nil, description: nil, icons: [], arguments: [], me end def validate_arguments!(args) + args ||= {} missing = required_args - args.keys return if missing.empty? diff --git a/test/mcp/prompt_test.rb b/test/mcp/prompt_test.rb index a434e06..a6fe18a 100644 --- a/test/mcp/prompt_test.rb +++ b/test/mcp/prompt_test.rb @@ -182,7 +182,7 @@ class FullPrompt < Prompt assert_equal expected, FullPrompt.to_h end - test "#to_h handles nil arguments value" do + test "#to_h omits arguments key when arguments are not declared" do class NoArgumentsPrompt < Prompt description "No arguments prompt" end @@ -196,6 +196,51 @@ class NoArgumentsPrompt < Prompt assert_equal expected, prompt.to_h end + test "#validate_arguments! does not raise when arguments are not declared" do + prompt_class = Class.new(Prompt) do + prompt_name "no_args_prompt" + description "A prompt with no arguments" + # NOTE: no `arguments` declaration at all + end + + assert_nothing_raised do + prompt_class.validate_arguments!({}) + end + end + + test "#validate_arguments! handles nil args" do + prompt_class = Class.new(Prompt) do + prompt_name "no_args_prompt" + description "A prompt with no arguments" + end + + assert_nothing_raised do + prompt_class.validate_arguments!(nil) + end + end + + test "#validate_arguments! does not raise when arguments is explicitly set to nil" do + prompt_class = Class.new(Prompt) do + prompt_name "nil_args_prompt" + description "A prompt with nil arguments" + arguments nil + end + + assert_nothing_raised do + prompt_class.validate_arguments!({}) + end + end + + test "#to_h omits arguments key when arguments is empty" do + prompt = Prompt.define( + name: "no_args_prompt", + description: "a prompt without arguments", + arguments: [], + ) + + refute prompt.to_h.key?(:arguments) + end + test "#to_h does not have `:icons` key when icons is empty" do prompt = Prompt.define( name: "prompt_without_icons",