Class: Jazari::Protocol::Dispatcher

Inherits:
Object
  • Object
show all
Defined in:
lib/jazari/protocol/dispatcher.rb

Constant Summary collapse

VERSION =
"jazari/v1"
ACTIONS =
([ "capabilities" ] + Mcp::Actions::NAMES).freeze
REQUEST_KEYS =
%w[protocol request_id action target arguments].freeze
DOMAIN_ERRORS =
%w[
  target_not_found invalid_runbook revision_conflict item_not_found
  item_not_in_snapshot read_only_target run_closed
].freeze

Instance Method Summary collapse

Constructor Details

#initialize(handler: Mcp::Handler.new) ⇒ Dispatcher

Returns a new instance of Dispatcher.



22
23
24
# File 'lib/jazari/protocol/dispatcher.rb', line 22

def initialize(handler: Mcp::Handler.new)
  @handler = handler
end

Instance Method Details

#call(input) ⇒ Object



43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/jazari/protocol/dispatcher.rb', line 43

def call(input)
  request = stringify(input)
  validate_request!(request)
  action = request.fetch("action")
  result = if action == "capabilities"
    capabilities
  else
    @handler.call(
      action: action,
      target: target_from(request.fetch("target")),
      arguments: request.fetch("arguments")
    )
  end

  envelope(request, result)
rescue InvalidRequest => error
  error_envelope(input, "invalid_request", error.message)
rescue ActiveRecord::RecordNotFound
  error_envelope(input, "target_not_found")
rescue ActiveRecord::StatementInvalid => error
  code = sqlite_busy?(error) ? "storage_busy" : "storage_failure"
  error_envelope(input, code)
rescue StandardError
  error_envelope(input, "storage_failure")
end

#capabilities ⇒ Object



26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# File 'lib/jazari/protocol/dispatcher.rb', line 26

def capabilities
  adapter = Jazari::ApplicationRecord.connection.adapter_name.downcase
  storage = if adapter.include?("sqlite")
    "sqlite"
  elsif adapter.include?("postgres")
    "postgresql"
  else
    raise ActiveRecord::AdapterNotSpecified, "jazari/v1 does not support the #{adapter} adapter"
  end
  {
    protocol: VERSION,
    storage: storage,
    transports: storage == "sqlite" ? %w[cli mcp-stdio] : %w[ruby],
    features: %w[recipes runbooks runs evidence]
  }
end