Class: MCPClient::Tool

Inherits:
Object
  • Object
show all
Includes:
DeepCopy
Defined in:
lib/mcp_client/tool.rb

Overview

Representation of an MCP tool

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from DeepCopy

copy, #initialize_copy, shallow_copy

Constructor Details

#initialize(name:, description:, schema:, title: nil, output_schema: nil, annotations: nil, server: nil, task_support: nil, icons: nil, meta: nil, output_schema_declared: nil) ⇒ Tool

Initialize a new Tool

Parameters:

  • name (String) —

    the name of the tool

  • description (String) —

    the description of the tool

  • schema (Hash) —

    the JSON schema for the tool inputs

  • title (String, nil) (defaults to: nil) —

    optional human-readable name of the tool for display purposes

  • output_schema (Hash, nil) (defaults to: nil) —

    optional JSON schema for structured tool outputs (MCP 2025-06-18)

  • annotations (Hash, nil) (defaults to: nil) —

    optional annotations describing tool behavior

  • server (MCPClient::ServerBase, nil) (defaults to: nil) —

    the server this tool belongs to

  • task_support (String, nil) (defaults to: nil) —

    execution.taskSupport value (MCP 2025-11-25)

  • icons (Array<Hash>, nil) (defaults to: nil) —

    optional icons for display in user interfaces (MCP 2025-11-25)

  • meta (Hash, nil) (defaults to: nil) —

    optional _meta metadata attached to the tool (MCP 2025-11-25)

  • output_schema_declared (Boolean, nil) (defaults to: nil) —

    whether the definition carried an outputSchema member at all; nil means "whenever a schema was given"



54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# File 'lib/mcp_client/tool.rb', line 54

def initialize(name:, description:, schema:, title: nil, output_schema: nil, annotations: nil, server: nil,
               task_support: nil, icons: nil, meta: nil, output_schema_declared: nil)
  @name = name
  @title = title
  @description = description
  @schema = schema
  @output_schema = output_schema
  # An explicit `"outputSchema": null` declares a schema — an unusable
  # one — and is not the same as leaving the member out.
  @output_schema_declared = output_schema_declared.nil? ? !output_schema.nil? : output_schema_declared
  @annotations = annotations
  @server = server
  @task_support = task_support
  @icons = icons
  @meta = meta
  # A frozen object is copied by reference by DeepCopy, so the token
  # survives every copy of this definition.
  @schema_identity = Object.new.freeze
end

Instance Attribute Details

#annotations ⇒ Hash? (readonly)

Returns optional annotations describing tool behavior (e.g., readOnly, destructive).

Returns:

  • (Hash, nil) —

    optional annotations describing tool behavior (e.g., readOnly, destructive)



31
32
# File 'lib/mcp_client/tool.rb', line 31

attr_reader :name, :title, :description, :schema, :output_schema, :annotations, :server, :task_support,
:icons, :meta

#description ⇒ String (readonly)

Returns the description of the tool.

Returns:

  • (String) —

    the description of the tool



31
32
# File 'lib/mcp_client/tool.rb', line 31

attr_reader :name, :title, :description, :schema, :output_schema, :annotations, :server, :task_support,
:icons, :meta

#icons ⇒ Array<Hash>? (readonly)

Returns optional icons for display in user interfaces (MCP 2025-11-25, SEP-973).

Returns:

  • (Array<Hash>, nil) —

    optional icons for display in user interfaces (MCP 2025-11-25, SEP-973)



31
32
# File 'lib/mcp_client/tool.rb', line 31

attr_reader :name, :title, :description, :schema, :output_schema, :annotations, :server, :task_support,
:icons, :meta

#meta ⇒ Object (readonly)

Returns the value of attribute meta.



31
32
# File 'lib/mcp_client/tool.rb', line 31

attr_reader :name, :title, :description, :schema, :output_schema, :annotations, :server, :task_support,
:icons, :meta

#name ⇒ String (readonly)

Returns the name of the tool.

Returns:

  • (String) —

    the name of the tool



31
32
33
# File 'lib/mcp_client/tool.rb', line 31

def name
  @name
end

#output_schema ⇒ Hash? (readonly)

Returns optional JSON schema for structured tool outputs (MCP 2025-06-18).

Returns:

  • (Hash, nil) —

    optional JSON schema for structured tool outputs (MCP 2025-06-18)



31
32
# File 'lib/mcp_client/tool.rb', line 31

attr_reader :name, :title, :description, :schema, :output_schema, :annotations, :server, :task_support,
:icons, :meta

#schema ⇒ Hash (readonly)

Returns the JSON schema for the tool inputs.

Returns:

  • (Hash) —

    the JSON schema for the tool inputs



31
32
# File 'lib/mcp_client/tool.rb', line 31

attr_reader :name, :title, :description, :schema, :output_schema, :annotations, :server, :task_support,
:icons, :meta

#schema_identity ⇒ Object (readonly)

Returns the value of attribute schema_identity.



39
40
41
# File 'lib/mcp_client/tool.rb', line 39

def schema_identity
  @schema_identity
end

#server ⇒ MCPClient::ServerBase? (readonly)

Returns the server this tool belongs to.

Returns:



31
32
# File 'lib/mcp_client/tool.rb', line 31

attr_reader :name, :title, :description, :schema, :output_schema, :annotations, :server, :task_support,
:icons, :meta

#task_support ⇒ String? (readonly)

Returns tool-level task negotiation (MCP 2025-11-25): 'forbidden' (default), 'optional', or 'required'; nil when not advertised.

Returns:

  • (String, nil) —

    tool-level task negotiation (MCP 2025-11-25): 'forbidden' (default), 'optional', or 'required'; nil when not advertised



31
32
# File 'lib/mcp_client/tool.rb', line 31

attr_reader :name, :title, :description, :schema, :output_schema, :annotations, :server, :task_support,
:icons, :meta

#title ⇒ String? (readonly)

Returns optional human-readable name of the tool for display purposes.

Returns:

  • (String, nil) —

    optional human-readable name of the tool for display purposes



31
32
# File 'lib/mcp_client/tool.rb', line 31

attr_reader :name, :title, :description, :schema, :output_schema, :annotations, :server, :task_support,
:icons, :meta

Class Method Details

.from_json(data, server: nil) ⇒ MCPClient::Tool

Create a Tool instance from JSON data

Parameters:

  • data (Hash) —

    JSON data from MCP server

  • server (MCPClient::ServerBase, nil) (defaults to: nil) —

    the server this tool belongs to

Returns:



78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/mcp_client/tool.rb', line 78

def self.from_json(data, server: nil)
  # Some servers (Playwright MCP CLI) use 'inputSchema' instead of 'schema'
  # Handle both string and symbol keys
  schema = data['inputSchema'] || data[:inputSchema] || data['schema'] || data[:schema]
  # By key presence: a boolean false schema is a schema (one that
  # accepts nothing), not an absent one, and neither is an explicit null
  # (an unusable schema root, like any other non-schema value).
  output_schema_declared = data.key?('outputSchema') || data.key?(:outputSchema)
  output_schema = data.key?('outputSchema') ? data['outputSchema'] : data[:outputSchema]
  annotations = data['annotations'] || data[:annotations]
  title = data['title'] || data[:title]
  execution = data['execution'] || data[:execution]
  task_support = execution && (execution['taskSupport'] || execution[:taskSupport])
  icons = data['icons'] || data[:icons]
  meta = data['_meta'] || data[:_meta]
  new(
    name: data['name'] || data[:name],
    description: data['description'] || data[:description],
    schema: schema,
    title: title,
    output_schema: output_schema,
    output_schema_declared: output_schema_declared,
    annotations: annotations,
    server: server,
    task_support: task_support,
    icons: icons,
    meta: meta
  )
end

Instance Method Details

#destructive? ⇒ Boolean

Check if the tool is marked as destructive (legacy annotation field)

Returns:

  • (Boolean) —

    true if the tool is destructive

See Also:



151
152
153
# File 'lib/mcp_client/tool.rb', line 151

def destructive?
  !!(@annotations && @annotations['destructive'] == true)
end

#destructive_hint? ⇒ Boolean

Check the destructiveHint annotation (MCP 2025-11-25) When true, the tool may perform destructive updates. Only meaningful when readOnlyHint is false. Per the MCP ToolAnnotations schema the default is true, i.e. a non-read-only tool without this hint is assumed to be potentially destructive.

Returns:

  • (Boolean) —

    defaults to true when not specified



178
179
180
181
182
# File 'lib/mcp_client/tool.rb', line 178

def destructive_hint?
  return true unless @annotations

  fetch_annotation_hint('destructiveHint', :destructiveHint, true)
end

#idempotent_hint? ⇒ Boolean

Check the idempotentHint annotation (MCP 2025-11-25) When true, calling the tool repeatedly with the same arguments has no additional effect. Only meaningful when readOnlyHint is false.

Returns:

  • (Boolean) —

    defaults to false when not specified



188
189
190
191
192
# File 'lib/mcp_client/tool.rb', line 188

def idempotent_hint?
  return false unless @annotations

  fetch_annotation_hint('idempotentHint', :idempotentHint, false)
end

#open_world_hint? ⇒ Boolean

Check the openWorldHint annotation (MCP 2025-11-25) When true, the tool may interact with the "open world" (external entities).

Returns:

  • (Boolean) —

    defaults to true when not specified



197
198
199
200
201
# File 'lib/mcp_client/tool.rb', line 197

def open_world_hint?
  return true unless @annotations

  fetch_annotation_hint('openWorldHint', :openWorldHint, true)
end

#read_only? ⇒ Boolean

Check if the tool is marked as read-only (legacy annotation field)

Returns:

  • (Boolean) —

    true if the tool is read-only

See Also:



144
145
146
# File 'lib/mcp_client/tool.rb', line 144

def read_only?
  !!(@annotations && @annotations['readOnly'] == true)
end

#read_only_hint? ⇒ Boolean

Check the readOnlyHint annotation (MCP 2025-11-25) When true, the tool does not modify its environment. Per the MCP ToolAnnotations schema the default is false, i.e. a tool without this hint is assumed to potentially modify its environment.

Returns:

  • (Boolean) —

    defaults to false when not specified



166
167
168
169
170
# File 'lib/mcp_client/tool.rb', line 166

def read_only_hint?
  return false unless @annotations

  fetch_annotation_hint('readOnlyHint', :readOnlyHint, false)
end

#requires_confirmation? ⇒ Boolean

Check if the tool requires confirmation before execution

Returns:

  • (Boolean) —

    true if the tool requires confirmation



157
158
159
# File 'lib/mcp_client/tool.rb', line 157

def requires_confirmation?
  !!(@annotations && @annotations['requiresConfirmation'] == true)
end

#structured_output? ⇒ Boolean

Check if the tool supports structured outputs (MCP 2025-06-18)

Returns:

  • (Boolean) —

    true if the tool has an output schema defined



205
206
207
208
209
210
211
# File 'lib/mcp_client/tool.rb', line 205

def structured_output?
  # Any declared schema counts: a boolean schema (true: any value;
  # false: none), the empty schema `{}` (any value) and an explicit null
  # (a schema root the validator rejects) included. Only the absence of
  # outputSchema means no structured output.
  @output_schema_declared
end

#supports_task? ⇒ Boolean

Whether task-augmented execution is allowed for this tool (MCP 2025-11-25). True when execution.taskSupport is 'optional' or 'required'.

Returns:

  • (Boolean)


216
217
218
# File 'lib/mcp_client/tool.rb', line 216

def supports_task?
  %w[optional required].include?(@task_support)
end

#task_forbidden? ⇒ Boolean

Whether task-augmented execution is forbidden (the default when unset)

Returns:

  • (Boolean)


234
235
236
# File 'lib/mcp_client/tool.rb', line 234

def task_forbidden?
  @task_support.nil? || @task_support == 'forbidden'
end

#task_optional? ⇒ Boolean

Whether task-augmented execution is optional for this tool

Returns:

  • (Boolean)


228
229
230
# File 'lib/mcp_client/tool.rb', line 228

def task_optional?
  @task_support == 'optional'
end

#task_required? ⇒ Boolean

Whether task-augmented execution is required for this tool

Returns:

  • (Boolean)


222
223
224
# File 'lib/mcp_client/tool.rb', line 222

def task_required?
  @task_support == 'required'
end

#to_anthropic_tool ⇒ Hash

Convert tool to Anthropic Claude tool specification format

Returns:

  • (Hash) —

    Anthropic Claude tool specification with cleaned schema



123
124
125
126
127
128
129
# File 'lib/mcp_client/tool.rb', line 123

def to_anthropic_tool
  {
    name: @name,
    description: @description,
    input_schema: cleaned_schema(@schema)
  }
end

#to_google_tool ⇒ Hash

Convert tool to Google Vertex AI tool specification format

Returns:

  • (Hash) —

    Google Vertex AI tool specification with cleaned schema



133
134
135
136
137
138
139
# File 'lib/mcp_client/tool.rb', line 133

def to_google_tool
  {
    name: @name,
    description: @description,
    parameters: cleaned_schema(@schema)
  }
end

#to_openai_tool ⇒ Hash

Convert tool to OpenAI function specification format

Returns:

  • (Hash) —

    OpenAI function specification



110
111
112
113
114
115
116
117
118
119
# File 'lib/mcp_client/tool.rb', line 110

def to_openai_tool
  {
    type: 'function',
    function: {
      name: @name,
      description: @description,
      parameters: @schema
    }
  }
end