lean_ctx/core/context_kernel/
mcp_e2e.rs1#[cfg(test)]
4mod tests {
5 use std::sync::{Mutex, MutexGuard};
6
7 use super::super::client_wiring::OptimizationLevel;
8 use super::super::coverage_class::CoverageClass;
9 use super::super::mcp_bridge::{self, McpCallData, McpClientInfo};
10 use super::super::mcp_coverage;
11 use super::super::mcp_receipt::{self, McpReceipt};
12 use super::super::mcp_schema_opt::{self, SchemaBudget, SchemaEntry};
13
14 static TEST_LOCK: Mutex<()> = Mutex::new(());
15
16 fn isolated_test() -> MutexGuard<'static, ()> {
17 let guard = match TEST_LOCK.lock() {
18 Ok(guard) => guard,
19 Err(poisoned) => poisoned.into_inner(),
20 };
21 mcp_bridge::reset_mcp_state();
22 mcp_receipt::reset_receipts();
23 guard
24 }
25
26 fn cursor() -> McpClientInfo {
27 McpClientInfo {
28 client_name: "cursor".to_owned(),
29 supports_roots: true,
30 supports_sampling: true,
31 tool_count: 15,
32 }
33 }
34
35 fn call(tool: &str, output_tokens: usize) -> McpCallData {
36 McpCallData {
37 tool_name: tool.to_owned(),
38 input_tokens: 1_000,
39 output_tokens,
40 is_retry: false,
41 call_number: 1,
42 }
43 }
44
45 fn receipt(tool: &str) -> McpReceipt {
46 McpReceipt {
47 tool: tool.to_owned(),
48 tokens_in: 1_000,
49 tokens_out: 400,
50 kernel_overhead: 50,
51 accepted: true,
52 }
53 }
54
55 #[test]
56 fn full_mcp_lifecycle() {
57 let _guard = isolated_test();
58 let context = mcp_bridge::process_mcp_context(&cursor());
59 assert_eq!(context.coverage, CoverageClass::FullInline);
60
61 for output_tokens in [100, 125, 150] {
62 mcp_bridge::record_mcp_call(&call("ctx_read", output_tokens));
63 mcp_receipt::record_receipt(receipt("ctx_read"));
64 }
65
66 assert!(mcp_bridge::mcp_etpao() > 0.0);
67 let accounting = mcp_receipt::mcp_accounting();
68 assert!(accounting.delivered_tokens > 0);
69 }
70
71 #[test]
72 fn schema_compression_saves_tokens() {
73 let _guard = isolated_test();
74 let schemas: Vec<SchemaEntry> = (0..10)
75 .map(|index| SchemaEntry {
76 name: format!("tool-{index}"),
77 description: "x".repeat(2000),
78 param_count: 5,
79 estimated_tokens: 600,
80 essential: false,
81 })
82 .collect();
83 let budget = SchemaBudget {
84 max_total_tokens: 3_000,
85 max_per_tool_tokens: 200,
86 };
87
88 let result = mcp_schema_opt::optimize_schemas(&schemas, &budget);
89
90 assert!(result.tokens_after < result.tokens_before);
91 assert!(result.compressed_count > 0);
92 }
93
94 #[test]
95 fn cursor_full_pipeline() {
96 let _guard = isolated_test();
97 assert_eq!(
98 mcp_coverage::detect_mcp_coverage("cursor", true, true),
99 CoverageClass::FullInline
100 );
101 assert_eq!(
102 mcp_coverage::mcp_client_profile("cursor").context_window,
103 200_000
104 );
105 assert_eq!(
106 mcp_coverage::mcp_optimization_level("cursor"),
107 OptimizationLevel::Full
108 );
109 }
110
111 #[test]
112 fn vscode_pipeline() {
113 let _guard = isolated_test();
114 assert_eq!(
115 mcp_coverage::detect_mcp_coverage("vscode", true, true),
116 CoverageClass::ContextControlled
117 );
118 assert_eq!(
119 mcp_coverage::mcp_client_profile("vscode").context_window,
120 128_000
121 );
122 assert_eq!(
123 mcp_coverage::mcp_optimization_level("vscode"),
124 OptimizationLevel::Partial
125 );
126 }
127
128 #[test]
129 fn receipt_per_tool_tracking() {
130 let _guard = isolated_test();
131 for _ in 0..5 {
132 mcp_receipt::record_receipt(receipt("ctx_read"));
133 }
134 for _ in 0..3 {
135 mcp_receipt::record_receipt(receipt("ctx_search"));
136 }
137
138 let savings = mcp_receipt::per_tool_savings();
139 assert_eq!(savings.len(), 2);
140 let read = savings
141 .iter()
142 .find(|entry| entry.tool == "ctx_read")
143 .expect("ctx_read savings must be present");
144 assert_eq!(read.calls, 5);
145 }
146
147 #[test]
148 fn etpao_tracks_mcp_calls() {
149 let _guard = isolated_test();
150 for index in 0..10 {
151 mcp_bridge::record_mcp_call(&call("ctx_read", 50 + index));
152 }
153
154 assert!(mcp_bridge::mcp_etpao() > 0.0);
155 assert_eq!(mcp_bridge::mcp_summary().total_calls, 10);
156 }
157
158 #[test]
159 fn coverage_affects_schema_budget() {
160 let _guard = isolated_test();
161 let full = mcp_schema_opt::budget_for_coverage(CoverageClass::FullInline);
162 let controlled = mcp_schema_opt::budget_for_coverage(CoverageClass::ContextControlled);
163 let observe = mcp_schema_opt::budget_for_coverage(CoverageClass::ObserveOnly);
164
165 assert!(full.max_total_tokens > observe.max_total_tokens);
166 assert_eq!(full.max_total_tokens, 12_000);
167 assert_eq!(controlled.max_total_tokens, 8_000);
168 assert_eq!(observe.max_total_tokens, 4_000);
169 }
170
171 #[test]
172 fn end_to_end_identity_to_receipt() {
173 let _guard = isolated_test();
174 let _context = mcp_bridge::process_mcp_context(&cursor());
175
176 for index in 0..5 {
177 mcp_bridge::record_mcp_call(&call("ctx_read", 100 + index));
178 mcp_receipt::record_receipt(receipt("ctx_read"));
179 }
180
181 assert_eq!(mcp_bridge::mcp_summary().total_calls, 5);
182 assert!(!mcp_receipt::per_tool_savings().is_empty());
183 assert!(mcp_receipt::total_kernel_overhead() > 0);
184 }
185}