ZAP Protocol
Language Bindings

JavaScript

ZAP JavaScript SDK - Node.js and browser support

JavaScript Binding

The JavaScript binding supports both Node.js and browser environments with full TypeScript types.

Installation

npm install @zap-protocol/zap
# or
pnpm add @zap-protocol/zap
# or
yarn add @zap-protocol/zap

Quick Start

import { Zap, ClientInfo, ToolCall } from '@zap-protocol/zap';

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

  // Initialize
  const server = await client.init({
    name: 'my-agent',
    version: '1.0.0',
  });
  console.log(`Connected to: ${server.name} v${server.version}`);

  // List tools
  const tools = await client.listTools();
  for (const tool of tools) {
    console.log(`  ${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('Error:', result.error);
  } else {
    console.log('Result:', result.content);
  }

  await client.close();
}

main().catch(console.error);

Client API

Connection

// Simple connection
const client = await Zap.connect('zap://localhost:9000');

// With options
const client = await Zap.connect('zap://localhost:9000', {
  timeout: 30000,
  identity: identity,
});

Tools

// List tools
const tools: Tool[] = await client.listTools();

// Call tool
const result: ToolResult = await client.callTool({
  id: 'call-1',
  name: 'my_tool',
  args: JSON.stringify({ param: 'value' }),
});

// Parse result
const content = JSON.parse(result.content);

Resources

// List resources
const resources: Resource[] = await client.listResources();

// Read resource
const content: ResourceContent = await client.readResource('file:///etc/hosts');
console.log(content.text);

// Subscribe to updates
const stream = await client.subscribe('file:///var/log/app.log');
for await (const update of stream) {
  console.log('Update:', update.content);
}

Prompts

// List prompts
const prompts: Prompt[] = await client.listPrompts();

// Get prompt messages
const messages: PromptMessage[] = await client.getPrompt('code_review', {
  topic: 'javascript',
});

Gateway

import { Gateway, ServerConfig, Transport, Auth } from '@zap-protocol/zap';

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

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

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

// List all tools
const tools = await gateway.listTools();

// Check status
const status = await gateway.serverStatus(fsId);

TypeScript Types

Full TypeScript definitions:

import type {
  Zap,
  Tool,
  ToolCall,
  ToolResult,
  Resource,
  ResourceContent,
  Prompt,
  PromptMessage,
  ServerInfo,
  ClientInfo,
  Capabilities,
  Metadata,
} from '@zap-protocol/zap';

interface MyToolArgs {
  path: string;
}

async function callMyTool(client: Zap, path: string): Promise<string> {
  const result = await client.callTool({
    id: crypto.randomUUID(),
    name: 'read_file',
    args: JSON.stringify({ path } satisfies MyToolArgs),
  });

  if (result.error) {
    throw new Error(result.error);
  }

  return result.content;
}

Error Handling

import { ZapError, DisconnectedError, TimeoutError } from '@zap-protocol/zap';

try {
  const result = await client.callTool(call);
} catch (error) {
  if (error instanceof DisconnectedError) {
    console.log('Connection lost, reconnecting...');
    await client.reconnect();
  } else if (error instanceof TimeoutError) {
    console.log('Request timed out');
  } else if (error instanceof ZapError) {
    console.log('ZAP error:', error.message);
  }
}

Browser Support

For browser environments:

import { Zap } from '@zap-protocol/zap/browser';

// WebSocket connection
const client = await Zap.connect('zap+ws://localhost:9000');

Server Implementation (Node.js)

import { Server, ZapHandler } from '@zap-protocol/zap/server';
import type {
  ClientInfo,
  ServerInfo,
  Tool,
  ToolCall,
  ToolResult,
} from '@zap-protocol/zap';

class MyHandler implements ZapHandler {
  async init(client: ClientInfo): Promise<ServerInfo> {
    return {
      name: 'my-server',
      version: '1.0.0',
      capabilities: {
        tools: true,
        resources: true,
        prompts: false,
        logging: true,
      },
    };
  }

  async listTools(): Promise<Tool[]> {
    return [
      {
        name: 'hello',
        description: 'Says hello',
        schema: JSON.stringify({
          type: 'object',
          properties: { name: { type: 'string' } },
        }),
        annotations: {},
      },
    ];
  }

  async callTool(call: ToolCall): Promise<ToolResult> {
    if (call.name === 'hello') {
      const args = JSON.parse(call.args);
      const name = args.name || 'World';
      return {
        id: call.id,
        content: `Hello, ${name}!`,
      };
    }
    return {
      id: call.id,
      error: 'Unknown tool',
    };
  }

  // ... other methods
}

const server = new Server(new MyHandler());
server.listen(9000);

Async Patterns

Concurrent Calls

async function callToolsConcurrently(
  client: Zap,
  calls: ToolCall[]
): Promise<ToolResult[]> {
  return Promise.all(calls.map((call) => client.callTool(call)));
}

AbortController

const controller = new AbortController();

// Cancel after 10 seconds
setTimeout(() => controller.abort(), 10000);

try {
  const result = await client.callTool(call, {
    signal: controller.signal,
  });
} catch (error) {
  if (error.name === 'AbortError') {
    console.log('Request aborted');
  }
}

Testing

import { describe, it, expect, vi } from 'vitest';
import { Zap } from '@zap-protocol/zap';

describe('ZAP Client', () => {
  it('should list tools', async () => {
    const mockClient = {
      listTools: vi.fn().mockResolvedValue([
        { name: 'test', description: 'Test tool' },
      ]),
    } as unknown as Zap;

    const tools = await mockClient.listTools();
    expect(tools).toHaveLength(1);
    expect(tools[0].name).toBe('test');
  });
});

Examples

Full examples at:

Last updated on

On this page