Skip to content

Commit f312695

Browse files
authored
Merge pull request #153 from modelcontextprotocol/prompt-spec-compliance
fix `Prompt` type gaps with 2025-06-18 spec
2 parents f8557e5 + a1dd3dd commit f312695

File tree

4 files changed

+86
-10
lines changed

4 files changed

+86
-10
lines changed

README.md

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -623,10 +623,12 @@ class MyPrompt < MCP::Prompt
623623
arguments [
624624
MCP::Prompt::Argument.new(
625625
name: "message",
626+
title: "Message Title",
626627
description: "Input message",
627628
required: true
628629
)
629630
]
631+
meta({ version: "1.0", category: "example" })
630632

631633
class << self
632634
def template(args, server_context:)
@@ -660,10 +662,12 @@ prompt = MCP::Prompt.define(
660662
arguments: [
661663
MCP::Prompt::Argument.new(
662664
name: "message",
665+
title: "Message Title",
663666
description: "Input message",
664667
required: true
665668
)
666-
]
669+
],
670+
meta: { version: "1.0", category: "example" }
667671
) do |args, server_context:|
668672
MCP::Prompt::Result.new(
669673
description: "Response description",
@@ -691,10 +695,12 @@ server.define_prompt(
691695
arguments: [
692696
Prompt::Argument.new(
693697
name: "message",
698+
title: "Message Title",
694699
description: "Input message",
695700
required: true
696701
)
697-
]
702+
],
703+
meta: { version: "1.0", category: "example" }
698704
) do |args, server_context:|
699705
Prompt::Result.new(
700706
description: "Response description",
@@ -717,7 +723,7 @@ e.g. around authentication state or user preferences.
717723

718724
### Key Components
719725

720-
- `MCP::Prompt::Argument` - Defines input parameters for the prompt template
726+
- `MCP::Prompt::Argument` - Defines input parameters for the prompt template with name, title, description, and required flag
721727
- `MCP::Prompt::Message` - Represents a message in the conversation with a role and content
722728
- `MCP::Prompt::Result` - The output of a prompt template containing description and messages
723729
- `MCP::Content::Text` - Text content for messages

lib/mcp/prompt.rb

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,20 @@ class << self
88
attr_reader :title_value
99
attr_reader :description_value
1010
attr_reader :arguments_value
11+
attr_reader :meta_value
1112

1213
def template(args, server_context: nil)
1314
raise NotImplementedError, "Subclasses must implement template"
1415
end
1516

1617
def to_h
17-
{ name: name_value, title: title_value, description: description_value, arguments: arguments_value.map(&:to_h) }.compact
18+
{
19+
name: name_value,
20+
title: title_value,
21+
description: description_value,
22+
arguments: arguments_value&.map(&:to_h),
23+
_meta: meta_value,
24+
}.compact
1825
end
1926

2027
def inherited(subclass)
@@ -23,6 +30,7 @@ def inherited(subclass)
2330
subclass.instance_variable_set(:@title_value, nil)
2431
subclass.instance_variable_set(:@description_value, nil)
2532
subclass.instance_variable_set(:@arguments_value, nil)
33+
subclass.instance_variable_set(:@meta_value, nil)
2634
end
2735

2836
def prompt_name(value = NOT_SET)
@@ -61,7 +69,15 @@ def arguments(value = NOT_SET)
6169
end
6270
end
6371

64-
def define(name: nil, title: nil, description: nil, arguments: [], &block)
72+
def meta(value = NOT_SET)
73+
if value == NOT_SET
74+
@meta_value
75+
else
76+
@meta_value = value
77+
end
78+
end
79+
80+
def define(name: nil, title: nil, description: nil, arguments: [], meta: nil, &block)
6581
Class.new(self) do
6682
prompt_name name
6783
title title
@@ -70,6 +86,7 @@ def define(name: nil, title: nil, description: nil, arguments: [], &block)
7086
define_singleton_method(:template) do |args, server_context: nil|
7187
instance_exec(args, server_context:, &block)
7288
end
89+
meta meta
7390
end
7491
end
7592

lib/mcp/prompt/argument.rb

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,22 @@
33
module MCP
44
class Prompt
55
class Argument
6-
attr_reader :name, :description, :required, :arguments
6+
attr_reader :name, :title, :description, :required
77

8-
def initialize(name:, description: nil, required: false)
8+
def initialize(name:, title: nil, description: nil, required: false)
99
@name = name
10+
@title = title
1011
@description = description
1112
@required = required
12-
@arguments = arguments
1313
end
1414

1515
def to_h
16-
{ name:, description:, required: }.compact
16+
{
17+
name: name,
18+
title: title,
19+
description: description,
20+
required: required,
21+
}.compact
1722
end
1823
end
1924
end

test/mcp/prompt_test.rb

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,8 +113,14 @@ def template(args, server_context:)
113113
title: "Mock Prompt",
114114
description: "a mock prompt for testing",
115115
arguments: [
116-
Prompt::Argument.new(name: "test_argument", description: "Test argument", required: true),
116+
Prompt::Argument.new(
117+
name: "test_argument",
118+
title: "Test argument title",
119+
description: "This is a test argument description",
120+
required: true,
121+
),
117122
],
123+
meta: { foo: "bar" },
118124
) do |args, server_context:|
119125
content = Content::Text.new(args["test_argument"] + " user: #{server_context[:user_id]}")
120126

@@ -130,6 +136,10 @@ def template(args, server_context:)
130136
assert_equal "mock_prompt", prompt.name_value
131137
assert_equal "a mock prompt for testing", prompt.description
132138
assert_equal "test_argument", prompt.arguments.first.name
139+
assert_equal "Test argument title", prompt.arguments.first.title
140+
assert_equal "This is a test argument description", prompt.arguments.first.description
141+
assert prompt.arguments.first.required
142+
assert_equal({ foo: "bar" }, prompt.meta_value)
133143

134144
expected = {
135145
description: "Hello, world!",
@@ -142,5 +152,43 @@ def template(args, server_context:)
142152
result = prompt.template({ "test_argument" => "Hello, friend!" }, server_context: { user_id: 123 })
143153
assert_equal expected, result.to_h
144154
end
155+
156+
test "#to_h returns a hash with name, title, description, arguments, and meta" do
157+
class FullPrompt < Prompt
158+
prompt_name "test_prompt"
159+
description "Test prompt description"
160+
title "Test Prompt title"
161+
arguments [
162+
Prompt::Argument.new(name: "test_argument", description: "Test argument", required: true),
163+
]
164+
meta({ test: "meta" })
165+
end
166+
167+
expected = {
168+
name: "test_prompt",
169+
title: "Test Prompt title",
170+
description: "Test prompt description",
171+
arguments: [
172+
{ name: "test_argument", description: "Test argument", required: true },
173+
],
174+
_meta: { test: "meta" },
175+
}
176+
177+
assert_equal expected, FullPrompt.to_h
178+
end
179+
180+
test "#to_h handles nil arguments value" do
181+
class NoArgumentsPrompt < Prompt
182+
description "No arguments prompt"
183+
end
184+
prompt = NoArgumentsPrompt
185+
186+
expected = {
187+
name: "no_arguments_prompt",
188+
description: "No arguments prompt",
189+
}
190+
191+
assert_equal expected, prompt.to_h
192+
end
145193
end
146194
end

0 commit comments

Comments
 (0)