Compute MCP

Un servidor MCP para evaluar expresiones aritméticas utilizando un analizador Pratt en Rust.

Documentación

🔮 Compute MCP

Un evaluador robusto de expresiones aritméticas implementado como un servidor MCP (Model Context Protocol). Este proyecto demuestra el desarrollo de parsers de calidad de producción utilizando técnicas modernas de Rust, pruebas exhaustivas basadas en propiedades y estrategias de pruebas adversariales.

✨ Características

  • Aritmética Completa: +, -, *, / con precedencia correcta
  • Notación Científica: 1e10, 2.5e-3, 1.23E+4
  • Agrupación con Paréntesis: (2 + 3) * 4
  • Números Decimales: 3.14159, -0.5
  • Operadores Unarios: -42, -(5 + 3), --5
  • Manejo Robusto de Errores: División por cero, entrada malformada, errores de análisis
  • Soporte de Anidamiento Profundo: Maneja expresiones anidadas complejas
  • Probado con Propiedades: Más de 60 pruebas que cubren invariantes matemáticas

🏗️ Arquitectura

Construido con un parser Pratt moderno para un manejo limpio de la precedencia de operadores:

Input String → Pest Grammar → Pratt Parser → AST → Evaluator → Result
     │              │              │         │         │          │
"2 + 3 * 4"    compute.pest    PrattParser  Expr::Add  eval_expr  Ok(14.0)
                                              /        \
                                       Expr::Num(2)  Expr::Mul
                                                      /        \
                                                Expr::Num(3)  Expr::Num(4)

Componentes Clave

  1. Gramática (src/compute.pest) - Define la sintaxis con átomos y operadores
  2. Parser Pratt (src/lib.rs) - Maneja la precedencia automáticamente
  3. AST (enum Expr) - Árbol de expresión inmutable
  4. Evaluador (eval_expr) - Evaluación recursiva segura para la pila
  5. Servidor MCP (src/bin/stdio_direct.rs) - Interfaz JSON-RPC

🚀 Inicio Rápido

Instalación

cargo build --release

Evaluación Directa

# Command line tool
cargo run --bin stdio_direct -- eval "2 + 3 * 4"
cargo run --bin stdio_direct -- eval "1e10 / (2.5 + 3.7)"

Servidor MCP

# Initialize server
echo '{"jsonrpc":"2.0","method":"initialize","params":{},"id":1}' | cargo run --bin stdio_direct

# Batch evaluation
echo '{"jsonrpc":"2.0","method":"tools/call","params":{"name":"evaluate_batch","arguments":{"expressions":["2+2","1e3*2","(5-3)^2"]}},"id":2}' | cargo run --bin stdio_direct

Integración con Claude Desktop

{
  "mcpServers": {
    "compute": {
      "command": "/path/to/compute-mcp/target/release/stdio_direct"
    }
  }
}

🧪 Pruebas Exhaustivas

Este proyecto cuenta con una de las suites de pruebas más completas para parsers aritméticos:

Categorías de Pruebas

🔧 Pruebas Unitarias (tests/tests.rs)

  • Operaciones aritméticas básicas
  • Precedencia y asociatividad
  • Manejo de errores
  • Análisis de ida y vuelta

⚡ Pruebas Adversariales (tests/adversarial_tests.rs)

  • Casos límite de punto flotante (infinito, NaN, subnormales)
  • Anidamiento profundo (más de 1000 niveles)
  • Fuzzing de entrada malformada
  • Pruebas de estrés de rendimiento

🎯 Pruebas Basadas en Propiedades (tests/proptest_adversarial.rs)

  • Invariantes matemáticas (conmutatividad, asociatividad, distributividad)
  • Robustez del parser (nunca entra en pánico)
  • Determinismo de la evaluación
  • Preservación de precisión

Invariantes Clave Probadas

// Precedence preservation
parse("a + b * c") == Add(a, Mul(b, c))

// Evaluation determinism  
eval(expr) == eval(expr)  // Always same result

// Mathematical laws
eval(Add(a, b)) ≈ eval(Add(b, a))  // Commutativity
eval(Add(Add(a, b), c)) ≈ eval(Add(a, Add(b, c)))  // Associativity

// Round-trip consistency
eval(parse(print(ast))) ≈ eval(ast)

// Error containment
parse(invalid_input) == Err(_)  // Never panics

Ejecutar Pruebas

# All tests
cargo test

# Specific test suites
cargo test --test tests           # Basic functionality
cargo test --test adversarial_tests  # Edge cases
cargo test --test proptest_adversarial  # Property tests

# Parallel execution
cargo test -- --test-threads=4

🐛 Errores Encontrados y Corregidos

Las pruebas basadas en propiedades descubrieron problemas críticos durante el desarrollo:

Ambigüedad en la Gramática: La gramática original permitía que -5 se analizara como Neg(Number(5)) o Number(-5), causando comportamiento no determinista. Se corrigió eliminando los signos negativos de los literales numéricos.

Casos Límite de Precisión: Las pruebas revelaron problemas de precisión de punto flotante con expresiones como 1e20 + 1 - 1e20, lo que llevó a una tolerancia de errores más robusta.

Límites de Anidamiento Profundo: Se encontraron acantilados de rendimiento del parser en ~40+ niveles de anidamiento, optimizados para casos de uso prácticos.

📊 Ejemplos de Código

Uso Básico

use compute_mcp::*;

// Simple evaluation
let result = evaluate("2 + 3 * 4")?;
assert_eq!(result, 14.0);

// Scientific notation
let result = evaluate("1.5e3 + 2.5e2")?;
assert_eq!(result, 1750.0);

// Complex expressions
let result = evaluate("((1 + 2) * 3 - 4) / 2")?;
assert_eq!(result, 2.5);

Características Avanzadas

// Parse to AST for inspection
let ast = parse_expression("-(2 + 3) * 4")?;
// Returns: Mul(Neg(Add(Number(2), Number(3))), Number(4))

// Batch processing
let expressions = vec!["1+1", "2*2", "3/3"];
let results = evaluate_batch(&expressions);

// Error handling
match evaluate("10 / 0") {
    Err(ComputeError::DivisionByZero) => println!("Caught division by zero"),
    _ => unreachable!(),
}

📁 Estructura del Proyecto

compute-mcp/
├── Cargo.toml                    # Dependencies and metadata
├── src/
│   ├── lib.rs                    # Parser, AST, and evaluator (~350 lines)
│   ├── compute.pest              # Pratt parser grammar (~35 lines)
│   └── bin/
│       └── stdio_direct.rs       # MCP server implementation
├── tests/
│   ├── tests.rs                  # Unit and integration tests
│   ├── adversarial_tests.rs      # Edge case and stress tests  
│   ├── proptest_adversarial.rs   # Property-based tests
│   └── *.proptest-regressions    # Saved failing test cases
└── target/                       # Build artifacts

🔗 Dependencias

[dependencies]
pest = "2.6"           # Parser generator
pest_derive = "2.6"    # Derive macros for grammar
lazy_static = "1.4"    # Global parser instance
mcpr = "0.2.3"         # MCP protocol
serde = "1.0"          # JSON serialization
clap = "4.4"           # Command line interface

[dev-dependencies]
proptest = "1.6.0"     # Property-based testing

🎓 Valor Educativo

Este proyecto sirve como un excelente caso de estudio para:

  • Diseño Moderno de Parsers: Parsers Pratt vs descenso recursivo
  • Pruebas Basadas en Propiedades: Descubriendo casos límite automáticamente
  • Mejores Prácticas de Rust: Manejo de errores, seguridad de tipos, abstracciones de costo cero
  • Implementación de Protocolos: Desarrollo de servidores MCP
  • Corrección Matemática: Asegurando que las leyes aritméticas se cumplan

Perfecto para publicaciones de blog, tutoriales y contenido educativo sobre desarrollo de software robusto.

📝 Licencia

MIT - Ver LICENCIA para más detalles.


🔮 Listo para uso en producción con la confianza respaldada por pruebas exhaustivas! 🔮