use crate::compression::engine::Tool;
use crate::compression::{CompressionEngine, CompressionLevel};
const TITLE: &str = "\
\x1b[32m█▀▄▀█ █▀▀ █▀█ █▀▀ █▀█ █▀▄▀█ █▀█ █▀█ █▀▀ █▀▀ █▀▀ █▀█ █▀█\x1b[0m
\x1b[32m█ ▀ █ █▄▄ █▀▀ █▄▄ █▄█ █ ▀ █ █▀▀ █▀▄ ██▄ ▄▄█ ▄▄█ █▄█ █▀▄\x1b[0m";
pub fn compression_stats(tools: &[Tool]) -> CompressionStats {
let original: usize = tools
.iter()
.map(|t| {
let name_len = t.name.len();
let desc_len = t.description.as_deref().unwrap_or("").len();
let schema_len = t
.input_schema
.get("properties")
.and_then(|p| serde_json::to_string(p).ok())
.map(|s| s.len())
.unwrap_or(0);
name_len + desc_len + schema_len
})
.sum();
let levels = [
CompressionLevel::Low,
CompressionLevel::Medium,
CompressionLevel::High,
CompressionLevel::Max,
];
let compressed: Vec<(CompressionLevel, usize)> = levels
.iter()
.map(|level| (level.clone(), compressed_frontend_size(tools, level)))
.collect();
CompressionStats {
original_size: original,
compressed,
}
}
pub struct CompressionStats {
pub original_size: usize,
pub compressed: Vec<(CompressionLevel, usize)>,
}
fn compressed_frontend_size(tools: &[Tool], level: &CompressionLevel) -> usize {
let engine = CompressionEngine::new(level.clone());
let listing = engine.format_listing(tools);
let get_tool_schema_description = format!(
"Get the complete schema and description for one backend tool. Available tools:\n{listing}"
);
let invoke_tool_description = "Invoke one backend tool by name with JSON input.";
let list_tools_description = "List backend tools available through this compressed MCP server.";
let schema_wrapper = serde_json::json!({
"type": "object",
"properties": {
"tool_name": {"type": "string", "description": "Name of the backend tool"}
},
"required": ["tool_name"]
});
let invoke_wrapper = serde_json::json!({
"type": "object",
"properties": {
"tool_name": {"type": "string", "description": "Name of the backend tool"},
"tool_input": {"type": "object", "description": "JSON input for the backend tool"}
},
"required": ["tool_name", "tool_input"]
});
let list_wrapper = serde_json::json!({
"type": "object",
"properties": {}
});
let mut size = get_tool_schema_description.len()
+ invoke_tool_description.len()
+ schema_wrapper.to_string().len()
+ invoke_wrapper.to_string().len();
if *level == CompressionLevel::Max {
size += list_tools_description.len() + list_wrapper.to_string().len();
}
size
}
pub fn print_banner(
server_name: Option<&str>,
transport_type: &str,
active_level: &CompressionLevel,
tools: &[Tool],
cli_info: Option<CliInfo<'_>>,
) {
let columns = terminal_width().min(80);
if columns < 63 {
return;
}
let content_width = columns - 6;
let header = format!("╭{}╮", "─".repeat(columns - 2));
let footer = format!("╰{}╯", "─".repeat(columns - 2));
let separator = format!("├{}┤", "─".repeat(columns - 2));
let blank = format!("│{}│", " ".repeat(columns - 2));
let stats = compression_stats(tools);
let mut lines = vec![header.clone(), blank.clone()];
for title_line in TITLE.lines() {
lines.push(pad_line(title_line, content_width, true));
}
lines.push(blank.clone());
lines.push(pad_line(
"https://atlassian-labs.github.io/mcp-compressor/",
content_width,
true,
));
if let Some(name) = server_name {
lines.push(blank.clone());
lines.push(pad_line(
&format!("\x1b[32m●\x1b[0m Backend server name: {name}"),
content_width,
false,
));
}
lines.push(pad_line(
&format!(
"\x1b[32m●\x1b[0m Backend server transport: {}",
transport_type.to_uppercase()
),
content_width,
false,
));
lines.push(blank.clone());
lines.push(separator.clone());
lines.push(blank.clone());
lines.push(pad_line(
&format!(
"📊 Compression Statistics (current = {}):",
capitalize(active_level)
),
content_width - 1,
false,
));
lines.push(blank.clone());
lines.extend(format_chart(&stats, content_width, active_level));
if let Some(info) = cli_info {
lines.push(blank.clone());
lines.push(separator.clone());
lines.push(blank.clone());
if let Some(script) = info.script_path {
lines.push(pad_line(
&format!("Script: {script}"),
content_width,
false,
));
}
if let Some(bridge) = info.bridge_url {
lines.push(pad_line(
&format!("Bridge: {bridge}"),
content_width,
false,
));
}
if let Some(invoke) = info.invoke_prefix {
lines.push(pad_line(
&format!("Run: {invoke} --help"),
content_width,
false,
));
}
}
lines.push(blank.clone());
lines.push(footer);
eprintln!("{}", lines.join("\n"));
}
pub struct CliInfo<'a> {
pub script_path: Option<&'a str>,
pub bridge_url: Option<&'a str>,
pub invoke_prefix: Option<&'a str>,
}
fn format_chart(
stats: &CompressionStats,
width: usize,
active_level: &CompressionLevel,
) -> Vec<String> {
let chart_width = width.saturating_sub(16);
let original = stats.original_size;
let mut lines = Vec::new();
let bar = "█".repeat(chart_width);
lines.push(pad_line(&format!("Original {bar} 100.0%"), width, false));
let levels = [
CompressionLevel::Low,
CompressionLevel::Medium,
CompressionLevel::High,
CompressionLevel::Max,
];
for level in &levels {
let size = stats
.compressed
.iter()
.find(|(l, _)| l == level)
.map(|(_, s)| *s)
.unwrap_or(0);
let ratio = if original > 0 {
size as f64 / original as f64
} else {
0.0
};
let filled = (ratio * chart_width as f64).round() as usize;
let filled = filled.min(chart_width);
let bar = format!("{}{}", "█".repeat(filled), "░".repeat(chart_width - filled));
let pct = ratio * 100.0;
let label = format!("{:<8}", capitalize(level));
let mut line = pad_line(&format!("{label} {bar} {pct:5.1}%"), width, false);
if level == active_level {
line = highlight_bar(&line);
}
lines.push(line);
}
lines
}
fn highlight_bar(line: &str) -> String {
if let Some(fade_byte) = line.char_indices().find(|(_, c)| *c == '░').map(|(i, _)| i) {
let prefix_end = line
.char_indices()
.take_while(|(_, c)| *c != '█' && *c != '░')
.last()
.map(|(i, c)| i + c.len_utf8())
.unwrap_or(0);
format!(
"{}\x1b[1;32m{}\x1b[0m{}",
&line[..prefix_end],
&line[prefix_end..fade_byte],
&line[fade_byte..]
)
} else {
format!("\x1b[1;32m{line}\x1b[0m")
}
}
fn capitalize(level: &CompressionLevel) -> String {
let s = level.to_string();
let mut chars = s.chars();
match chars.next() {
Some(c) => c.to_uppercase().to_string() + chars.as_str(),
None => String::new(),
}
}
fn pad_line(line: &str, total_width: usize, center: bool) -> String {
let clean: String = strip_ansi(line);
let clean_width = clean.chars().count();
if center {
let padding_total = total_width.saturating_sub(clean_width);
let padding_left = padding_total / 2;
let padding_right = padding_total - padding_left;
format!(
"│ {}{}{} │",
" ".repeat(padding_left),
line,
" ".repeat(padding_right)
)
} else {
let padding_right = total_width.saturating_sub(clean_width);
format!("│ {}{} │", line, " ".repeat(padding_right))
}
}
fn strip_ansi(s: &str) -> String {
let mut result = String::with_capacity(s.len());
let mut in_escape = false;
for c in s.chars() {
if in_escape {
if c.is_ascii_alphabetic() {
in_escape = false;
}
} else if c == '\x1b' {
in_escape = true;
} else {
result.push(c);
}
}
result
}
fn terminal_width() -> usize {
#[cfg(unix)]
{
use std::mem::MaybeUninit;
unsafe {
let mut ws = MaybeUninit::<libc::winsize>::zeroed();
if libc::ioctl(2, libc::TIOCGWINSZ, ws.as_mut_ptr()) == 0 {
let ws = ws.assume_init();
if ws.ws_col > 0 {
return ws.ws_col as usize;
}
}
}
}
80
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn highlight_bar_handles_unicode_box_border() {
let line =
"│ Medium █████████░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 15.5% │";
let highlighted = highlight_bar(line);
assert!(highlighted.contains("\x1b[1;32m"));
assert!(highlighted.contains("Medium"));
assert_eq!(strip_ansi(&highlighted), line);
}
#[test]
fn format_chart_only_shows_compression_levels() {
let stats = CompressionStats {
original_size: 129,
compressed: vec![
(CompressionLevel::Low, 80),
(CompressionLevel::Medium, 20),
(CompressionLevel::High, 10),
(CompressionLevel::Max, 5),
],
};
let lines = format_chart(&stats, 80, &CompressionLevel::Medium);
assert_eq!(lines.len(), 5);
assert!(lines.iter().any(|line| line.contains("Original")));
assert!(lines.iter().any(|line| line.contains("Low")));
assert!(lines.iter().any(|line| line.contains("Medium")));
assert!(lines.iter().any(|line| line.contains("High")));
assert!(lines.iter().any(|line| line.contains("Max")));
assert!(!lines.iter().any(|line| line.contains("CLI mode")));
let medium = lines.iter().find(|line| line.contains("Medium")).unwrap();
assert!(medium.contains("\x1b[1;32m"));
}
#[test]
fn max_compression_stat_includes_wrapper_schema_surface() {
let tools = vec![Tool::new(
"echo",
Some("Echo a message".to_string()),
serde_json::json!({
"type": "object",
"properties": {"message": {"type": "string"}},
"required": ["message"]
}),
)];
let stats = compression_stats(&tools);
let max = stats
.compressed
.iter()
.find(|(level, _)| *level == CompressionLevel::Max)
.map(|(_, size)| *size)
.unwrap();
assert!(max > 0);
}
}