From 91ff179d788a4585d79de895e5b517eb029cd69e Mon Sep 17 00:00:00 2001 From: Yuki Minamiya Date: Sun, 7 Jun 2026 16:32:21 +0900 Subject: [PATCH] Add `size` field to `MCP::Resource` per MCP specification ## Motivation and Context The MCP specification defines an optional `size` field on the `Resource` type, added in spec revision 2025-06-18 and retained in 2025-11-25: https://modelcontextprotocol.io/specification/2025-11-25/server/resources > The size of the raw resource content, in bytes (i.e., before base64 > encoding or any tokenization), if known. This can be used by Hosts to > display file sizes and estimate context window usage. `MCP::Resource` was missing this field, so servers had no way to declare a resource's byte size. Without it, hosts cannot show file sizes or estimate context window usage before reading the resource contents. This aligns the Ruby SDK with the spec, matching the TypeScript SDK (modelcontextprotocol/typescript-sdk#1574). ## How Has This Been Tested? Added tests in `test/mcp/resource_test.rb`: - `#to_h` omits `size` when nil - `#to_h` includes `size` when present - `#to_h` includes `size` when zero (distinguishes an unset size from a 0-byte resource) The full unit suite and RuboCop pass locally. ## Breaking Changes None. `size:` is a new optional keyword argument defaulting to `nil`, and it is omitted from `#to_h` output when not set, so existing callers are unaffected. --- lib/mcp/resource.rb | 6 ++++-- test/mcp/resource_test.rb | 18 ++++++++++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/lib/mcp/resource.rb b/lib/mcp/resource.rb index 990156b4..e4e55fcd 100644 --- a/lib/mcp/resource.rb +++ b/lib/mcp/resource.rb @@ -5,15 +5,16 @@ module MCP class Resource - attr_reader :uri, :name, :title, :description, :icons, :mime_type, :meta + attr_reader :uri, :name, :title, :description, :icons, :mime_type, :size, :meta - def initialize(uri:, name:, title: nil, description: nil, icons: [], mime_type: nil, meta: nil) + def initialize(uri:, name:, title: nil, description: nil, icons: [], mime_type: nil, size: nil, meta: nil) @uri = uri @name = name @title = title @description = description @icons = icons @mime_type = mime_type + @size = size @meta = meta end @@ -25,6 +26,7 @@ def to_h description: description, icons: icons&.then { |icons| icons.empty? ? nil : icons.map(&:to_h) }, mimeType: mime_type, + size: size, _meta: meta, }.compact end diff --git a/test/mcp/resource_test.rb b/test/mcp/resource_test.rb index fb2254d4..a3d6a1b8 100644 --- a/test/mcp/resource_test.rb +++ b/test/mcp/resource_test.rb @@ -49,5 +49,23 @@ class ResourceTest < ActiveSupport::TestCase assert_equal meta, resource.to_h[:_meta] end + + test "#to_h omits size when nil" do + resource = Resource.new(uri: "file:///test.txt", name: "resource_without_size") + + refute resource.to_h.key?(:size) + end + + test "#to_h includes size when present" do + resource = Resource.new(uri: "file:///test.txt", name: "resource_with_size", size: 12_345) + + assert_equal 12_345, resource.to_h[:size] + end + + test "#to_h includes size when zero" do + resource = Resource.new(uri: "file:///empty.txt", name: "empty_resource", size: 0) + + assert_equal 0, resource.to_h[:size] + end end end