diff --git a/lib/mcp/annotations.rb b/lib/mcp/annotations.rb index 88bead5..50eb0eb 100644 --- a/lib/mcp/annotations.rb +++ b/lib/mcp/annotations.rb @@ -1,18 +1,13 @@ # frozen_string_literal: true module MCP - class Annotations - attr_reader :audience, :priority - + Annotations = Data.define(:audience, :priority) do def initialize(audience: nil, priority: nil) - @audience = audience - @priority = priority - - freeze + super(audience:, priority:) end def to_h - { audience:, priority: }.compact.freeze + super.compact.freeze end end end diff --git a/lib/mcp/content.rb b/lib/mcp/content.rb index 65fc11f..e9cf283 100644 --- a/lib/mcp/content.rb +++ b/lib/mcp/content.rb @@ -3,30 +3,24 @@ module MCP module Content - class Text - attr_reader :text, :annotations - + Text = Data.define(:text, :annotations) do def initialize(text, annotations: nil) - @text = text - @annotations = annotations + super(text:, annotations:) end def to_h - { text:, annotations:, type: "text" }.compact + { **super, type: "text" }.compact.freeze end end - class Image - attr_reader :data, :mime_type, :annotations - + Image = Data.define(:data, :mime_type, :annotations) do def initialize(data, mime_type, annotations: nil) - @data = data - @mime_type = mime_type - @annotations = annotations + super(data:, mime_type:, annotations:) end + # FIXME: mime_type should probably turn into mimeType def to_h - { data:, mime_type:, annotations:, type: "image" }.compact + { **super, type: "image" }.compact.freeze end end end diff --git a/lib/mcp/prompt.rb b/lib/mcp/prompt.rb index 1a260f7..1a6ce6a 100644 --- a/lib/mcp/prompt.rb +++ b/lib/mcp/prompt.rb @@ -2,8 +2,8 @@ # frozen_string_literal: true module MCP - class Prompt - attr_reader :name, :description, :arguments, :to_h + Prompt = Data.define(:name, :description, :arguments) do + attr_reader :to_h class << self def define(...) = new(...) @@ -20,18 +20,12 @@ def inherited(subclass) def initialize(name:, description:, arguments:, &block) arguments = arguments.map { |arg| Hash === arg ? Argument.new(**arg) : arg } - @name = name - @description = description - @arguments = arguments @block = block - @to_h = { name:, description:, arguments: arguments.map(&:to_h) }.compact.freeze - freeze + super(name:, description:, arguments:) end - def call(args, server_context:) - @block.call(args, server_context:) - end + def call(args, server_context:) = @block.call(args, server_context:) end end diff --git a/lib/mcp/prompt/argument.rb b/lib/mcp/prompt/argument.rb index 307099a..57ec050 100644 --- a/lib/mcp/prompt/argument.rb +++ b/lib/mcp/prompt/argument.rb @@ -3,21 +3,17 @@ module MCP class Prompt - class Argument - attr_reader :name, :description, :required, :to_h + Argument = Data.define(:name, :description, :required) do + attr_reader :to_h def initialize(name:, description: nil, required: false) - @name = name - @description = description - @required = required - @to_h = { name:, description:, required:, }.compact.freeze - freeze + super(name:, description:, required:) end end end diff --git a/lib/mcp/prompt/message.rb b/lib/mcp/prompt/message.rb index b5c94f9..f0d2ebc 100644 --- a/lib/mcp/prompt/message.rb +++ b/lib/mcp/prompt/message.rb @@ -3,16 +3,13 @@ module MCP class Prompt - class Message - attr_reader :role, :content - + Message = Data.define(:role, :content) do def initialize(role:, content:) - @role = role - @content = content + super(role:, content:) end def to_h - { role:, content: content.to_h }.compact + { role:, content: content.to_h }.compact.freeze end end end diff --git a/lib/mcp/prompt/result.rb b/lib/mcp/prompt/result.rb index 693885f..8007558 100644 --- a/lib/mcp/prompt/result.rb +++ b/lib/mcp/prompt/result.rb @@ -3,16 +3,13 @@ module MCP class Prompt - class Result - attr_reader :description, :messages - + Result = Data.define(:description, :messages) do def initialize(description: nil, messages: []) - @description = description - @messages = messages + super(description:, messages:) end def to_h - { description:, messages: messages.map(&:to_h) }.compact + { description:, messages: messages.map(&:to_h) }.compact.freeze end end end diff --git a/lib/mcp/resource.rb b/lib/mcp/resource.rb index 95c7db8..143d1e7 100644 --- a/lib/mcp/resource.rb +++ b/lib/mcp/resource.rb @@ -2,23 +2,13 @@ # frozen_string_literal: true module MCP - class Resource - attr_reader :uri, :name, :description, :mime_type - + Resource = Data.define(:uri, :name, :description, :mime_type) do def initialize(uri:, name:, description: nil, mime_type: nil) - @uri = uri - @name = name - @description = description - @mime_type = mime_type + super(uri:, name:, description:, mime_type:) end def to_h - { - uri: @uri, - name: @name, - description: @description, - mimeType: @mime_type, - }.compact + { uri:, name:, description:, mimeType: mime_type }.compact.freeze end end end diff --git a/lib/mcp/resource/contents.rb b/lib/mcp/resource/contents.rb index f49d18f..3adf280 100644 --- a/lib/mcp/resource/contents.rb +++ b/lib/mcp/resource/contents.rb @@ -3,42 +3,36 @@ module MCP class Resource - class Contents - attr_reader :uri, :mime_type + # FIXME: Should mime_type to_h as mimeType? + # FIXME: Is it a problem that we lose inheritance here? + Contents = Data.define(:uri, :mime_type) do def initialize(uri:, mime_type: nil) - @uri = uri - @mime_type = mime_type + super(uri:, mime_type:) end def to_h - { uri:, mime_type: }.compact + { uri:, mime_type: }.compact.freeze end end - class TextContents < Contents - attr_reader :text - + TextContents = Data.define(:text, :uri, :mime_type) do def initialize(text:, uri:, mime_type:) - super(uri:, mime_type:) - @text = text + super(text:, uri:, mime_type:) end def to_h - super.merge(text:) + { text:, uri:, mime_type: }.compact.freeze end end - class BlobContents < Contents - attr_reader :data - + BlobContents = Data.define(:data, :uri, :mime_type) do def initialize(data:, uri:, mime_type:) - super(uri:, mime_type:) - @data = data + super(data:, uri:, mime_type:) end def to_h - super.merge(data:) + { data:, uri:, mime_type: }.compact.freeze end end end diff --git a/lib/mcp/resource/embedded.rb b/lib/mcp/resource/embedded.rb index 66a76d8..94a838b 100644 --- a/lib/mcp/resource/embedded.rb +++ b/lib/mcp/resource/embedded.rb @@ -3,16 +3,13 @@ module MCP class Resource - class Embedded - attr_reader :resource, :annotations - + Embedded = Data.define(:resource, :annotations) do def initialize(resource:, annotations: nil) - @resource = resource - @annotations = annotations + super(resource:, annotations:) end def to_h - { resource: resource.to_h, annotations: }.compact + { resource: resource.to_h, annotations: }.compact.freeze end end end diff --git a/lib/mcp/resource_template.rb b/lib/mcp/resource_template.rb index ab6b46b..8186335 100644 --- a/lib/mcp/resource_template.rb +++ b/lib/mcp/resource_template.rb @@ -2,15 +2,10 @@ # frozen_string_literal: true module MCP - class ResourceTemplate - attr_reader :uri_template, :name, :description, :mime_type, :to_h + ResourceTemplate = Data.define(:uri_template, :name, :description, :mime_type) do + attr_reader :to_h def initialize(uri_template:, name:, description: nil, mime_type: nil) - @uri_template = uri_template - @name = name - @description = description - @mime_type = mime_type - @to_h = { uriTemplate: @uri_template, name: @name, @@ -18,7 +13,7 @@ def initialize(uri_template:, name:, description: nil, mime_type: nil) mimeType: @mime_type, }.compact.freeze - freeze + super(uri_template:, name:, description:, mime_type:) end end end diff --git a/lib/mcp/tool.rb b/lib/mcp/tool.rb index 334e704..12f3e79 100644 --- a/lib/mcp/tool.rb +++ b/lib/mcp/tool.rb @@ -1,8 +1,8 @@ # frozen_string_literal: true module MCP - class Tool - attr_reader :name, :description, :input_schema, :annotations, :to_h + Tool = Data.define(:name, :description, :input_schema, :annotations) do + attr_reader :to_h class << self def define(...) = new(...) @@ -17,16 +17,11 @@ def inherited(subclass) end def initialize(name:, description: nil, input_schema: nil, annotations: nil, &block) - input_schema = InputSchema.new(**input_schema) if Hash === input_schema - annotations = Annotations.new(**annotations) if Hash === annotations + input_schema = Tool::InputSchema.new(**input_schema) if Hash === input_schema + annotations = Tool::Annotations.new(**annotations) if Hash === annotations raise ArgumentError, "Tool definition requires a block" unless block - @name = name - @description = description - @input_schema = input_schema - @annotations = annotations - @block = block - + @block = block @to_h = { name:, description:, @@ -34,7 +29,7 @@ def initialize(name:, description: nil, input_schema: nil, annotations: nil, &bl annotations: annotations&.to_h, }.compact.freeze - freeze + super(name:, description:, input_schema:, annotations:) end def call(args, server_context:) diff --git a/lib/mcp/tool/annotations.rb b/lib/mcp/tool/annotations.rb index dfdafa1..cecbf07 100644 --- a/lib/mcp/tool/annotations.rb +++ b/lib/mcp/tool/annotations.rb @@ -2,16 +2,10 @@ module MCP class Tool - class Annotations - attr_reader :title, :read_only_hint, :destructive_hint, :idempotent_hint, :open_world_hint, :to_h + Annotations = Data.define(:title, :read_only_hint, :destructive_hint, :idempotent_hint, :open_world_hint) do + attr_reader :to_h def initialize(title: nil, read_only_hint: nil, destructive_hint: nil, idempotent_hint: nil, open_world_hint: nil) - @title = title - @read_only_hint = read_only_hint - @destructive_hint = destructive_hint - @idempotent_hint = idempotent_hint - @open_world_hint = open_world_hint - @to_h = { title:, readOnlyHint: read_only_hint, @@ -20,7 +14,7 @@ def initialize(title: nil, read_only_hint: nil, destructive_hint: nil, idempoten openWorldHint: open_world_hint, }.compact.freeze - freeze + super(title:, read_only_hint:, destructive_hint:, idempotent_hint:, open_world_hint:) end end end diff --git a/lib/mcp/tool/input_schema.rb b/lib/mcp/tool/input_schema.rb index dca3a43..dbf225e 100644 --- a/lib/mcp/tool/input_schema.rb +++ b/lib/mcp/tool/input_schema.rb @@ -2,12 +2,12 @@ module MCP class Tool - class InputSchema - attr_reader :properties, :required, :to_h + InputSchema = Data.define(:properties, :required) do + attr_reader :to_h def initialize(properties: {}, required: []) - @properties = properties.transform_keys(&:to_sym) - @required = required.map(&:to_sym) + properties = properties.transform_keys(&:to_sym) + required = required.map(&:to_sym) @to_h = { type: "object", @@ -15,7 +15,7 @@ def initialize(properties: {}, required: []) required:, }.compact.freeze - freeze + super(properties:, required:) end end end diff --git a/lib/mcp/tool/response.rb b/lib/mcp/tool/response.rb index 690f360..3ae9c84 100644 --- a/lib/mcp/tool/response.rb +++ b/lib/mcp/tool/response.rb @@ -2,16 +2,13 @@ module MCP class Tool - class Response - attr_reader :content, :is_error - + Response = Data.define(:content, :is_error) do def initialize(content, is_error: false) - @content = content - @is_error = is_error + super(content:, is_error:) end def to_h - { content:, isError: is_error }.compact + { content:, isError: is_error }.compact.freeze end end end