Example Model Context Protocol (MCP) Server providing a penalty calculation function
An example Model Context Protocol (MCP) server developed in Rust that provides a strongly-typed penalty calculation function. This project demonstrates how to build MCP servers with explicit computational logic.
Enterprises who need to comply with regulations that make them to have their data secure and on-premise but at the same time want to leverage the power of AI usually rely on small models. These models alveit powerful some times are not capable enough to deal with complex, multi-step, logic and hence are not as realiable as a highly regulated environment needs.
Some references around this subject:
- Mathematical Reasoning in Large Language Models: Assessing Logical and Arithmetic Errors across Wide Numerical Ranges
- The Validation Gap: A Mechanistic Analysis of How Language Models Compute Arithmetic but Fail to Validate It
- Self-Error-Instruct: Generalizing from Errors for LLMs Mathematical Reasoning
This server provides a penalty calculation function that demonstrates explicit, transparent business logic.
This is a demonstration/example project only. The calculations and logic implemented here are for educational and demonstration purposes. This software:
- Should NOT be used for actual financial or legal decisions
- Does NOT represent real business calculations
- Is NOT affiliated with any official entity
- Serves as a technical example of MCP server implementation
For real financial or legal calculations, please consult appropriate professional services.
In fictional Lysmark Republic the Ministry of Technology and Innovation have started to build a ChatBOT to help their citizens with their queries and although they tried to build it around a naΓ―ve RAG soon they realized that queries like "What penalty applies for a 15-day delay?" weren't easy to resolve this way. As a small country at Lysmark Republic they tend to be frugal and prefer enginering solution over just throwing resources at problems.
So they decided to use agents and in order to provide tools to the agents in a standard way they built an MCP server starting with this legal document:
- Calculation Function: calc_penalty
- Explicit Logic: No external dependencies - all logic is transparent and verifiable
- Robust Input Validation: Demonstrates JSON schema validation with detailed error handling
- Containerization: Example Podman setup for deployment
- Claude Desktop Integration: Example MCPB packaging for MCP integration
- Professional Version Management: Automated version sync with cargo-release
- CI/CD Pipeline: Comprehensive GitHub Actions workflow
- Clean Repository Structure: Organized scripts and clean project layout
| Task | Command | Description |
|---|---|---|
| π§ͺ Test | make test |
Run all tests |
| π§ͺ Test MCP | make test-mcp |
Run MCP server with Streamable HTTP transport |
| π Release | make release-patch |
Create new patch release |
| π¦ Package | make pack |
Create Claude Desktop package |
| π³ Container | make image-build |
Build container image |
| βΉοΈ Help | make help |
Show all commands |
| Function | Description | Example |
|---|---|---|
| calc_penalty | Calculate penalty with cap and interest | 12 days late Γ 100/day = 1,050 with interest |
Note: This function demonstrates a common multi-step calculation pattern.
If there's a 15 day delay, then penalty is $1,050
- Base penalty: 15 days Γ $100 = $1,500
- Cap applied: $1,500 capped at $1,000
- Interest: $1,000 Γ 5.0% = $50
- Total Penalty: $1,050
- Warning: Base penalty exceeded cap of $1,000
When querying the LLM with this MCP agent:
- Be specific with numbers - Provide exact figures for calculations
- Include context - Mention the policy, contract type, or jurisdiction
- Ask for explanations - The tools provide detailed step-by-step breakdowns
- Ask for clarity - The tool returns a step-by-step explanation
- Use natural language - No need to know the exact API parameters
- Rust 1.70+ (Install Rust)
- Cargo (included with Rust)
jqfor JSON processing (Install jq)cargo-releasefor version management:cargo install cargo-release- NodeJS 19+ has to be installed if you want to test the server with MCP Inspector
# Clone the repository
git clone https://github.com/alpha-hack-program/penalty-engine-mcp-rs.git
cd penalty-engine-mcp-rs# Build all servers
make build-all
# Or build individually
make build-mcp # MCP Streamable HTTP Server
make build-stdio # STDIO Server for Claude# Run all tests
make testNOTE:
By default
BIND_ADDRESS=127.0.0.1:8000for Streamable HTTPBUT in the Makefile
test-mcptargets setBIND_ADDRESS=0.0.0.0:8001
# MCP Streamable HTTP Server
make test-mcp
# Or directly
RUST_LOG=info BIND_ADDRESS=127.0.0.1:8002 ./target/release/mcp_serverLet's run the MCP server with Streamable HTTP transport in one terminal:
make test-mcpRun MCP inspector with make inspector:
NOTE: NodeJS 19+ has to be installed
$ make inspector
npx @modelcontextprotocol/inspector
Starting MCP inspector...
βοΈ Proxy server listening on 127.0.0.1:6277
π Session token: 6f0fdc22e2a9775a95d60c976b37b873bffec1816002fc702ca8ec7186a7c338
Use this token to authenticate requests or set DANGEROUSLY_OMIT_AUTH=true to disable auth
π Open inspector with token pre-filled:
http://localhost:6274/?MCP_PROXY_AUTH_TOKEN=6f0fdc22e2a9775a95d60c976b37b873bffec1816002fc702ca8ec7186a7c338
π MCP Inspector is up and running at http://127.0.0.1:6274 πOpen a browser and point to the URL with the token pre-filled.
Make sure:
- Transport Type:
Streamable HTTP - URL:
http://localhost:8002/mcp
Then click connect.
Now click on List Tools, then you should see the list of tools:
Finally click on calc_penalty, fill in the form and click Run tool:
- days_late: 12
Congratulations your Penalty tool is ready to be used by an MCP enabled agent.
# Create MCPB package for Claude Desktop
$ make pack
cargo build --release --bin stdio_server
Compiling penalty-engine-mcp-rs v1.0.8 (/Users/.../penalty-engine-mcp-rs)
Finished `release` profile [optimized] target(s) in 18.23s
Packing MCP server for Claude Desktop...
chmod +x ./target/release/stdio_server
zip -rX penalty-engine-mcp-rs.mcpb -j mcpb/manifest.json ./target/release/stdio_server
updating: manifest.json (deflated 49%)
updating: stdio_server (deflated 63%)Open Claude Desktop and go to Settings->Extensions dropping area.
Note: This demonstrates MCP integration patterns and is not intended for production use with real data.
Drag and drop the MCPB file.
Click on Install:
Click on Install:
Click on Configure then close the dialog.
Your're ready to go, open a new chat:
Use this example query "We had a 12-day delay on a contract. What penalty applies under our standard terms?":
Congratulation the tool works with Claude Desktop.
# Logging level (debug, info, warn, error)
RUST_LOG=info
# Or use BIND_ADDRESS directly
BIND_ADDRESS=127.0.0.1:8000{
"days_late": 12
}Response: 1050.0 (penalty capped at $1000 + 5% interest = $1050)
Important: These are example calculations for demonstration purposes only.
This requires podman or docker. Configuration is managed through .env file.
# Build container image
scripts/image.sh build
# Run locally
scripts/image.sh run
# Run from remote registry
scripts/image.sh push
scripts/image.sh run-remote
# Show container information
scripts/image.sh info# Production configuration
podman run -p 8001:8001 \
-e BIND_ADDRESS=0.0.0.0:8001 \
-e RUST_LOG=info \
quay.io/dgarciap/penalty-engine-mcp-server:latestmake build-all # Build all servers
make build-mcp # Build MCP server (streamable-http)
make build-sse # Build SSE server
make build-stdio # Build stdio server
make pack # Pack MCP server for Claude Desktopmake release-patch # Create patch release (1.0.6 β 1.0.7)
make release-minor # Create minor release (1.0.6 β 1.1.0)
make release-major # Create major release (1.0.6 β 2.0.0)
make release-dry-run # Show what release-patch would do
make sync-version # Manually sync version to all filesmake test # Run all tests
make test-sse # Test SSE server locally
make test-mcp # Test MCP server locallymake clean # Clean build artifacts
make help # Show all available commandsβββ src/ # Source code
β βββ common/
β β βββ penalty_engine.rs # MCP logic and calculation functions
β β βββ mod.rs
β βββ sse_server.rs # SSE Server
β βββ mcp_server.rs # MCP HTTP Server
β βββ stdio_server.rs # STDIO Server
βββ scripts/ # Utility scripts
β βββ sync-manifest-version.sh # Version sync for cargo-release
β βββ image.sh # Container management script
βββ mcpb/
β βββ manifest.json # Claude Desktop manifest
βββ .github/workflows/ # CI/CD pipelines
β βββ ci.yml # GitHub Actions workflow
βββ docs/ # Documentation
βββ .env # Environment variables
βββ Containerfile # Container definition
βββ Cargo.toml # Rust package manifest
βββ Makefile # Build commands
| Field | Type | Description |
|---|---|---|
days_late |
number | Number of days late |
rate_per_day |
number | Rate per day |
cap |
number | Maximum penalty cap |
interest_rate |
number | Interest rate (decimal) |
- Input validation: Strict JSON schemas
- Non-root user: Containers run as user
1001 - Security audit:
cargo auditin CI/CD - Minimal image: Based on UBI 9 minimal
- Fork the project
- Create feature branch:
git checkout -b feature/new-feature - Make changes and test:
make test - Commit changes:
git commit -am 'Add new feature' - Push to branch:
git push origin feature/new-feature - Create Pull Request
- Development: Make changes, test with
make test - Version Bump: Use
make release-patch/minor/major - Build: Use
make packfor Claude Desktop integration - Container: Use
make image-buildfor containerization
- Code Quality: Follow
cargo fmtand passcargo clippy - Testing: Add tests for new functionality
- Version Management: Let cargo-release handle versioning
- CI/CD: Ensure all GitHub Actions pass
- Documentation: Update README.md as needed
- Professional Structure: Keep scripts in
scripts/directory
This project uses cargo-release for professional version management with automatic synchronization across all configuration files.
From Cargo.toml release configuration:
[package.metadata.release]
# Don't publish to crates.io (since this is a binary project)
publish = false
# Don't push git tags (you can enable this if you want)
push = false
# Run pre-release hook
pre-release-hook = ["scripts/sync-manifest-version.sh"]
# Create git tag with 'v' prefix
tag-name = "v{{version}}"
# Sign tags (optional)
sign-tag = false- Single Source of Truth:
Cargo.tomlversion controls everything - Automatic Sync: Updates
mcpb/manifest.jsonand.envautomatically - Git Integration: Creates commits and tags automatically
Work on your code, then when happy with it:
# 1. Make your changes and commit them
git add -A && git commit -m "feat: your changes"
# 2. Create a release (choose appropriate version bump)
make release-patch # Bug fixes: 1.0.6 β 1.0.7
make release-minor # New features: 1.0.6 β 1.1.0
make release-major # Breaking changes: 1.0.6 β 2.0.0
# 3. Build and package
make pack
make image-build
make image-push
# 4. Push to repository
git push && git push --tags# See what would happen without making changes
make release-dry-run# Sync version from Cargo.toml to other files manually
make sync-versionWhen using this MCP agent with an LLM, users can ask natural language questions that trigger the appropriate calculation tools. Here are realistic scenarios:
Query: "We have a client who is 15 days late on their contractual obligations. What penalty should we charge them according to our standard terms?"
Result: $1,050
- Base penalty: 15 days Γ $100 = $1,500
- Cap applied: $1,500 capped at $1,000
- Interest: $1,000 Γ 5.0% = $50
- Total Penalty: $1,050
- Warning: Base penalty exceeded cap of $1,000
Query: "A vendor delivered our order 8 days late. Can you calculate the liquidated damages we should apply?"
Result: $840
- Base penalty: 8 days Γ $100 = $800
- No cap applied ($800 β€ $1,000)
- Interest: $800 Γ 5.0% = $40
- Total Penalty: $840
Query: "Our customer missed the payment deadline by 25 days. What's the total penalty including interest charges?"
Result: $1,050
- Base penalty: 25 days Γ $100 = $2,500
- Cap applied: $2,500 capped at $1,000
- Interest: $1,000 Γ 5.0% = $50
- Total Penalty: $1,050
- Warning: Base penalty exceeded cap of $1,000
Query: "Help me calculate the late delivery penalty for a project that was completed 12 days after the agreed deadline."
Result: $1,050
- Base penalty: 12 days Γ $100 = $1,200
- Cap applied: $1,200 capped at $1,000
- Interest: $1,000 Γ 5.0% = $50
- Total Penalty: $1,050
- Warning: Base penalty exceeded cap of $1,000
- Daily Rate: $100 per day late
- Maximum Cap: $1,000 (base penalty cannot exceed this amount)
- Interest Rate: 5% applied to the final penalty amount (after cap)
- Calculation Order: Daily penalty β apply cap β add interest
- Warning System: Alerts when base penalty exceeds the cap limit
The LLM will use calc_penalty with the specified days and apply configured defaults (100/day rate, 1000 cap, 5% interest).
This project is licensed under the MIT License - see LICENSE for details.
The project includes a comprehensive GitHub Actions workflow:
- β Automated Testing: Unit tests and integration tests
- β Version Sync Validation: Tests cargo-release functionality
- β Container Building: Tests containerization process
- β Artifact Management: Builds and uploads release artifacts
- β Cross-platform Support: Tests on Ubuntu with multiple container runtimes
- Issues: GitHub Issues
- Documentation: Project Wiki
- CI/CD: Automated testing and deployment via GitHub Actions
mcp model-context-protocol rust penalty-engine penalty explicit-logic claude computation-engine cargo-release professional-rust containerization ci-cd
Developed with β€οΈ by Alpha Hack Group









