Class: Hitch::MCP::Tool
- Inherits:
-
Object
- Object
- Hitch::MCP::Tool
- Defined in:
- app/models/hitch/mcp/tool.rb
Overview
Declarative MCP tool descriptor. Registry admission, listing, and later execution resolve the current named subclass; instances are never needed.
Class Method Summary collapse
- .annotations(value = NOT_SET, **keywords) ⇒ Object
-
.authorize!(_context, arguments:) ⇒ Object
Argument-aware host policy is deny-default.
-
.available_to?(_context) ⇒ Boolean
Coarse request-local admission.
-
.call(server_context:, **sdk_arguments) ⇒ Object
This SDK-facing boundary is final.
- .description(value = NOT_SET) ⇒ Object
- .inherited(subclass) ⇒ Object
- .input_schema(value = NOT_SET, **keywords) ⇒ Object
- .output_schema(value = NOT_SET, **keywords) ⇒ Object
-
.perform(_context, arguments:) ⇒ Object
Host behavior runs only after availability, static scope, SDK schema, and argument-aware policy have all admitted the invocation.
- .tool_name(value = NOT_SET) ⇒ Object
Class Method Details
.annotations(value = NOT_SET, **keywords) ⇒ Object
54 55 56 57 58 |
# File 'app/models/hitch/mcp/tool.rb', line 54 def annotations(value = NOT_SET, **keywords) return @annotations if value.equal?(NOT_SET) && keywords.empty? @annotations = copy_declaration(combine_value_and_keywords(value, keywords)) end |
.authorize!(_context, arguments:) ⇒ Object
Argument-aware host policy is deny-default. Its return value is not an authority signal: allowing means returning without raising.
68 69 70 |
# File 'app/models/hitch/mcp/tool.rb', line 68 def (_context, arguments:) raise Forbidden end |
.available_to?(_context) ⇒ Boolean
Coarse request-local admission. Host applications must opt each tool in explicitly.
62 63 64 |
# File 'app/models/hitch/mcp/tool.rb', line 62 def available_to?(_context) false end |
.call(server_context:, **sdk_arguments) ⇒ Object
This SDK-facing boundary is final. Registry validation rejects any subclass that replaces it, so every invocation follows the same context extraction, argument normalization, policy, host, and Result normalization order.
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 107 108 109 110 111 112 113 114 115 116 117 |
# File 'app/models/hitch/mcp/tool.rb', line 82 def call(server_context:, **sdk_arguments) phase = :context invocation = nil reporting_tool_name = tool_name context = server_context.fetch(:hitch_context) phase = :arguments arguments = normalize_arguments(sdk_arguments) invocation = Internal::Observation.start_invocation(tool_name: reporting_tool_name) phase = :authorization (context, arguments:) invocation&.argument_policy_allowed! phase = :execution invocation&.execution_started! result = perform(context, arguments:) phase = :result normalized = Internal::ResultNormalizer.call( result:, output_schema: output_schema, max_bytes: Hitch.configuration.mcp.max_result_bytes ) invocation&.result_normalized!(kind: result.kind) normalized rescue StandardError, SystemStackError => error invocation&.failed!( phase:, expected_denial: phase == :authorization && error.is_a?(Hitch::MCP::Forbidden) ) Internal::ErrorNormalizer.call( error:, phase:, context:, tool_name: reporting_tool_name ) ensure invocation&.finish! end |
.description(value = NOT_SET) ⇒ Object
36 37 38 39 40 |
# File 'app/models/hitch/mcp/tool.rb', line 36 def description(value = NOT_SET) return @description if value.equal?(NOT_SET) @description = copy_declaration(value) end |
.inherited(subclass) ⇒ Object
21 22 23 24 25 26 27 28 |
# File 'app/models/hitch/mcp/tool.rb', line 21 def inherited(subclass) super subclass.instance_variable_set(:@tool_name, nil) subclass.instance_variable_set(:@description, nil) subclass.instance_variable_set(:@input_schema, nil) subclass.instance_variable_set(:@output_schema, nil) subclass.instance_variable_set(:@annotations, nil) end |
.input_schema(value = NOT_SET, **keywords) ⇒ Object
42 43 44 45 46 |
# File 'app/models/hitch/mcp/tool.rb', line 42 def input_schema(value = NOT_SET, **keywords) return @input_schema if value.equal?(NOT_SET) && keywords.empty? @input_schema = copy_declaration(combine_value_and_keywords(value, keywords)) end |
.output_schema(value = NOT_SET, **keywords) ⇒ Object
48 49 50 51 52 |
# File 'app/models/hitch/mcp/tool.rb', line 48 def output_schema(value = NOT_SET, **keywords) return @output_schema if value.equal?(NOT_SET) && keywords.empty? @output_schema = copy_declaration(combine_value_and_keywords(value, keywords)) end |
.perform(_context, arguments:) ⇒ Object
Host behavior runs only after availability, static scope, SDK schema, and argument-aware policy have all admitted the invocation.
74 75 76 |
# File 'app/models/hitch/mcp/tool.rb', line 74 def perform(_context, arguments:) raise "MCP tool perform must be implemented" end |
.tool_name(value = NOT_SET) ⇒ Object
30 31 32 33 34 |
# File 'app/models/hitch/mcp/tool.rb', line 30 def tool_name(value = NOT_SET) return @tool_name if value.equal?(NOT_SET) @tool_name = copy_declaration(value) end |