mcpkill 0.1.0

Universal MCP proxy — semantic cache + chunking to kill token waste
Documentation
use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion};
use mcpkill::{chunker, similarity, token};

fn bench_cosine(c: &mut Criterion) {
    let sizes = [64usize, 128, 384];
    let mut group = c.benchmark_group("cosine");

    for &dim in &sizes {
        let a: Vec<f32> = (0..dim).map(|i| i as f32 / dim as f32).collect();
        let b: Vec<f32> = (0..dim).map(|i| (dim - i) as f32 / dim as f32).collect();

        group.bench_with_input(
            BenchmarkId::from_parameter(dim),
            &(&a, &b),
            |bench, (a, b)| {
                bench.iter(|| similarity::cosine(black_box(a), black_box(b)));
            },
        );
    }

    group.finish();
}

fn bench_chunker(c: &mut Criterion) {
    let markdown = include_str!("../README.md").repeat(3);
    let paragraphs = "Lorem ipsum dolor sit amet.\n\n".repeat(100);

    let mut group = c.benchmark_group("chunker");

    group.bench_function("markdown_readme_x3", |bench| {
        bench.iter(|| chunker::chunk(black_box(&markdown)));
    });

    group.bench_function("plain_100_paragraphs", |bench| {
        bench.iter(|| chunker::chunk(black_box(&paragraphs)));
    });

    group.finish();
}

fn bench_token_estimate(c: &mut Criterion) {
    let texts = [100usize, 1_000, 10_000, 100_000];
    let mut group = c.benchmark_group("token_estimate");

    for &len in &texts {
        let text = "a".repeat(len);
        group.bench_with_input(BenchmarkId::from_parameter(len), &text, |bench, t| {
            bench.iter(|| token::estimate(black_box(t)));
        });
    }

    group.finish();
}

criterion_group!(benches, bench_cosine, bench_chunker, bench_token_estimate);
criterion_main!(benches);