Class: Legate::Mcp::Server::LegateDirectAgentAdapter
- Inherits:
-
FastMcp::Tool
- Object
- FastMcp::Tool
- Legate::Mcp::Server::LegateDirectAgentAdapter
- Defined in:
- lib/legate/mcp/server/legate_direct_agent_adapter.rb
Overview
Adapter to expose an Legate::Agent instance directly as a single tool via fast-mcp. The agent is used ephemerally for each call.
Class Attribute Summary collapse
-
.legate_agent_instance ⇒ Object
readonly
Returns the value of attribute legate_agent_instance.
-
.session_service ⇒ Object
readonly
Returns the value of attribute session_service.
Class Method Summary collapse
-
.wrap(agent_instance, session_service_instance) ⇒ Class<LegateDirectAgentAdapter>
Dynamically creates a new FastMcp::Tool subclass that wraps the given Legate::Agent instance.
Instance Method Summary collapse
-
#call(prompt:) ⇒ Any
Executes the wrapped Legate Agent instance for a single turn.
Class Attribute Details
.legate_agent_instance ⇒ Object (readonly)
Returns the value of attribute legate_agent_instance.
18 19 20 |
# File 'lib/legate/mcp/server/legate_direct_agent_adapter.rb', line 18 def legate_agent_instance @legate_agent_instance end |
.session_service ⇒ Object (readonly)
Returns the value of attribute session_service.
18 19 20 |
# File 'lib/legate/mcp/server/legate_direct_agent_adapter.rb', line 18 def session_service @session_service end |
Class Method Details
.wrap(agent_instance, session_service_instance) ⇒ Class<LegateDirectAgentAdapter>
Dynamically creates a new FastMcp::Tool subclass that wraps the given Legate::Agent instance.
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
# File 'lib/legate/mcp/server/legate_direct_agent_adapter.rb', line 26 def self.wrap(agent_instance, session_service_instance) raise ArgumentError, 'Provided object is not a valid Legate::Agent instance.' unless agent_instance.is_a?(Legate::Agent) raise ArgumentError, 'Session service instance must inherit from Legate::SessionService::Base.' unless session_service_instance.is_a?(Legate::SessionService::Base) agent_name = agent_instance.name agent_description = agent_instance.description # Create the anonymous adapter class Class.new(LegateDirectAgentAdapter) do # Store instances on the generated class @legate_agent_instance = agent_instance @session_service = session_service_instance # Set fast-mcp tool metadata tool_name "run_agent_#{agent_name}" # Or just agent_name if desired description "Runs the Legate Agent '#{agent_name}': #{agent_description}" # Define the single prompt argument arguments do required(:prompt).filled(:string).description('The user input/prompt for the agent') end Mcp.logger.info("Created direct fast-mcp adapter for Legate agent instance: '#{agent_name}'") end end |
Instance Method Details
#call(prompt:) ⇒ Any
Executes the wrapped Legate Agent instance for a single turn.
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 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 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 |
# File 'lib/legate/mcp/server/legate_direct_agent_adapter.rb', line 57 def call(prompt:) # Retrieve instances from the *class* instance variables agent = self.class.legate_agent_instance session_service = self.class.session_service unless agent && session_service raise NotImplementedError, 'LegateDirectAgentAdapter must be configured using .wrap first.' end agent_name = agent.name Mcp.logger.info("Executing Legate Agent '#{agent_name}' via direct MCP adapter with prompt: '#{prompt}'") temp_session = nil was_agent_already_running = agent.running? begin # 1. Create Temporary Session Mcp.logger.debug('Creating temporary session...') temp_session = session_service.create_session(app_name: agent_name, user_id: "mcp_direct_#{SecureRandom.hex(4)}") Mcp.logger.debug("Temporary session created: #{temp_session.id}") # 2. Ensure Agent is Running unless was_agent_already_running Mcp.logger.debug('Starting ephemeral agent runtime...') agent.start end # 3. Run Task Mcp.logger.debug("Running task in temp session #{temp_session.id}...") final_event = agent.run_task( session_id: temp_session.id, user_input: prompt, session_service: session_service ) Mcp.logger.debug("Agent run_task finished. Final event: #{final_event.inspect}") # 4. Process Result raise StandardError, "Agent task finished with unexpected event format: #{final_event.inspect}" unless final_event.is_a?(Legate::Event) && final_event.role == :agent && final_event.content.is_a?(Hash) result_content = final_event.content case result_content[:status] when :success result_content[:result] # Return result payload when :error err_msg = result_content[:error_message] || 'Agent execution failed.' Mcp.logger.error("Agent '#{agent_name}' execution failed: #{err_msg}") raise StandardError, "Agent Error: #{err_msg}" when :pending job_id = result_content[:job_id] msg = result_content[:message] || 'Agent task resulted in a pending job.' Mcp.logger.warn("Agent '#{agent_name}' execution ended with pending status (Job: #{job_id}). Returning as structured data.") { status: 'pending', job_id: job_id, message: msg } else raise StandardError, "Agent task finished with unknown status: #{result_content[:status]}" end rescue StandardError => e Mcp.logger.error("Error during LegateDirectAgentAdapter call for '#{agent_name}': #{e.class} - #{e.}") Mcp.logger.error(e.backtrace.join("\n")) raise StandardError, "Failed to run agent '#{agent_name}': #{e.}" ensure # 5. Cleanup if !was_agent_already_running && agent&.running? begin Mcp.logger.debug('Stopping ephemeral agent runtime...') agent.stop rescue StandardError => e Mcp.logger.error("Error stopping agent runtime during cleanup: #{e.}") end end if temp_session && session_service begin Mcp.logger.debug("Deleting temporary session: #{temp_session.id}") session_service.delete_session(session_id: temp_session.id) rescue StandardError => e Mcp.logger.error("Error deleting temporary session #{temp_session.id}: #{e.}") end end end end |