Class: Jazari::Mcp::Handler

Inherits:
Object
  • Object
show all
Defined in:
lib/jazari/mcp/handler.rb

Overview

Transport-neutral adapter between an MCP action name and the domain.

It knows nothing about transport, authentication, or product naming. The HOST owns tool identity — one flat action-enum tool per product, named for that product — and the host authorizes the actor and constructs the target BEFORE calling here. This class only maps action names onto domain calls and shapes the reply.

That split is deliberate: two products sharing this handler still present their own tool, their own subject vocabulary, and their own permissions.

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.actions_for(scope) ⇒ Object

Actions are declared once, in Mcp::Actions, so the schema a host publishes and the behaviour implemented here cannot drift apart.



22
# File 'lib/jazari/mcp/handler.rb', line 22

def self.actions_for(scope) = Actions.names(scope: scope)

Instance Method Details

#call(action:, target:, arguments: {}) ⇒ Object



24
25
26
27
28
29
30
31
32
33
# File 'lib/jazari/mcp/handler.rb', line 24

def call(action:, target:, arguments: {})
  args = symbolize(arguments)
  descriptor = Actions.fetch(action)   # raises on an unknown action

  reply(public_send(:"handle_#{descriptor.name}", target, args))
rescue Jazari::Error => error
  # The closed taxonomy crosses the wire as a code, never as a message
  # that could disclose a record, a query, or whether a target exists.
  { ok: false, error: error.code }
end

#handle_add_item(target, args) ⇒ Object



54
55
56
57
# File 'lib/jazari/mcp/handler.rb', line 54

def handle_add_item(target, args)
  Operations.add_item(target: target, expected_revision: args[:expected_revision],
                      text: args[:text], required: args.fetch(:required, true))
end

#handle_check_item(target, args) ⇒ Object



64
65
66
67
# File 'lib/jazari/mcp/handler.rb', line 64

def handle_check_item(target, args)
  Operations.check_item(target: target, expected_revision: args[:expected_revision],
                        item_id: args[:item_id], done: args[:done])
end

#handle_evidence(_target, args) ⇒ Object



93
94
95
96
97
98
# File 'lib/jazari/mcp/handler.rb', line 93

def handle_evidence(_target, args)
  run = Runs.attach_evidence(run: args.fetch(:run_id), expected_revision: args[:expected_revision],
                             item_id: args[:item_id], kind: args.fetch(:kind),
                             value: args.fetch(:value), actor_ref: args[:actor_ref])
  run_view(run)
end

#handle_finish(_target, args) ⇒ Object



100
101
102
103
104
# File 'lib/jazari/mcp/handler.rb', line 100

def handle_finish(_target, args)
  run = Runs.close(run: args.fetch(:run_id), expected_revision: args[:expected_revision],
                   outcome: args.fetch(:outcome, "completed"))
  run_view(run)
end

#handle_get(target, _args) ⇒ Object

-- read ---------------------------------------------------------------



37
# File 'lib/jazari/mcp/handler.rb', line 37

def handle_get(target, _args) = Operations.resolve(target: target)

#handle_last_run(target, _args) ⇒ Object



39
40
41
42
# File 'lib/jazari/mcp/handler.rb', line 39

def handle_last_run(target, _args)
  run = Runs.last(target: target)
  run ? run_view(run) : { last_run: nil }
end

#handle_remove_item(target, args) ⇒ Object



59
60
61
62
# File 'lib/jazari/mcp/handler.rb', line 59

def handle_remove_item(target, args)
  Operations.remove_item(target: target, expected_revision: args[:expected_revision],
                         item_id: args[:item_id])
end

#handle_reset(target, args) ⇒ Object

Destructive: it discards the operator's customization. The host must gate this on explicit confirmation before calling.



71
72
73
74
75
76
77
# File 'lib/jazari/mcp/handler.rb', line 71

def handle_reset(target, args)
  unless args[:confirm] == true
    raise InvalidRunbook, "reset discards the customization and requires confirm: true"
  end

  Operations.reset(target: target, expected_revision: args[:expected_revision])
end

#handle_set(target, args) ⇒ Object

-- runbook ------------------------------------------------------------



46
47
48
49
50
51
52
# File 'lib/jazari/mcp/handler.rb', line 46

def handle_set(target, args)
  Operations.customize(
    target: target, expected_revision: args[:expected_revision],
    topic: args[:topic], description: args[:description].to_s,
    checklist: args.fetch(:checklist, [])
  )
end

#handle_start(target, args) ⇒ Object

-- runs ---------------------------------------------------------------



81
82
83
84
# File 'lib/jazari/mcp/handler.rb', line 81

def handle_start(target, args)
  result = Runs.open(target: target, actor_ref: args.fetch(:actor_ref))
  run_view(result[:run]).merge(created: result[:created], idempotent_reuse: result[:idempotent_reuse])
end

#handle_tick(_target, args) ⇒ Object



86
87
88
89
90
91
# File 'lib/jazari/mcp/handler.rb', line 86

def handle_tick(_target, args)
  run = Runs.tick(run: args.fetch(:run_id), expected_revision: args[:expected_revision],
                  item_id: args[:item_id], done: args.fetch(:done, true),
                  actor_ref: args[:actor_ref], note: args[:note])
  run_view(run)
end