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 types;
10
11pub use types::{HandleResult, ToolCallHandler, ToolCallHandlerConfig};
12
13use super::decision::DecisionEmitter;
14use super::identity::ToolIdentity;
15use super::jsonrpc::JsonRpcRequest;
16use super::lifecycle::LifecycleEmitter;
17use super::policy::{McpPolicy, PolicyState};
18use crate::runtime::{Authorizer, MandateData};
19use serde_json::Value;
20use std::sync::Arc;
21
22impl ToolCallHandler {
23    /// Create a new handler.
24    pub fn new(
25        policy: McpPolicy,
26        authorizer: Option<Authorizer>,
27        emitter: Arc<dyn DecisionEmitter>,
28        config: ToolCallHandlerConfig,
29    ) -> Self {
30        types::new_handler(policy, authorizer, emitter, config)
31    }
32
33    /// Set the lifecycle emitter for mandate.used events (P0-B).
34    pub fn with_lifecycle_emitter(self, emitter: Arc<dyn LifecycleEmitter>) -> Self {
35        types::with_lifecycle_emitter(self, emitter)
36    }
37
38    /// Handle a tool call with full authorization and always-emit guarantee.
39    ///
40    /// This is the main entry point that enforces invariant I1: exactly one
41    /// decision event is emitted for every tool call attempt.
42    pub fn handle_tool_call(
43        &self,
44        request: &JsonRpcRequest,
45        state: &mut PolicyState,
46        runtime_identity: Option<&ToolIdentity>,
47        mandate: Option<&MandateData>,
48        transaction_object: Option<&Value>,
49    ) -> HandleResult {
50        evaluate::handle_tool_call(
51            self,
52            request,
53            state,
54            runtime_identity,
55            mandate,
56            transaction_object,
57        )
58    }
59}
60
61#[cfg(test)]
62mod tests;