Getting Started

Install ZAP and build your first AI agent

This guide walks you through installing ZAP and building your first AI agent.

Prerequisites

  • Cap'n Proto compiler (capnp)
  • Language-specific toolchain (Rust, Go, Python, etc.)
brew install capnp
# Debian/Ubuntu
sudo apt-get install capnproto libcapnp-dev

# Fedora
sudo dnf install capnproto capnproto-devel
# Using Chocolatey
choco install capnproto

# Or download from https://capnproto.org/install.html

Installation

cargo add zap-proto
[dependencies]
zap-proto = "0.1"
tokio = { version = "1", features = ["full"] }
go get github.com/zap-proto/go
pip install zap-proto

Or with uv:

uv add zap-proto
npm install @zap-proto/zap

Or with pnpm:

pnpm add @zap-proto/zap

Quick Start

1

Create a ZAP Client

use zap_protocol::{Zap, ClientInfo};

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

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

    println!("Connected to: {} v{}", server_info.name, server_info.version);
    println!("Capabilities: {:?}", server_info.capabilities);

    Ok(())
}
package main

import (
    "context"
    "fmt"
    "log"

    zap "github.com/zap-proto/go"
)

func main() {
    ctx := context.Background()

    // Connect to ZAP server
    client, err := zap.Connect(ctx, "zap://localhost:9000")
    if err != nil {
        log.Fatal(err)
    }
    defer client.Close()

    // Initialize with client info
    serverInfo, err := client.Init(ctx, &zap.ClientInfo{
        Name:    "my-agent",
        Version: "1.0.0",
    })
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Connected to: %s v%s\n", serverInfo.Name, serverInfo.Version)
}
import asyncio
from zap_protocol import Zap, ClientInfo

async def main():
    # Connect to ZAP server
    client = await Zap.connect("zap://localhost:9000")

    # Initialize with client info
    server_info = await client.init(ClientInfo(
        name="my-agent",
        version="1.0.0"
    ))

    print(f"Connected to: {server_info.name} v{server_info.version}")
    print(f"Capabilities: {server_info.capabilities}")

asyncio.run(main())
import { Zap, ClientInfo } from '@zap-proto/zap';

async function main() {
  // Connect to ZAP server
  const client = await Zap.connect('zap://localhost:9000');

  // Initialize with client info
  const serverInfo = await client.init({
    name: 'my-agent',
    version: '1.0.0'
  });

  console.log(`Connected to: ${serverInfo.name} v${serverInfo.version}`);
  console.log('Capabilities:', serverInfo.capabilities);
}

main().catch(console.error);
2

List and Call Tools

// List available tools
let tools = client.list_tools().await?;

for tool in &tools {
    println!("Tool: {} - {}", 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(&json!({
        "path": "/etc/hosts"
    }))?,
    metadata: Default::default(),
}).await?;

if let Some(error) = result.error {
    eprintln!("Tool error: {}", error);
} else {
    let content: serde_json::Value = serde_json::from_slice(&result.content)?;
    println!("Result: {}", content);
}
// List available tools
tools, err := client.ListTools(ctx)
if err != nil {
    log.Fatal(err)
}

for _, tool := range tools {
    fmt.Printf("Tool: %s - %s\n", tool.Name, tool.Description)
}

// Call a tool
result, err := client.CallTool(ctx, &zap.ToolCall{
    ID:   uuid.New().String(),
    Name: "read_file",
    Args: []byte(`{"path": "/etc/hosts"}`),
})
if err != nil {
    log.Fatal(err)
}

if result.Error != "" {
    log.Printf("Tool error: %s", result.Error)
} else {
    fmt.Printf("Result: %s\n", result.Content)
}
# List available tools
tools = await client.list_tools()

for tool in tools:
    print(f"Tool: {tool.name} - {tool.description}")

# Call a tool
result = await client.call_tool(ToolCall(
    id=str(uuid.uuid4()),
    name="read_file",
    args=json.dumps({"path": "/etc/hosts"}).encode()
))

if result.error:
    print(f"Tool error: {result.error}")
else:
    content = json.loads(result.content)
    print(f"Result: {content}")
// List available tools
const tools = await client.listTools();

for (const tool of tools) {
  console.log(`Tool: ${tool.name} - ${tool.description}`);
}

// Call a tool
const result = await client.callTool({
  id: crypto.randomUUID(),
  name: 'read_file',
  args: JSON.stringify({ path: '/etc/hosts' })
});

if (result.error) {
  console.error('Tool error:', result.error);
} else {
  const content = JSON.parse(result.content);
  console.log('Result:', content);
}
3

Bridge MCP Servers

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

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

// Add MCP filesystem server
let fs_id = gateway.add_server(
    "filesystem",
    "stdio://npx -y @modelcontextprotocol/server-filesystem /tmp",
    ServerConfig {
        transport: Transport::Stdio,
        ..Default::default()
    },
).await?;

// Add MCP GitHub server
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")?)),
        ..Default::default()
    },
).await?;

// Now use gateway.list_tools() to get tools from all servers
let all_tools = gateway.list_tools().await?;
// Create gateway
gateway := zap.NewGateway()

// Add MCP filesystem server
fsID, err := gateway.AddServer(ctx, "filesystem",
    "stdio://npx -y @modelcontextprotocol/server-filesystem /tmp",
    &zap.ServerConfig{
        Transport: zap.TransportStdio,
    })
if err != nil {
    log.Fatal(err)
}

// Add MCP GitHub server
ghID, err := gateway.AddServer(ctx, "github",
    "stdio://npx -y @modelcontextprotocol/server-github",
    &zap.ServerConfig{
        Transport: zap.TransportStdio,
        Auth: &zap.Auth{
            Bearer: os.Getenv("GITHUB_TOKEN"),
        },
    })
if err != nil {
    log.Fatal(err)
}

// Get tools from all servers
allTools, _ := gateway.ListTools(ctx)
from zap_protocol import Gateway, ServerConfig, Transport, Auth
import os

# Create gateway
gateway = Gateway()

# Add MCP filesystem server
fs_id = await gateway.add_server(
    "filesystem",
    "stdio://npx -y @modelcontextprotocol/server-filesystem /tmp",
    ServerConfig(transport=Transport.STDIO)
)

# Add MCP GitHub server
gh_id = await gateway.add_server(
    "github",
    "stdio://npx -y @modelcontextprotocol/server-github",
    ServerConfig(
        transport=Transport.STDIO,
        auth=Auth(bearer=os.environ["GITHUB_TOKEN"])
    )
)

# Get tools from all servers
all_tools = await gateway.list_tools()
import { Gateway, ServerConfig, Transport, Auth } from '@zap-proto/zap';

// Create gateway
const gateway = new Gateway();

// Add MCP filesystem server
const fsId = await gateway.addServer(
  'filesystem',
  'stdio://npx -y @modelcontextprotocol/server-filesystem /tmp',
  { transport: Transport.STDIO }
);

// Add MCP GitHub server
const ghId = await gateway.addServer(
  'github',
  'stdio://npx -y @modelcontextprotocol/server-github',
  {
    transport: Transport.STDIO,
    auth: { bearer: process.env.GITHUB_TOKEN }
  }
);

// Get tools from all servers
const allTools = await gateway.listTools();

Next Steps

Was this page useful?
Last updated Oct 5, 2026