Skip to main content

assay_core/mcp/tool_call_handler/
mod.rs

1//! Central tool call handler with mandate authorization.
2//!
3//! This module integrates policy evaluation, mandate authorization, and
4//! decision emission into a single handler that guarantees the always-emit
5//! invariant (I1).
6
7mod emit;
8mod evaluate;
9mod evaluate_next;
10mod types;
11
12pub use types::{HandleResult, ToolCallHandler, ToolCallHandlerConfig};
13
14use super::decision::DecisionEmitter;
15use super::identity::ToolIdentity;
16use super::jsonrpc::JsonRpcRequest;
17use super::lifecycle::LifecycleEmitter;
18use super::policy::{McpPolicy, PolicyState};
19use super::tool_definition::ToolDefinitionBinding;
20use crate::runtime::{Authorizer, MandateData};
21use serde_json::Value;
22use std::sync::Arc;
23
24impl ToolCallHandler {
25    /// Create a new handler.
26    pub fn new(
27        policy: McpPolicy,
28        authorizer: Option<Authorizer>,
29        emitter: Arc<dyn DecisionEmitter>,
30        config: ToolCallHandlerConfig,
31    ) -> Self {
32        types::new_handler(policy, authorizer, emitter, config)
33    }
34
35    /// Set the lifecycle emitter for mandate.used events (P0-B).
36    pub fn with_lifecycle_emitter(self, emitter: Arc<dyn LifecycleEmitter>) -> Self {
37        types::with_lifecycle_emitter(self, emitter)
38    }
39
40    /// Handle a tool call with full authorization and always-emit guarantee.
41    ///
42    /// This is the main entry point that enforces invariant I1: exactly one
43    /// decision event is emitted for every tool call attempt.
44    pub fn handle_tool_call(
45        &self,
46        request: &JsonRpcRequest,
47        state: &mut PolicyState,
48        runtime_identity: Option<&ToolIdentity>,
49        mandate: Option<&MandateData>,
50        transaction_object: Option<&Value>,
51    ) -> HandleResult {
52        evaluate::handle_tool_call(
53            self,
54            request,
55            state,
56            runtime_identity,
57            None,
58            mandate,
59            transaction_object,
60        )
61    }
62
63    /// Handle a tool call with an observed bounded tool-definition binding.
64    ///
65    /// This preserves the existing runtime identity/pin surface while allowing
66    /// supported `tools/list` observations to be projected onto decision
67    /// evidence as P56b digest visibility.
68    pub fn handle_tool_call_with_tool_definition_binding(
69        &self,
70        request: &JsonRpcRequest,
71        state: &mut PolicyState,
72        runtime_identity: Option<&ToolIdentity>,
73        tool_definition_binding: Option<&ToolDefinitionBinding>,
74        mandate: Option<&MandateData>,
75        transaction_object: Option<&Value>,
76    ) -> HandleResult {
77        evaluate::handle_tool_call(
78            self,
79            request,
80            state,
81            runtime_identity,
82            tool_definition_binding,
83            mandate,
84            transaction_object,
85        )
86    }
87}
88
89#[cfg(test)]
90mod tests;