#[async_trait]
impl TemplateGenerator for MCPServerTemplate {
fn generate(&self, ctx: &AgentContext) -> Result<GeneratedFiles> {
let mut files = GeneratedFiles::new();
files.add_text_file("Cargo.toml", generate_mcp_cargo_toml(ctx));
files.add_text_file("src/main.rs", generate_mcp_main(ctx));
files.add_text_file("src/mcp/mod.rs", generate_mcp_mod());
files.add_text_file("src/mcp/server.rs", generate_mcp_server(ctx));
files.add_text_file("src/mcp/tools.rs", generate_mcp_tools());
files.add_text_file("src/mcp/transport.rs", generate_mcp_transport());
files.add_text_file("src/agent/mod.rs", generate_agent_mod());
files.add_text_file("src/agent/core.rs", generate_agent_core(ctx));
files.add_text_file("src/agent/handlers.rs", generate_agent_handlers());
if ctx.quality_level != QualityLevel::Standard {
files.add_text_file("src/quality/mod.rs", generate_quality_mod());
files.add_text_file("src/quality/invariants.rs", generate_invariants());
files.add_text_file("src/quality/validators.rs", generate_validators());
}
files.add_text_file("tests/integration.rs", generate_integration_tests(ctx));
files.add_text_file("tests/deterministic.rs", generate_deterministic_tests());
files.add_text_file(".pmat/agent.toml", generate_agent_config(ctx));
files.add_text_file(".pmat/quality-gates.toml", generate_quality_gates(ctx));
files.add_text_file("README.md", generate_readme(ctx));
Ok(files)
}
fn validate_context(&self, ctx: &AgentContext) -> Result<()> {
if ctx.name.is_empty() {
bail!("Agent name is required");
}
Ok(())
}
fn name(&self) -> &str {
&self.name
}
fn description(&self) -> &str {
&self.description
}
}
fn generate_mcp_cargo_toml(ctx: &AgentContext) -> String {
format!(
r#"[package]
name = "{}"
version = "0.1.0"
edition = "2021"
[dependencies]
pmcp = "0.3.1"
tokio = {{ version = "1.40", features = ["full"] }}
serde = {{ version = "1.0", features = ["derive"] }}
serde_json = "1.0"
async-trait = "0.1"
anyhow = "1.0"
tracing = "0.1"
tracing-subscriber = {{ version = "0.3", features = ["env-filter"] }}
[dev-dependencies]
proptest = "1.5"
tokio-test = "0.4"
criterion = "0.5"
[[bench]]
name = "performance"
harness = false
"#,
ctx.name
)
}
fn generate_mcp_main(ctx: &AgentContext) -> String {
format!(
r#"//! {} - MCP Agent Server
use anyhow::Result;
use tracing::info;
use tracing_subscriber::EnvFilter;
mod agent;
mod mcp;
{}
#[tokio::main]
async fn main() -> Result<()> {{
// Initialize tracing
tracing_subscriber::fmt()
.with_env_filter(EnvFilter::from_default_env())
.init();
info!("Starting {} agent server");
// Start MCP server
mcp::server::run().await
}}
"#,
ctx.name,
if ctx.quality_level == QualityLevel::Standard {
""
} else {
"mod quality;"
},
ctx.name
)
}
fn generate_mcp_mod() -> String {
r"//! MCP server implementation.
pub mod server;
pub mod tools;
pub mod transport;
"
.to_string()
}
fn generate_mcp_server(ctx: &AgentContext) -> String {
format!(
r#"//! MCP server implementation for {}.
use anyhow::Result;
use pmcp::{{Server, ServerBuilder}};
use tracing::info;
use crate::agent::core::AgentCore;
use super::tools::register_tools;
use super::transport::create_transport;
/// Run the MCP server.
pub async fn run() -> Result<()> {{
let transport = create_transport().await?;
let agent = AgentCore::new();
let server = ServerBuilder::new()
.name("{}")
.version(env!("CARGO_PKG_VERSION"))
.build();
register_tools(&server, agent)?;
info!("MCP server listening");
server.serve(transport).await?;
Ok(())
}}
"#,
ctx.name, ctx.name
)
}
fn generate_mcp_tools() -> String {
r#"//! Tool definitions for MCP server.
use anyhow::Result;
use pmcp::{Server, Tool};
use serde_json::Value;
use crate::agent::core::AgentCore;
/// Register all tools with the MCP server.
pub fn register_tools(server: &Server, agent: AgentCore) -> Result<()> {
// Register analyze tool
server.register_tool(Tool {
name: "analyze".to_string(),
description: "Analyze input data".to_string(),
input_schema: serde_json::json!({
"type": "object",
"properties": {
"data": {
"type": "string",
"description": "Data to analyze"
}
},
"required": ["data"]
}),
handler: Box::new(move |params: Value| {
let agent = agent.clone();
Box::pin(async move {
agent.analyze(params).await
})
}),
});
Ok(())
}
"#
.to_string()
}
fn generate_mcp_transport() -> String {
r"//! Transport layer for MCP server.
use anyhow::Result;
use pmcp::transport::{StdioTransport, Transport};
/// Create the transport layer for the MCP server.
pub async fn create_transport() -> Result<Box<dyn Transport>> {
Ok(Box::new(StdioTransport::new()))
}
"
.to_string()
}
fn generate_agent_mod() -> String {
r"//! Agent implementation.
pub mod core;
pub mod handlers;
"
.to_string()
}
fn generate_agent_core(ctx: &AgentContext) -> String {
format!(
r#"//! Core agent implementation for {}.
use anyhow::Result;
use serde_json::Value;
use std::sync::Arc;
use tokio::sync::RwLock;
/// Core agent implementation.
#[derive(Clone)]
pub struct AgentCore {{
state: Arc<RwLock<AgentState>>,
}}
/// Agent state.
#[derive(Default)]
struct AgentState {{
// Add state fields as needed
}}
impl AgentCore {{
/// Create a new agent instance.
pub fn new() -> Self {{
Self {{
state: Arc::new(RwLock::new(AgentState::default())),
}}
}}
/// Analyze input data.
pub async fn analyze(&self, params: Value) -> Result<Value> {{
// Implementation here
Ok(serde_json::json!({{
"status": "success",
"result": "Analysis complete"
}}))
}}
}}
"#,
ctx.name
)
}
fn generate_agent_handlers() -> String {
r#"//! Request handlers for the agent.
use anyhow::Result;
use serde_json::Value;
/// Handle a request.
pub async fn handle_request(request: Value) -> Result<Value> {
// Implementation here
Ok(serde_json::json!({
"status": "success"
}))
}
"#
.to_string()
}
fn generate_quality_mod() -> String {
r"//! Quality enforcement module.
pub mod invariants;
pub mod validators;
"
.to_string()
}
fn generate_invariants() -> String {
r"//! Runtime invariants for quality enforcement.
use anyhow::Result;
/// Check all invariants.
pub fn check_invariants() -> Result<()> {
// Add invariant checks here
Ok(())
}
"
.to_string()
}
fn generate_validators() -> String {
r"//! Input and output validators.
use anyhow::Result;
use serde_json::Value;
/// Validate input.
pub fn validate_input(input: &Value) -> Result<()> {
// Add validation logic here
Ok(())
}
/// Validate output.
pub fn validate_output(output: &Value) -> Result<()> {
// Add validation logic here
Ok(())
}
"
.to_string()
}
fn generate_integration_tests(ctx: &AgentContext) -> String {
format!(
r"//! Integration tests for {}.
#[tokio::test]
async fn test_agent_startup() {{
// Test agent initialization
}}
#[tokio::test]
async fn test_tool_invocation() {{
// Test tool invocation
}}
",
ctx.name
)
}
fn generate_deterministic_tests() -> String {
r"//! Determinism verification tests.
use proptest::prelude::*;
proptest! {
#[test]
fn test_deterministic_behavior(input in any::<String>()) {
// Verify deterministic behavior
}
}
"
.to_string()
}
fn generate_agent_config(ctx: &AgentContext) -> String {
format!(
r#"# Agent configuration
[agent]
name = "{}"
version = "0.1.0"
template = "mcp-server"
[quality]
level = "{:?}"
"#,
ctx.name, ctx.quality_level
)
}
fn generate_quality_gates(ctx: &AgentContext) -> String {
let level = &ctx.quality_level;
format!(
r#"# Quality gate configuration
[complexity]
max_cyclomatic = {}
max_cognitive = {}
max_nesting = {}
[coverage]
min_line = {}
min_branch = {}
min_function = {}
[linting]
deny = ["unsafe_code", "missing_docs", "clippy::all"]
warn = ["clippy::pedantic"]
[satd]
allowed_markers = []
scan_comments = true
"#,
level.max_complexity(),
level.max_cognitive_complexity(),
level.max_nesting(),
level.min_line_coverage(),
level.min_branch_coverage(),
level.min_function_coverage()
)
}
fn generate_readme(ctx: &AgentContext) -> String {
format!(
r"# {}
MCP Agent Server generated with PMAT.
## Quick Start
```bash
cargo build --release
cargo run
```
## Testing
```bash
cargo test
cargo test --test integration
```
## Quality
This agent follows {} quality standards.
",
ctx.name,
match ctx.quality_level {
QualityLevel::Standard => "standard",
QualityLevel::Strict => "strict",
QualityLevel::Extreme => "Toyota Way extreme",
}
)
}