systemprompt_api/services/proxy/audit/
mod.rs1pub mod jsonrpc;
13pub mod tap;
14
15use std::sync::Arc;
16
17use chrono::{DateTime, Utc};
18use serde_json::Value;
19use systemprompt_mcp::models::{ExecutionStatus, ToolExecutionRequest, ToolExecutionResult};
20use systemprompt_mcp::repository::ToolUsageRepository;
21use systemprompt_models::RequestContext;
22
23pub(crate) use jsonrpc::parse_tool_call;
24pub(crate) use tap::record;
25
26use jsonrpc::{ToolCallInvocation, ToolCallOutcome};
27
28#[derive(Debug)]
29pub struct McpAudit {
30 repo: Arc<ToolUsageRepository>,
31 context: RequestContext,
32 server_name: String,
33 invocation: ToolCallInvocation,
34 started_at: DateTime<Utc>,
35}
36
37impl McpAudit {
38 pub fn new(
39 repo: Arc<ToolUsageRepository>,
40 context: RequestContext,
41 server_name: String,
42 invocation: ToolCallInvocation,
43 ) -> Self {
44 Self {
45 repo,
46 context,
47 server_name,
48 invocation,
49 started_at: Utc::now(),
50 }
51 }
52
53 const fn request_id(&self) -> &Value {
54 &self.invocation.id
55 }
56
57 fn finalize(self, outcome: Option<ToolCallOutcome>) {
58 let (output, error_message) = match outcome {
59 Some(o) => (o.output, o.error_message),
60 None => (
61 None,
62 Some("external MCP tool call produced no parseable result".to_owned()),
63 ),
64 };
65
66 let request = ToolExecutionRequest {
67 tool_name: self.invocation.tool_name,
68 server_name: self.server_name.clone(),
69 input: self.invocation.arguments,
70 started_at: self.started_at,
71 context: self.context,
72 request_method: Some("mcp".to_owned()),
73 request_source: Some(self.server_name),
74 ai_tool_call_id: None,
75 };
76 let result = ToolExecutionResult {
77 status: ExecutionStatus::from_error(error_message.is_some()).to_string(),
78 error_message,
79 output,
80 output_schema: None,
81 started_at: self.started_at,
82 completed_at: Utc::now(),
83 };
84
85 let repo = self.repo;
86 tokio::spawn(async move {
87 if let Err(e) = repo.log_execution_sync(&request, &result).await {
88 tracing::warn!(
89 tool = %request.tool_name,
90 server = %request.server_name,
91 error = %e,
92 "Failed to record external MCP tool execution"
93 );
94 }
95 });
96 }
97}