Class: ActionMCP::Prompt

Inherits:
Capability show all
Includes:
Callbacks, CurrentHelpers
Defined in:
lib/action_mcp/prompt.rb

Overview

Abstract base class for Prompts

Direct Known Subclasses

ApplicationMCPPrompt

Instance Attribute Summary

Attributes inherited from Capability

#execution_context

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Capability

abstract!, abstract?, capability_name, description, #initialize, #session, #with_context

Methods included from Renderable

#render_resource_link

Constructor Details

This class inherits a constructor from ActionMCP::Capability

Class Method Details

.argument(arg_name, description: "", required: false, default: nil, enum: nil, type: :string) ⇒ void

This method returns an undefined value.


Argument DSL


Defines an argument for the prompt.

Parameters:

  • arg_name (Symbol)

    The name of the argument.

  • description (String) (defaults to: "")

    The description of the argument.

  • required (Boolean) (defaults to: false)

    Whether the argument is required.

  • default (Object) (defaults to: nil)

    The default value of the argument.

  • enum (Array<String>) (defaults to: nil)

    The list of allowed values for the argument.

  • type (Symbol) (defaults to: :string)

    The type of the argument (e.g., :string, :integer, :boolean). Defaults to :string.



79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/action_mcp/prompt.rb', line 79

def self.argument(arg_name, description: "", required: false, default: nil, enum: nil, type: :string)
  arg_def = {
    name: arg_name.to_s,
    description: description,
    required: required,
    default: default,
    enum: enum
  }
  self._argument_definitions += [ arg_def ]

  # Register the attribute so it's recognized by ActiveModel
  attribute arg_name, type, default: default
  validates arg_name, presence: true if required

  return unless enum.present?

  validates arg_name, inclusion: { in: enum }, allow_blank: !required
end

.argumentsArray<Hash>

Returns the list of argument definitions.

Returns:

  • (Array<Hash>)

    The list of argument definitions.



101
102
103
# File 'lib/action_mcp/prompt.rb', line 101

def self.arguments
  _argument_definitions
end

.call(params) ⇒ PromptResponse


Class-level call method


Receives a Hash of params, initializes a prompt instance, validates it, and if valid, calls the instance call method. If invalid, raises a JsonRpcError with code :invalid_params.

Parameters:

  • params (Hash)

    The parameters for the prompt.

Returns:



131
132
133
134
135
136
# File 'lib/action_mcp/prompt.rb', line 131

def self.call(params)
  prompt = new(params) # Initialize an instance with provided params

  # If we reach here, the prompt is valid
  prompt.call
end

.default_prompt_nameString Also known as: default_capability_name

Returns the default prompt name based on the class name.

Returns:

  • (String)

    The default prompt name.



29
30
31
32
33
# File 'lib/action_mcp/prompt.rb', line 29

def self.default_prompt_name
  return "" if name.nil?

  name.demodulize.underscore.sub(/_prompt$/, "")
end

.inherited(subclass) ⇒ Object

Hook called when a class inherits from Prompt



47
48
49
50
51
52
53
# File 'lib/action_mcp/prompt.rb', line 47

def inherited(subclass)
  super
  # Run the ActiveSupport load hook when a prompt is defined
  subclass.class_eval do
    ActiveSupport.run_load_hooks(:action_mcp_prompt, subclass)
  end
end

.meta(data = nil) ⇒ Object

Sets or retrieves the _meta field



56
57
58
59
60
61
62
63
64
# File 'lib/action_mcp/prompt.rb', line 56

def meta(data = nil)
  if data
    raise ArgumentError, "_meta must be a hash" unless data.is_a?(Hash)

    self._meta = _meta.merge(data)
  else
    _meta
  end
end

.prompt_name(name = nil) ⇒ String


Prompt Name


Gets or sets the prompt name.

Parameters:

  • name (String, nil) (defaults to: nil)

    The prompt name to set.

Returns:

  • (String)

    The prompt name.



18
19
20
21
22
23
24
# File 'lib/action_mcp/prompt.rb', line 18

def self.prompt_name(name = nil)
  if name
    self._capability_name = name
  else
    _capability_name || default_prompt_name
  end
end

.to_hHash


Convert prompt definition to Hash


Returns:

  • (Hash)

    The prompt definition as a Hash.



109
110
111
112
113
114
115
116
117
118
119
120
# File 'lib/action_mcp/prompt.rb', line 109

def self.to_h
  result = {
    name: prompt_name,
    description: description.presence,
    arguments: arguments.map { |arg| arg.slice(:name, :description, :required, :type) }
  }.compact

  # Add _meta if present
  result[:_meta] = _meta if _meta.any?

  result
end

.typeObject



38
39
40
# File 'lib/action_mcp/prompt.rb', line 38

def type
  :prompt
end

.unregister_from_registryObject



42
43
44
# File 'lib/action_mcp/prompt.rb', line 42

def unregister_from_registry
  ActionMCP::PromptsRegistry.unregister(self) if ActionMCP::PromptsRegistry.items.values.include?(self)
end

Instance Method Details

#callObject

Public entry point for executing the prompt Returns a PromptResponse object containing messages



144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
# File 'lib/action_mcp/prompt.rb', line 144

def call
  @response = PromptResponse.new

  # Check validations before proceeding
  if valid?
    begin
      run_callbacks :perform do
        perform # Invoke the subclass-specific logic if valid
      end
    rescue StandardError
      # Handle exceptions during execution
      @response.mark_as_error!(:internal_error, message: "Unhandled Error executing prompt")
    end
  else
    # Handle validation failure
    @response.mark_as_error!(:invalid_params, message: "Invalid input", data: errors.full_messages)
  end

  @response # Return the response with collected messages
end

#inspectObject



165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
# File 'lib/action_mcp/prompt.rb', line 165

def inspect
  attributes_hash = attributes.transform_values(&:inspect)

  response_info = if defined?(@response) && @response
                    "response: #{@response.messages.size} message(s)"
  else
                    "response: nil"
  end

  errors_info = errors.any? ? ", errors: #{errors.full_messages}" : ""

  "#<#{self.class.name} #{attributes_hash.map do |k, v|
    "#{k}: #{v.inspect}"
  end.join(', ')}, #{response_info}#{errors_info}>"
end

#render(**args) ⇒ Object

Override render to collect messages



182
183
184
185
186
# File 'lib/action_mcp/prompt.rb', line 182

def render(**args)
  content = super(**args.slice(:text, :audio, :image, :resource, :mime_type, :blob))
  @response.add_content(content, role: args.fetch(:role, "user")) # Add to the response
  content # Return the content for potential use in perform
end