Skip to content

Commit 88248fc

Browse files
authored
Merge pull request #310 from koic/add_meta_field_support
Add `_meta` field to resource, content, and result classes
2 parents ff8e6b8 + 0ad9a89 commit 88248fc

12 files changed

Lines changed: 269 additions & 29 deletions

File tree

lib/mcp/content.rb

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,56 +3,60 @@
33
module MCP
44
module Content
55
class Text
6-
attr_reader :text, :annotations
6+
attr_reader :text, :annotations, :meta
77

8-
def initialize(text, annotations: nil)
8+
def initialize(text, annotations: nil, meta: nil)
99
@text = text
1010
@annotations = annotations
11+
@meta = meta
1112
end
1213

1314
def to_h
14-
{ text: text, annotations: annotations, type: "text" }.compact
15+
{ text: text, annotations: annotations, _meta: meta, type: "text" }.compact
1516
end
1617
end
1718

1819
class Image
19-
attr_reader :data, :mime_type, :annotations
20+
attr_reader :data, :mime_type, :annotations, :meta
2021

21-
def initialize(data, mime_type, annotations: nil)
22+
def initialize(data, mime_type, annotations: nil, meta: nil)
2223
@data = data
2324
@mime_type = mime_type
2425
@annotations = annotations
26+
@meta = meta
2527
end
2628

2729
def to_h
28-
{ data: data, mimeType: mime_type, annotations: annotations, type: "image" }.compact
30+
{ data: data, mimeType: mime_type, annotations: annotations, _meta: meta, type: "image" }.compact
2931
end
3032
end
3133

3234
class Audio
33-
attr_reader :data, :mime_type, :annotations
35+
attr_reader :data, :mime_type, :annotations, :meta
3436

35-
def initialize(data, mime_type, annotations: nil)
37+
def initialize(data, mime_type, annotations: nil, meta: nil)
3638
@data = data
3739
@mime_type = mime_type
3840
@annotations = annotations
41+
@meta = meta
3942
end
4043

4144
def to_h
42-
{ data: data, mimeType: mime_type, annotations: annotations, type: "audio" }.compact
45+
{ data: data, mimeType: mime_type, annotations: annotations, _meta: meta, type: "audio" }.compact
4346
end
4447
end
4548

4649
class EmbeddedResource
47-
attr_reader :resource, :annotations
50+
attr_reader :resource, :annotations, :meta
4851

49-
def initialize(resource, annotations: nil)
52+
def initialize(resource, annotations: nil, meta: nil)
5053
@resource = resource
5154
@annotations = annotations
55+
@meta = meta
5256
end
5357

5458
def to_h
55-
{ resource: resource.to_h, annotations: annotations, type: "resource" }.compact
59+
{ resource: resource.to_h, annotations: annotations, _meta: meta, type: "resource" }.compact
5660
end
5761
end
5862
end

lib/mcp/prompt/result.rb

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,16 @@
33
module MCP
44
class Prompt
55
class Result
6-
attr_reader :description, :messages
6+
attr_reader :description, :messages, :meta
77

8-
def initialize(description: nil, messages: [])
8+
def initialize(description: nil, messages: [], meta: nil)
99
@description = description
1010
@messages = messages
11+
@meta = meta
1112
end
1213

1314
def to_h
14-
{ description: description, messages: messages.map(&:to_h) }.compact
15+
{ description: description, messages: messages.map(&:to_h), _meta: meta }.compact
1516
end
1617
end
1718
end

lib/mcp/resource.rb

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,16 @@
55

66
module MCP
77
class Resource
8-
attr_reader :uri, :name, :title, :description, :icons, :mime_type
8+
attr_reader :uri, :name, :title, :description, :icons, :mime_type, :meta
99

10-
def initialize(uri:, name:, title: nil, description: nil, icons: [], mime_type: nil)
10+
def initialize(uri:, name:, title: nil, description: nil, icons: [], mime_type: nil, meta: nil)
1111
@uri = uri
1212
@name = name
1313
@title = title
1414
@description = description
1515
@icons = icons
1616
@mime_type = mime_type
17+
@meta = meta
1718
end
1819

1920
def to_h
@@ -24,6 +25,7 @@ def to_h
2425
description: description,
2526
icons: icons&.then { |icons| icons.empty? ? nil : icons.map(&:to_h) },
2627
mimeType: mime_type,
28+
_meta: meta,
2729
}.compact
2830
end
2931
end

lib/mcp/resource/contents.rb

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,24 @@
33
module MCP
44
class Resource
55
class Contents
6-
attr_reader :uri, :mime_type
6+
attr_reader :uri, :mime_type, :meta
77

8-
def initialize(uri:, mime_type: nil)
8+
def initialize(uri:, mime_type: nil, meta: nil)
99
@uri = uri
1010
@mime_type = mime_type
11+
@meta = meta
1112
end
1213

1314
def to_h
14-
{ uri: uri, mimeType: mime_type }.compact
15+
{ uri: uri, mimeType: mime_type, _meta: meta }.compact
1516
end
1617
end
1718

1819
class TextContents < Contents
1920
attr_reader :text
2021

21-
def initialize(text:, uri:, mime_type:)
22-
super(uri: uri, mime_type: mime_type)
22+
def initialize(text:, uri:, mime_type:, meta: nil)
23+
super(uri: uri, mime_type: mime_type, meta: meta)
2324
@text = text
2425
end
2526

@@ -31,8 +32,8 @@ def to_h
3132
class BlobContents < Contents
3233
attr_reader :data
3334

34-
def initialize(data:, uri:, mime_type:)
35-
super(uri: uri, mime_type: mime_type)
35+
def initialize(data:, uri:, mime_type:, meta: nil)
36+
super(uri: uri, mime_type: mime_type, meta: meta)
3637
@data = data
3738
end
3839

lib/mcp/resource_template.rb

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,16 @@
22

33
module MCP
44
class ResourceTemplate
5-
attr_reader :uri_template, :name, :title, :description, :icons, :mime_type
5+
attr_reader :uri_template, :name, :title, :description, :icons, :mime_type, :meta
66

7-
def initialize(uri_template:, name:, title: nil, description: nil, icons: [], mime_type: nil)
7+
def initialize(uri_template:, name:, title: nil, description: nil, icons: [], mime_type: nil, meta: nil)
88
@uri_template = uri_template
99
@name = name
1010
@title = title
1111
@description = description
1212
@icons = icons
1313
@mime_type = mime_type
14+
@meta = meta
1415
end
1516

1617
def to_h
@@ -21,6 +22,7 @@ def to_h
2122
description: description,
2223
icons: icons&.then { |icons| icons.empty? ? nil : icons.map(&:to_h) },
2324
mimeType: mime_type,
25+
_meta: meta,
2426
}.compact
2527
end
2628
end

lib/mcp/tool/response.rb

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ class Tool
55
class Response
66
NOT_GIVEN = Object.new.freeze
77

8-
attr_reader :content, :structured_content
8+
attr_reader :content, :structured_content, :meta
99

10-
def initialize(content = nil, deprecated_error = NOT_GIVEN, error: false, structured_content: nil)
10+
def initialize(content = nil, deprecated_error = NOT_GIVEN, error: false, structured_content: nil, meta: nil)
1111
if deprecated_error != NOT_GIVEN
1212
warn("Passing `error` with the 2nd argument of `Response.new` is deprecated. Use keyword argument like `Response.new(content, error: error)` instead.", uplevel: 1)
1313
error = deprecated_error
@@ -16,14 +16,15 @@ def initialize(content = nil, deprecated_error = NOT_GIVEN, error: false, struct
1616
@content = content || []
1717
@error = error
1818
@structured_content = structured_content
19+
@meta = meta
1920
end
2021

2122
def error?
2223
!!@error
2324
end
2425

2526
def to_h
26-
{ content: content, isError: error?, structuredContent: @structured_content }.compact
27+
{ content: content, isError: error?, structuredContent: @structured_content, _meta: meta }.compact
2728
end
2829
end
2930
end

test/mcp/content_test.rb

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,19 @@ class ImageTest < ActiveSupport::TestCase
2828

2929
refute result.key?(:annotations)
3030
end
31+
32+
test "#to_h with meta" do
33+
meta = { "application/vnd.ant.mcp-app" => { "csp" => "default-src 'self'" } }
34+
image = Image.new("base64data", "image/png", meta: meta)
35+
36+
assert_equal meta, image.to_h[:_meta]
37+
end
38+
39+
test "#to_h without meta omits the key" do
40+
image = Image.new("base64data", "image/png")
41+
42+
refute image.to_h.key?(:_meta)
43+
end
3144
end
3245

3346
class AudioTest < ActiveSupport::TestCase
@@ -53,6 +66,19 @@ class AudioTest < ActiveSupport::TestCase
5366

5467
refute result.key?(:annotations)
5568
end
69+
70+
test "#to_h with meta" do
71+
meta = { "application/vnd.ant.mcp-app" => { "csp" => "default-src 'self'" } }
72+
audio = Audio.new("base64data", "audio/wav", meta: meta)
73+
74+
assert_equal meta, audio.to_h[:_meta]
75+
end
76+
77+
test "#to_h without meta omits the key" do
78+
audio = Audio.new("base64data", "audio/wav")
79+
80+
refute audio.to_h.key?(:_meta)
81+
end
5682
end
5783

5884
class EmbeddedResourceTest < ActiveSupport::TestCase
@@ -92,6 +118,52 @@ def resource.to_h
92118

93119
refute result.key?(:annotations)
94120
end
121+
122+
test "#to_h with meta" do
123+
resource = Object.new
124+
def resource.to_h
125+
{ uri: "test://x" }
126+
end
127+
128+
meta = { "application/vnd.ant.mcp-app" => { "csp" => "default-src 'self'" } }
129+
embedded = EmbeddedResource.new(resource, meta: meta)
130+
131+
assert_equal meta, embedded.to_h[:_meta]
132+
end
133+
134+
test "#to_h without meta omits the key" do
135+
resource = Object.new
136+
def resource.to_h
137+
{ uri: "test://x" }
138+
end
139+
140+
embedded = EmbeddedResource.new(resource)
141+
142+
refute embedded.to_h.key?(:_meta)
143+
end
144+
end
145+
146+
class TextTest < ActiveSupport::TestCase
147+
test "#to_h returns correct format per MCP spec" do
148+
text = Text.new("hello")
149+
result = text.to_h
150+
151+
assert_equal "text", result[:type]
152+
assert_equal "hello", result[:text]
153+
end
154+
155+
test "#to_h with meta" do
156+
meta = { "application/vnd.ant.mcp-app" => { "csp" => "default-src 'self'" } }
157+
text = Text.new("hello", meta: meta)
158+
159+
assert_equal meta, text.to_h[:_meta]
160+
end
161+
162+
test "#to_h without meta omits the key" do
163+
text = Text.new("hello")
164+
165+
refute text.to_h.key?(:_meta)
166+
end
95167
end
96168
end
97169
end

test/mcp/prompt/result_test.rb

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# frozen_string_literal: true
2+
3+
require "test_helper"
4+
5+
module MCP
6+
class Prompt
7+
class ResultTest < ActiveSupport::TestCase
8+
test "#to_h returns description and messages" do
9+
result = Prompt::Result.new(
10+
description: "a prompt",
11+
messages: [Prompt::Message.new(role: "user", content: Content::Text.new("hi"))],
12+
)
13+
14+
hash = result.to_h
15+
16+
assert_equal "a prompt", hash[:description]
17+
assert_equal 1, hash[:messages].size
18+
end
19+
20+
test "#to_h includes _meta when present" do
21+
meta = { "application/vnd.ant.mcp-app" => { "csp" => "default-src 'self'" } }
22+
result = Prompt::Result.new(
23+
description: "a prompt",
24+
messages: [Prompt::Message.new(role: "user", content: Content::Text.new("hi"))],
25+
meta: meta,
26+
)
27+
28+
assert_equal meta, result.to_h[:_meta]
29+
end
30+
31+
test "#to_h omits _meta when nil" do
32+
result = Prompt::Result.new(
33+
description: "a prompt",
34+
messages: [Prompt::Message.new(role: "user", content: Content::Text.new("hi"))],
35+
)
36+
37+
refute result.to_h.key?(:_meta)
38+
end
39+
end
40+
end
41+
end

0 commit comments

Comments
 (0)