use std::sync::{Mutex, MutexGuard, OnceLock};
use std::time::{SystemTime, UNIX_EPOCH};
use super::client_wiring::OptimizationLevel;
use super::coverage_class::{self, CoverageClass};
use super::etpao_live::{EtpaoLive, OutcomeMetrics, RequestMetrics};
use super::identity::{CallerIdentity, CallerRole, IdentityLedger};
use super::outcome_signal::{self, OutcomeSignal};
use super::types::ReceiptOutcome;
static MCP_ETPAO: OnceLock<Mutex<EtpaoLive>> = OnceLock::new();
static MCP_IDENTITY: OnceLock<Mutex<IdentityLedger>> = OnceLock::new();
const MCP_SESSION_ID: &str = "mcp-session";
#[derive(Debug, Clone, Default)]
pub struct McpClientInfo {
pub client_name: String,
pub supports_roots: bool,
pub supports_sampling: bool,
pub tool_count: usize,
}
#[derive(Debug, Clone, Default)]
pub struct McpCallData {
pub tool_name: String,
pub input_tokens: usize,
pub output_tokens: usize,
pub is_retry: bool,
pub call_number: usize,
}
#[derive(Debug, Clone)]
pub struct McpKernelResult {
pub coverage: CoverageClass,
pub coverage_label: &'static str,
pub is_addressable: bool,
pub optimization_level: OptimizationLevel,
pub schema_budget: usize,
}
#[derive(Debug, Clone, Default)]
pub struct McpSummary {
pub total_calls: usize,
pub total_input_tokens: usize,
pub total_output_tokens: usize,
pub accepted_calls: usize,
pub etpao: f64,
pub coverage_label: String,
}
#[must_use]
pub fn process_mcp_context(info: &McpClientInfo) -> McpKernelResult {
let coverage = super::mcp_coverage::detect_mcp_coverage(
&info.client_name,
info.supports_roots,
info.supports_sampling,
);
let profile = super::mcp_coverage::mcp_client_profile(&info.client_name);
McpKernelResult {
coverage,
coverage_label: coverage_class::coverage_label(coverage),
is_addressable: coverage_class::is_addressable(coverage),
optimization_level: optimization_level(coverage),
schema_budget: profile.tool_budget.max_schema_tokens,
}
}
pub fn record_mcp_call(data: &McpCallData) {
let call_number = if data.is_retry {
data.call_number.max(2)
} else {
data.call_number
};
let inferred = outcome_signal::infer_outcome(call_number, data.is_retry, data.output_tokens);
let accepted = inferred.outcome == ReceiptOutcome::Accepted;
lock_etpao().record_request(RequestMetrics {
input_tokens: data.input_tokens,
output_tokens: data.output_tokens,
reasoning_tokens: 0,
schema_tokens: 0,
cache_write_tokens: 0,
retry_count: usize::from(data.is_retry),
client_id: MCP_SESSION_ID.to_owned(),
coverage_class: CoverageClass::ContextControlled,
});
lock_etpao().record_outcome(OutcomeMetrics {
accepted,
quality_score: inferred.confidence,
first_pass: inferred.signal == OutcomeSignal::FirstPass,
client_id: MCP_SESSION_ID.to_owned(),
});
lock_identity().record(
&mcp_identity(),
data.input_tokens,
data.output_tokens,
accepted,
);
}
#[must_use]
pub fn generate_mcp_receipt(
plan_id: &str,
tool_name: &str,
_input_tokens: usize,
output_tokens: usize,
cache_hit: bool,
) -> super::types::ContextReceiptV1 {
use std::collections::HashMap;
use super::types::{ContextReceiptV1, ReceiptOutcome};
ContextReceiptV1 {
receipt_id: format!("mcp-{tool_name}-{}", uuid_v4_short()),
plan_id: plan_id.to_owned(),
task_id: crate::core::task_spine::TaskSpine::task_id(),
delivered_tokens: output_tokens,
cache_hits: usize::from(cache_hit),
cache_misses: usize::from(!cache_hit),
outcome: ReceiptOutcome::Accepted,
quality_signals: vec![],
feedback_attribution: HashMap::new(),
}
}
#[must_use]
pub fn mcp_etpao() -> f64 {
lock_etpao().current_etpao()
}
#[must_use]
pub fn mcp_summary() -> McpSummary {
let etpao = lock_etpao();
let etpao_summary = etpao.summary();
let total_calls = etpao.request_count();
drop(etpao);
let identity_summary = lock_identity().summary();
McpSummary {
total_calls,
total_input_tokens: identity_summary.total_tokens,
total_output_tokens: identity_summary.total_savings,
accepted_calls: etpao_summary.accepted_outcomes,
etpao: etpao_summary.etpao,
coverage_label: coverage_class::coverage_label(CoverageClass::ContextControlled).to_owned(),
}
}
pub fn reset_mcp_state() {
*lock_etpao() = EtpaoLive::new();
*lock_identity() = IdentityLedger::new();
}
fn optimization_level(coverage: CoverageClass) -> OptimizationLevel {
match coverage {
CoverageClass::FullInline => OptimizationLevel::Full,
CoverageClass::ContextControlled => OptimizationLevel::Partial,
CoverageClass::ObserveOnly => OptimizationLevel::ObserveOnly,
CoverageClass::Unmanaged => OptimizationLevel::None,
}
}
fn mcp_identity() -> CallerIdentity {
CallerIdentity {
user_id: Some(MCP_SESSION_ID.to_owned()),
role: CallerRole::Agent,
session_id: Some(MCP_SESSION_ID.to_owned()),
..CallerIdentity::default()
}
}
fn uuid_v4_short() -> String {
SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap_or_default()
.as_nanos()
.to_string()
}
fn lock_etpao() -> MutexGuard<'static, EtpaoLive> {
MCP_ETPAO
.get_or_init(|| Mutex::new(EtpaoLive::new()))
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner)
}
fn lock_identity() -> MutexGuard<'static, IdentityLedger> {
MCP_IDENTITY
.get_or_init(|| Mutex::new(IdentityLedger::new()))
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner)
}
#[cfg(test)]
pub mod tests {
use std::sync::{Mutex, MutexGuard};
use super::{
McpCallData, McpClientInfo, generate_mcp_receipt, mcp_etpao, mcp_summary,
process_mcp_context, record_mcp_call, reset_mcp_state,
};
use crate::core::context_kernel::coverage_class::CoverageClass;
use crate::core::context_kernel::types::ReceiptOutcome;
static TEST_LOCK: Mutex<()> = Mutex::new(());
fn test_guard() -> MutexGuard<'static, ()> {
TEST_LOCK
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner)
}
fn call(number: usize, retry: bool) -> McpCallData {
McpCallData {
tool_name: "ctx_read".to_owned(),
input_tokens: 100,
output_tokens: 20,
is_retry: retry,
call_number: number,
}
}
#[test]
fn process_cursor_context() {
let _guard = test_guard();
let result = process_mcp_context(&McpClientInfo {
client_name: "cursor".to_owned(),
..McpClientInfo::default()
});
assert_eq!(result.coverage, CoverageClass::FullInline);
}
#[test]
fn process_vscode_context() {
let _guard = test_guard();
let result = process_mcp_context(&McpClientInfo {
client_name: "vscode".to_owned(),
..McpClientInfo::default()
});
assert_eq!(result.coverage, CoverageClass::ContextControlled);
}
#[test]
fn process_unknown_context() {
let _guard = test_guard();
let result = process_mcp_context(&McpClientInfo {
client_name: "unknown".to_owned(),
..McpClientInfo::default()
});
assert_eq!(result.coverage, CoverageClass::ObserveOnly);
}
#[test]
fn record_call_updates_etpao() {
let _guard = test_guard();
reset_mcp_state();
record_mcp_call(&call(1, false));
assert!(mcp_etpao() > 0.0);
}
#[test]
fn record_retry_is_rejected() {
let _guard = test_guard();
reset_mcp_state();
record_mcp_call(&call(2, true));
assert_eq!(mcp_summary().accepted_calls, 0);
}
#[test]
fn summary_aggregates() {
let _guard = test_guard();
reset_mcp_state();
for number in 1..=5 {
record_mcp_call(&call(number, false));
}
let summary = mcp_summary();
assert_eq!(summary.total_calls, 5);
assert_eq!(summary.total_input_tokens, 500);
assert_eq!(summary.total_output_tokens, 100);
}
#[test]
fn reset_clears() {
let _guard = test_guard();
reset_mcp_state();
record_mcp_call(&call(1, false));
reset_mcp_state();
assert_eq!(mcp_etpao(), 0.0);
assert_eq!(mcp_summary().total_calls, 0);
}
#[test]
fn test_generate_mcp_receipt_fields() {
let receipt = generate_mcp_receipt("plan-42", "ctx_read", 100, 20, false);
assert_eq!(receipt.plan_id, "plan-42");
assert!(receipt.receipt_id.starts_with("mcp-ctx_read-"));
assert_eq!(receipt.delivered_tokens, 20);
assert_eq!(receipt.outcome, ReceiptOutcome::Accepted);
}
#[test]
fn test_receipt_cache_hit_counting() {
let receipt = generate_mcp_receipt("plan-42", "ctx_read", 100, 20, true);
assert_eq!(receipt.cache_hits, 1);
assert_eq!(receipt.cache_misses, 0);
}
#[test]
fn test_receipt_cache_miss_counting() {
let receipt = generate_mcp_receipt("plan-42", "ctx_read", 100, 20, false);
assert_eq!(receipt.cache_hits, 0);
assert_eq!(receipt.cache_misses, 1);
}
}