| Crates.io | pforge-runtime |
| lib.rs | pforge-runtime |
| version | 0.1.4 |
| created_at | 2025-10-02 14:50:05.281965+00 |
| updated_at | 2025-12-06 12:08:49.872911+00 |
| description | Zero-boilerplate MCP server framework with EXTREME TDD methodology |
| homepage | https://github.com/paiml/pforge |
| repository | https://github.com/paiml/pforge |
| max_upload_size | |
| id | 1864486 |
| size | 297,646 |
Core runtime for building high-performance Model Context Protocol (MCP) servers with pforge.
Built on pmcp (Pragmatic AI Labs MCP SDK):
cargo add pforge-runtime
use pforge_runtime::prelude::*;
use serde_json::{json, Value};
#[derive(Default)]
struct CalculatorHandler;
#[async_trait::async_trait]
impl Handler for CalculatorHandler {
async fn handle(&self, params: Value) -> Result<Value> {
let a = params["a"].as_i64().ok_or(Error::Validation("Missing 'a'".into()))?;
let b = params["b"].as_i64().ok_or(Error::Validation("Missing 'b'".into()))?;
let op = params["op"].as_str().ok_or(Error::Validation("Missing 'op'".into()))?;
let result = match op {
"add" => a + b,
"sub" => a - b,
"mul" => a * b,
"div" if b != 0 => a / b,
_ => return Err(Error::Validation("Invalid operation".into())),
};
Ok(json!({ "result": result }))
}
}
#[tokio::main]
async fn main() -> Result<()> {
let mut registry = HandlerRegistry::new();
registry.register("calculator", Arc::new(CalculatorHandler::default()));
// Use the registry...
Ok(())
}
Pure Rust handlers compiled into your binary:
#[async_trait::async_trait]
impl Handler for MyHandler {
async fn handle(&self, params: Value) -> Result<Value> {
// Your logic here
Ok(json!({"status": "success"}))
}
}
Wrap command-line tools as MCP tools:
- type: cli
name: git_status
description: "Check git status"
command: git
args: ["status", "--short"]
Proxy HTTP endpoints as MCP tools:
- type: http
name: fetch_user
description: "Fetch user data"
endpoint: "https://api.example.com/users/{id}"
method: GET
Chain multiple tools together:
- type: pipeline
name: process_data
description: "Fetch and transform data"
steps:
- tool: fetch_data
- tool: transform
- tool: validate
Build composable middleware stacks:
use pforge_runtime::{MiddlewareChain, LoggingMiddleware, ValidationMiddleware, RecoveryMiddleware};
let mut chain = MiddlewareChain::new();
// Add logging
chain.add(Arc::new(LoggingMiddleware::new("my-server")));
// Add validation
chain.add(Arc::new(ValidationMiddleware::new(vec!["input".to_string()])));
// Add recovery with circuit breaker
chain.add(Arc::new(RecoveryMiddleware::new()
.with_circuit_breaker(CircuitBreakerConfig {
failure_threshold: 5,
timeout: Duration::from_secs(60),
success_threshold: 2,
})));
// Execute through middleware
let result = chain.execute(params, |req| async move {
// Handler logic
Ok(json!({"output": req["input"]}))
}).await?;
Persistent state for your handlers:
use pforge_runtime::{StateManager, MemoryStateManager};
let state = MemoryStateManager::new();
// Set a value
state.set("user:123", b"Alice".to_vec(), None).await?;
// Get a value
if let Some(value) = state.get("user:123").await? {
println!("User: {}", String::from_utf8_lossy(&value));
}
// Delete a value
state.delete("user:123").await?;
Prevent cascading failures:
use pforge_runtime::{CircuitBreaker, CircuitBreakerConfig};
let cb = CircuitBreaker::new(CircuitBreakerConfig {
failure_threshold: 5, // Open after 5 failures
timeout: Duration::from_secs(60), // Try again after 60s
success_threshold: 2, // Close after 2 successes
});
let result = cb.call(|| async {
// Potentially failing operation
risky_operation().await
}).await?;
Resilient execution with exponential backoff:
use pforge_runtime::{retry_with_policy, RetryPolicy};
let policy = RetryPolicy::new(3)
.with_backoff(Duration::from_millis(100), Duration::from_secs(5))
.with_jitter(true);
let result = retry_with_policy(&policy, || async {
unstable_operation().await
}).await?;
MIT