enki-runtime 0.1.4

A Rust-based agent mesh framework for building local and distributed AI agent systems
Documentation
//! Example: Connecting MCP Client to Enki MCP Server
//!
//! This example demonstrates how to connect to the Enki MCP server
//! (mcp_server example) and use its calculator tools.
//!
//! To run this example:
//! 1. First build: cargo build --examples --features mcp
//! 2. Then run: cargo run --example mcp_client --features mcp

use enki_runtime::mcp::{McpClient, McpTransport};
use serde_json::json;
use std::path::PathBuf;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    println!("=== MCP Client Example ===\n");
    println!("Connecting to Enki Calculator MCP Server...\n");

    // Find the mcp_server binary in target directory
    let server_path = find_mcp_server_binary();

    println!("Using server binary: {}\n", server_path.display());

    let transport = McpTransport::stdio(server_path.to_string_lossy().to_string(), vec![]);

    match McpClient::connect(transport).await {
        Ok(client) => {
            println!("✓ Connected to Enki MCP Server!\n");

            // List available tools
            let tools = client.tools();
            println!("Available tools ({}):", tools.len());
            for tool in tools {
                println!(
                    "  - {}: {}",
                    tool.name,
                    tool.description.as_deref().unwrap_or("No description")
                );
            }

            // Test the calculator tools
            println!("\n--- Testing Calculator Tools ---\n");

            // Test add
            println!("Calling add(10, 5)...");
            match client.call_tool("add", json!({"a": 10, "b": 5})).await {
                Ok(result) => println!("  Result: {}\n", result),
                Err(e) => println!("  Error: {}\n", e),
            }

            // Test subtract
            println!("Calling subtract(20, 8)...");
            match client.call_tool("subtract", json!({"a": 20, "b": 8})).await {
                Ok(result) => println!("  Result: {}\n", result),
                Err(e) => println!("  Error: {}\n", e),
            }

            // Test multiply
            println!("Calling multiply(7, 6)...");
            match client.call_tool("multiply", json!({"a": 7, "b": 6})).await {
                Ok(result) => println!("  Result: {}\n", result),
                Err(e) => println!("  Error: {}\n", e),
            }

            println!("--- All tests complete! ---\n");

            // Disconnect gracefully
            println!("Disconnecting...");
            if let Err(e) = client.disconnect().await {
                println!("Disconnect warning: {}", e);
            }
        }
        Err(e) => {
            println!("✗ Failed to connect to MCP server: {}\n", e);
            println!("Make sure you have built the mcp_server example first:");
            println!("  cargo build --example mcp_server --features mcp");
            println!("\nExpected binary at: {}", server_path.display());
        }
    }

    println!("\n=== Example Complete ===");
    Ok(())
}

/// Find the mcp_server binary in the target directory
fn find_mcp_server_binary() -> PathBuf {
    // Try to find the binary relative to the current exe or manifest
    let exe_name = if cfg!(windows) {
        "mcp_server.exe"
    } else {
        "mcp_server"
    };

    // Check common locations
    let candidates = vec![
        // Relative to workspace root
        PathBuf::from("target/debug/examples").join(exe_name),
        PathBuf::from("../target/debug/examples").join(exe_name),
        PathBuf::from("../../target/debug/examples").join(exe_name),
        // From CARGO_MANIFEST_DIR
        std::env::var("CARGO_MANIFEST_DIR")
            .map(|dir| {
                PathBuf::from(dir)
                    .join("../target/debug/examples")
                    .join(exe_name)
            })
            .unwrap_or_default(),
    ];

    for path in candidates {
        if path.exists() {
            return path.canonicalize().unwrap_or(path);
        }
    }

    // Default path
    PathBuf::from("target/debug/examples").join(exe_name)
}