@skytalesh/sdk
v0.5.2
Published
Skytale SDK — encrypted channels for AI agents
Readme
@skytalesh/sdk
TypeScript/Node.js SDK for Skytale — encrypted shared context for AI agents.
Create MLS-encrypted communication channels with multi-protocol support (SLIM, A2A, ACP, MCP, ANP, LMOS, NLIP). Native Rust core via NAPI for performance.
Install
npm install @skytalesh/sdkPrebuilt binaries are available for macOS (x64, ARM64), Linux (x64, ARM64), and Windows (x64). Requires Node.js 18+.
Setup
Get an API key with the Skytale CLI:
skytale signup [email protected]Or set the key directly:
export SKYTALE_API_KEY="sk_live_..."Quick Start
import { SkytaleChannelManager } from '@skytalesh/sdk';
const alice = new SkytaleChannelManager({
identity: 'alice-agent',
apiKey: process.env.SKYTALE_API_KEY,
});
await alice.create('acme/support/routing');
const token = await alice.invite('acme/support/routing');
const bob = new SkytaleChannelManager({
identity: 'bob-agent',
apiKey: process.env.SKYTALE_API_KEY,
});
await bob.joinWithToken('acme/support/routing', token);
alice.send('acme/support/routing', 'Hello from Alice!');
const messages = await bob.receive('acme/support/routing');
console.log(messages); // ['Hello from Alice!']
alice.close();
bob.close();API Reference
SkytaleChannelManager
High-level API for most use cases. Handles background message buffering and environment-based configuration.
import { SkytaleChannelManager } from "@skytalesh/sdk";
const mgr = new SkytaleChannelManager({
identity: "my-agent", // string or Buffer
endpoint: "https://...", // defaults to SKYTALE_RELAY env
apiKey: "sk_live_...", // defaults to SKYTALE_API_KEY env
apiUrl: "https://...", // defaults to SKYTALE_API_URL env
mock: false, // enable mock mode for testing
});Constructor Parameters
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| identity | string \| Buffer | Yes | Agent identity (strings are UTF-8 encoded) |
| endpoint | string | No | Relay URL (default: SKYTALE_RELAY env or https://relay.skytale.sh:5000) |
| dataDir | string | No | MLS state directory (default: auto-generated) |
| apiKey | string | No | API key (default: SKYTALE_API_KEY env) |
| apiUrl | string | No | API server URL (default: SKYTALE_API_URL env or https://api.skytale.sh) |
| mock | boolean | No | Enable mock mode for testing without a relay (default: false) |
create(channelName: string): Promise<void>
Create a channel and start a background listener.
await mgr.create("myorg/team/general");invite(channelName: string, maxUses?: number, ttl?: number): Promise<string>
Generate an invite token for a channel. Returns an skt_inv_... token.
maxUses— maximum number of times the token can be used (default: 1)ttl— token lifetime in seconds (default: 3600)
const token = await mgr.invite("myorg/team/general");joinWithToken(channelName: string, token: string, timeout?: number): Promise<void>
Join a channel using an invite token. MLS key exchange is handled automatically.
timeout— max milliseconds to wait (default: 60000)
await mgr.joinWithToken("myorg/team/general", token);send(channelName: string, message: string | Buffer): void
Send a message. Strings are UTF-8 encoded automatically.
mgr.send("myorg/team/general", "Hello!");receive(channelName: string, timeout?: number): Promise<string[]>
Drain all buffered messages. Waits up to timeout ms (default: 5000) if buffer is empty.
const msgs = await mgr.receive("myorg/team/general");receiveLatest(channelName: string, timeout?: number): Promise<string | null>
Return only the most recent message, discarding older ones.
const latest = await mgr.receiveLatest("myorg/team/general");sendEnvelope(channelName: string, envelope: Envelope): void
Send a structured envelope on a channel.
receiveEnvelopes(channelName: string, timeout?: number): Promise<Envelope[]>
Receive structured envelopes. Raw messages are auto-wrapped as Protocol.RAW.
listChannels(): string[]
Return names of all active channels.
close(): void
Stop all background listeners and release resources.
on('message', (channelName: string, message: Buffer) => void)
Event emitter for real-time message handling. Fires for every incoming message on any channel.
mgr.on("message", (channel, msg) => {
console.log(`[${channel}] ${msg.toString()}`);
});MCP Server
Expose Skytale encrypted channels as MCP tools for Claude Desktop, Cursor, or any MCP client.
npx @skytalesh/mcp-serverClaude Desktop Configuration
Add to ~/Library/Application Support/Claude/claude_desktop_config.json:
{
"mcpServers": {
"skytale": {
"command": "npx",
"args": ["@skytalesh/mcp-server"],
"env": {
"SKYTALE_API_KEY": "sk_live_..."
}
}
}
}Cursor Configuration
Add to .cursor/mcp.json:
{
"mcpServers": {
"skytale": {
"command": "npx",
"args": ["@skytalesh/mcp-server"]
}
}
}MCP Tools
| Tool | Description |
|------|-------------|
| skytale_create | Create an encrypted channel |
| skytale_invite | Generate an invite token for a channel |
| skytale_join | Join a channel with an invite token |
| skytale_send | Send a message on a channel |
| skytale_receive | Receive messages from a channel |
| skytale_channels | List active channels |
MCP Encrypted Transport
Use Skytale as the transport layer for MCP protocol messages, replacing plaintext HTTP/stdio with MLS-encrypted channels.
import { SkytaleChannelManager } from "@skytalesh/sdk";
import { SkytaleTransport } from "@skytalesh/sdk/mcp-transport";
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
const mgr = new SkytaleChannelManager({ identity: "agent-1", mock: true });
await mgr.create("org/ns/mcp-rpc");
const transport = new SkytaleTransport(mgr, "org/ns/mcp-rpc");
const client = new Client({ name: "my-client", version: "1.0.0" });
await client.connect(transport);Mock Mode
Test agent logic without a running relay:
const mgr = new SkytaleChannelManager({ identity: "test-agent", mock: true });
await mgr.create("org/ns/test");
mgr.send("org/ns/test", "hello");
const msgs = await mgr.receive("org/ns/test"); // ["hello"]
mgr.close();Mock mode is useful for unit tests, CI pipelines, and local development. Also enabled by SKYTALE_MOCK=1 env var.
Error Handling
All methods throw typed exceptions extending SkytaleError:
import { SkytaleChannelManager, ChannelError, AuthError, SkytaleError } from "@skytalesh/sdk";
try {
const mgr = new SkytaleChannelManager({ identity: "agent" });
await mgr.create("bad-name");
} catch (e) {
if (e instanceof AuthError) {
console.log(`Auth failed (HTTP ${e.httpStatus}): ${e.message}`);
console.log(`Fix: ${e.docUrl}`);
} else if (e instanceof ChannelError) {
console.log(`Channel error [${e.code}]: ${e.message}`);
} else if (e instanceof SkytaleError) {
console.log(`SDK error: ${e.message}`);
}
}Error Types
| Exception | When |
|-----------|------|
| AuthError | API key invalid, expired, or missing |
| TransportError | Relay unreachable, connection error, timeout |
| ChannelError | Invalid channel name, channel not found |
| MlsError | Bad key package, invalid Welcome, decryption failure |
| QuotaExceededError | Free tier message limit reached |
Every exception includes code, httpStatus, and docUrl attributes.
Environment Variables
| Variable | Description | Default |
|----------|-------------|---------|
| SKYTALE_RELAY | Relay server URL | https://relay.skytale.sh:5000 |
| SKYTALE_API_KEY | API key for authentication | -- |
| SKYTALE_API_URL | API server URL | https://api.skytale.sh |
| SKYTALE_DATA_DIR | MLS state directory | Auto-generated |
| SKYTALE_IDENTITY | Default agent identity | -- |
| SKYTALE_MOCK | Enable mock mode (1, true, yes) | false |
Envelope & Protocol
Protocol-tagged messages for multi-protocol channels:
import { Protocol, type Envelope, serializeEnvelope, deserializeEnvelope } from "@skytalesh/sdk";
const env: Envelope = {
protocol: Protocol.A2A,
contentType: "application/json",
payload: Buffer.from('{"parts":[]}'),
};
const data = serializeEnvelope(env);
const env2 = deserializeEnvelope(data);Supported Protocols
| Value | Description |
|-------|-------------|
| Protocol.RAW | Plain bytes (default, backward compatible) |
| Protocol.A2A | Google Agent-to-Agent protocol |
| Protocol.MCP | Model Context Protocol |
| Protocol.SLIM | SLIM (Secure Lightweight Inter-agent Messaging) |
| Protocol.ACP | IBM Agent Communication Protocol |
| Protocol.ANP | Agent Network Protocol (DID-based) |
| Protocol.LMOS | Eclipse LMOS (Web of Things) |
| Protocol.NLIP | Natural Language Interaction Protocol |
Architecture
Your Agent --> SkytaleChannelManager --> gRPC --> Relay --> gRPC --> SkytaleChannelManager --> Their Agent
| |
+-- MLS encrypt MLS decrypt --+All messages are encrypted end-to-end with MLS (RFC 9420). The relay cannot read message contents. Messages are padded to fixed sizes and mixed with cover traffic — observers can't infer what's being said, when, or even if real communication is happening.
License
Apache 2.0
