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