ZAP Protocol
Language Bindings

Rust

ZAP Rust SDK - Reference implementation

Rust Binding

The Rust binding is the reference ZAP implementation with full async support, post-quantum cryptography, and Ringtail consensus.

Installation

Add to your Cargo.toml:

[dependencies]
zap-protocol = "0.1"
tokio = { version = "1", features = ["full"] }

# Optional features
zap-protocol = { version = "0.1", features = ["pq-tls", "ringtail", "did"] }

Quick Start

use zap_protocol::{Zap, ClientInfo, ToolCall};
use anyhow::Result;

#[tokio::main]
async fn main() -> Result<()> {
    // Connect to ZAP server
    let client = Zap::connect("zap://localhost:9000").await?;

    // Initialize
    let server = client.init(ClientInfo {
        name: "my-agent".into(),
        version: "1.0.0".into(),
    }).await?;

    println!("Connected to: {} v{}", server.name, server.version);

    // List tools
    let tools = client.list_tools().await?;
    for tool in &tools {
        println!("  {} - {}", tool.name, tool.description);
    }

    // Call a tool
    let result = client.call_tool(&ToolCall {
        id: uuid::Uuid::new_v4().to_string(),
        name: "read_file".into(),
        args: serde_json::to_vec(&serde_json::json!({
            "path": "/etc/hosts"
        }))?,
        metadata: Default::default(),
    }).await?;

    if let Some(err) = result.error {
        eprintln!("Error: {}", err);
    } else {
        println!("Result: {}", String::from_utf8_lossy(&result.content));
    }

    Ok(())
}

Client API

Connection

use zap_protocol::{Zap, ConnectOptions};

// Simple connection
let client = Zap::connect("zap://localhost:9000").await?;

// With options
let client = Zap::connect_with_options(
    "zap+pq://localhost:9000",
    ConnectOptions {
        timeout: Duration::from_secs(30),
        identity: Some(identity),
        ..Default::default()
    }
).await?;

Tools

// List tools
let tools: Vec<Tool> = client.list_tools().await?;

// Call tool
let call = ToolCall {
    id: "call-1".into(),
    name: "my_tool".into(),
    args: b"{}".to_vec(),
    metadata: Metadata::default(),
};
let result: ToolResult = client.call_tool(&call).await?;

Resources

// List resources
let resources: Vec<Resource> = client.list_resources().await?;

// Read resource
let content: ResourceContent = client.read_resource("file:///etc/hosts").await?;

// Subscribe to updates
let stream = client.subscribe("file:///var/log/app.log").await?;
while let Some(update) = stream.next().await {
    println!("Update: {:?}", update);
}

Prompts

// List prompts
let prompts: Vec<Prompt> = client.list_prompts().await?;

// Get prompt messages
let args = Metadata::from([("topic", "rust")]);
let messages: Vec<PromptMessage> = client.get_prompt("code_review", args).await?;

Gateway

use zap_protocol::{Gateway, ServerConfig, Transport, Auth};

// Create gateway
let gateway = Gateway::new().await?;

// Add MCP server
let id = gateway.add_server(
    "filesystem",
    "stdio://npx -y @modelcontextprotocol/server-filesystem /tmp",
    ServerConfig {
        transport: Transport::Stdio,
        auth: None,
        timeout: 30000,
    }
).await?;

// Add with authentication
let gh_id = gateway.add_server(
    "github",
    "stdio://npx -y @modelcontextprotocol/server-github",
    ServerConfig {
        transport: Transport::Stdio,
        auth: Some(Auth::Bearer(std::env::var("GITHUB_TOKEN")?)),
        timeout: 60000,
    }
).await?;

// List all tools from all servers
let tools = gateway.list_tools().await?;

// Check server status
let status = gateway.server_status(&id).await?;
println!("Server status: {:?}", status);

Post-Quantum TLS

Enable the pq-tls feature:

[dependencies]
zap-protocol = { version = "0.1", features = ["pq-tls"] }
use zap_protocol::{Zap, PQIdentity};

// Generate or load identity
let identity = PQIdentity::generate()?;
// or
let identity = PQIdentity::load("./identity.key")?;

// Connect with PQ-TLS
let client = Zap::connect_pq(
    "zap+pq://localhost:9000",
    identity,
).await?;

Ringtail Consensus

Enable the ringtail feature:

[dependencies]
zap-protocol = { version = "0.1", features = ["ringtail"] }
use zap_protocol::ringtail::{Party, Coordinator, SignRequest};

// Create party
let party = Party::new(party_id, total_parties, threshold)?;

// Join coordinator
let coordinator = Coordinator::connect("zap://coordinator:9001").await?;
coordinator.register(&party).await?;

// Sign message
let request = SignRequest {
    message: b"Sign this message".to_vec(),
    session_id: 1,
    participants: vec![0, 1, 2],
    timeout_ms: 30000,
};

let signature = coordinator.sign(request).await?;

// Verify
let valid = party.verify(&signature, b"Sign this message")?;

DID Support

Enable the did feature:

[dependencies]
zap-protocol = { version = "0.1", features = ["did"] }
use zap_protocol::did::{Did, DidMethod, DidRegistry};

// Create DID
let did = Did::new(DidMethod::Key, public_key)?;
println!("DID: {}", did);  // did:key:z6Mk...

// Connect to registry
let registry = DidRegistry::connect("zap://did-registry:9002").await?;

// Resolve DID
let doc = registry.resolve(&did).await?;
println!("Controller: {}", doc.controller);

// Create blockchain-anchored DID
let lux_did = registry.create(DidMethod::Lux, public_key, services).await?;

Error Handling

use zap_protocol::{Error, ErrorKind};

match client.call_tool(&call).await {
    Ok(result) => {
        if let Some(err) = result.error {
            println!("Tool error: {}", err);
        }
    }
    Err(Error { kind: ErrorKind::Disconnected, .. }) => {
        println!("Connection lost, reconnecting...");
        client.reconnect().await?;
    }
    Err(Error { kind: ErrorKind::Timeout, .. }) => {
        println!("Request timed out");
    }
    Err(e) => {
        return Err(e.into());
    }
}

Server Implementation

use zap_protocol::server::{Server, ZapImpl};

struct MyZapServer;

#[async_trait]
impl ZapImpl for MyZapServer {
    async fn init(&self, client: ClientInfo) -> Result<ServerInfo> {
        Ok(ServerInfo {
            name: "my-server".into(),
            version: "1.0.0".into(),
            capabilities: Capabilities {
                tools: true,
                resources: true,
                prompts: false,
                logging: true,
            },
        })
    }

    async fn list_tools(&self) -> Result<Vec<Tool>> {
        Ok(vec![
            Tool {
                name: "hello".into(),
                description: "Says hello".into(),
                schema: serde_json::to_vec(&json!({
                    "type": "object",
                    "properties": {
                        "name": { "type": "string" }
                    }
                }))?,
                annotations: Default::default(),
            }
        ])
    }

    async fn call_tool(&self, call: ToolCall) -> Result<ToolResult> {
        match call.name.as_str() {
            "hello" => {
                let args: serde_json::Value = serde_json::from_slice(&call.args)?;
                let name = args["name"].as_str().unwrap_or("World");
                Ok(ToolResult {
                    id: call.id,
                    content: format!("Hello, {}!", name).into_bytes(),
                    error: None,
                    metadata: Default::default(),
                })
            }
            _ => Ok(ToolResult {
                id: call.id,
                content: vec![],
                error: Some("Unknown tool".into()),
                metadata: Default::default(),
            }),
        }
    }

    // ... other methods
}

#[tokio::main]
async fn main() -> Result<()> {
    let server = Server::new(MyZapServer).listen("0.0.0.0:9000").await?;
    server.run().await?;
    Ok(())
}

Testing

#[cfg(test)]
mod tests {
    use super::*;
    use zap_protocol::testing::MockZap;

    #[tokio::test]
    async fn test_tool_call() {
        let mut mock = MockZap::new();
        mock.expect_list_tools().returning(|| Ok(vec![
            Tool { name: "test".into(), ..Default::default() }
        ]));

        let tools = mock.list_tools().await.unwrap();
        assert_eq!(tools.len(), 1);
    }
}

Examples

Full examples available at:

Last updated on

On this page