Compute MCP

An MCP server for evaluating arithmetic expressions using a Pratt parser in Rust.

๐Ÿ”ฎ Compute MCP

A robust arithmetic expression evaluator implemented as an MCP (Model Context Protocol) server. This project demonstrates production-quality parser development using modern Rust techniques, comprehensive property-based testing, and adversarial test strategies.

โœจ Features

  • Complete Arithmetic: +, -, *, / with correct precedence
  • Scientific Notation: 1e10, 2.5e-3, 1.23E+4
  • Parentheses Grouping: (2 + 3) * 4
  • Decimal Numbers: 3.14159, -0.5
  • Unary Operators: -42, -(5 + 3), --5
  • Robust Error Handling: Division by zero, malformed input, parse errors
  • Deep Nesting Support: Handles complex nested expressions
  • Property-Based Tested: 60+ tests covering mathematical invariants

๐Ÿ—๏ธ Architecture

Built using a modern Pratt parser for clean operator precedence handling:

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)

Key Components

  1. Grammar (src/compute.pest) - Defines syntax with atoms and operators
  2. Pratt Parser (src/lib.rs) - Handles precedence automatically
  3. AST (Expr enum) - Immutable expression tree
  4. Evaluator (eval_expr) - Stack-safe recursive evaluation
  5. MCP Server (src/bin/stdio_direct.rs) - JSON-RPC interface

๐Ÿš€ Quick Start

Installation

cargo build --release

Direct Evaluation

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

MCP Server

# 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

Claude Desktop Integration

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

๐Ÿงช Comprehensive Testing

This project features one of the most thorough test suites for arithmetic parsers:

Test Categories

๐Ÿ”ง Unit Tests (tests/tests.rs)

  • Basic arithmetic operations
  • Precedence and associativity
  • Error handling
  • Round-trip parsing

โšก Adversarial Tests (tests/adversarial_tests.rs)

  • Floating-point edge cases (infinity, NaN, subnormals)
  • Deep nesting (1000+ levels)
  • Malformed input fuzzing
  • Performance stress testing

๐ŸŽฏ Property-Based Tests (tests/proptest_adversarial.rs)

  • Mathematical invariants (commutativity, associativity, distributivity)
  • Parser robustness (never panics)
  • Evaluation determinism
  • Precision preservation

Key Invariants Tested

// 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

Running Tests

# 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

๐Ÿ› Bugs Found & Fixed

Property-based testing discovered critical issues during development:

Grammar Ambiguity: The original grammar allowed -5 to parse as either Neg(Number(5)) or Number(-5), causing non-deterministic behavior. Fixed by removing minus signs from number literals.

Precision Edge Cases: Tests revealed floating-point precision issues with expressions like 1e20 + 1 - 1e20, leading to more robust error tolerance.

Deep Nesting Limits: Found parser performance cliffs at ~40+ nesting levels, optimized for practical use cases.

๐Ÿ“Š Code Examples

Basic Usage

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);

Advanced Features

// 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!(),
}

๐Ÿ“ Project Structure

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

๐Ÿ”— Dependencies

[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

๐ŸŽ“ Educational Value

This project serves as an excellent case study for:

  • Modern Parser Design: Pratt parsers vs recursive descent
  • Property-Based Testing: Discovering edge cases automatically
  • Rust Best Practices: Error handling, type safety, zero-cost abstractions
  • Protocol Implementation: MCP server development
  • Mathematical Correctness: Ensuring arithmetic laws hold

Perfect for blog posts, tutorials, and educational content about robust software development.

๐Ÿ“ License

MIT - See LICENSE for details.


๐Ÿ”ฎ Ready for production use with confidence backed by comprehensive testing! ๐Ÿ”ฎ

Related Servers