skills/contextvm/cvmi/client-dev

client-dev

SKILL.md

ContextVM Client Development

Build MCP clients that connect to ContextVM servers over the Nostr network.

Quick Start

Connect to a ContextVM server:

import { Client } from '@modelcontextprotocol/sdk/client';
import {
  NostrClientTransport,
  PrivateKeySigner,
  ApplesauceRelayPool,
  EncryptionMode,
} from '@contextvm/sdk';

const signer = new PrivateKeySigner(process.env.CLIENT_PRIVATE_KEY!);
const relayPool = new ApplesauceRelayPool(['wss://relay.contextvm.org', 'wss://cvm.otherstuff.ai']);

const SERVER_PUBKEY = 'server-public-key-hex';

const transport = new NostrClientTransport({
  signer,
  serverPubkey: SERVER_PUBKEY,
  encryptionMode: EncryptionMode.OPTIONAL,
});

const client = new Client({
  name: 'my-client',
  version: '1.0.0',
});

await client.connect(transport);

// Use the client
const tools = await client.listTools();
const result = await client.callTool({
  name: 'echo',
  arguments: { message: 'Hello' },
});

Server Discovery

Direct Connection (Known Pubkey)

Connect when you know the server's public key:

const transport = new NostrClientTransport({
  signer,
<<<<<<< feat/call
  relayHandler: relayPool,
  serverPubkey: 'known-server-pubkey',
=======
  serverPubkey: "known-server-pubkey",
>>>>>>> main
});

Discovery via Announcements

Find servers broadcasting on the network:

import { CTXVM_MESSAGES_KIND, SERVER_ANNOUNCEMENT_KIND } from '@contextvm/sdk';

// Query relays for server announcements
await relayPool.subscribe([{ kinds: [SERVER_ANNOUNCEMENT_KIND] }], (event) => {
  const serverInfo = JSON.parse(event.content);
  console.log(`Found server: ${serverInfo.serverInfo.name}`);
  console.log(`Pubkey: ${event.pubkey}`);
});

NostrClientTransport Options

Option Type Description
signer NostrSigner Required. Signs all Nostr events
relayHandler RelayHandler | string[] Optional explicit operational relays
serverPubkey string Required. Target server's public key
discoveryRelayUrls string[] Optional relay URLs for CEP-17 discovery lookups
encryptionMode EncryptionMode OPTIONAL, REQUIRED, or DISABLED
isStateless boolean Skip initialization handshake. Default: false
logLevel LogLevel Logging verbosity

Relay Resolution Order

NostrClientTransport resolves operational relays in this order:

  1. explicit operational relays from relayHandler
  2. relay hints embedded in nprofile
  3. CEP-17 relay-list discovery via discoveryRelayUrls
  4. SDK bootstrap discovery relays when discoveryRelayUrls is omitted

This allows leaner client setup when the target server already publishes kind:10002 metadata.

Stateless Mode

Skip the initialization handshake for faster connections:

const transport = new NostrClientTransport({
  signer,
  serverPubkey: SERVER_PUBKEY,
  isStateless: true, // Skip initialize roundtrip
});

Proxy Pattern

Use NostrMCPProxy to connect existing MCP clients to ContextVM servers:

import { NostrMCPProxy } from '@contextvm/sdk';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';

const proxy = new NostrMCPProxy({
  // Local transport for existing client to connect to
  mcpHostTransport: new StdioServerTransport(),

  // Remote server connection
  nostrTransportOptions: {
    signer,
    serverPubkey: SERVER_PUBKEY,
  },
});

await proxy.start();

This allows any standard MCP client to use ContextVM servers without native support.

Encryption

Control encryption behavior:

// Require encrypted connections only
encryptionMode: EncryptionMode.REQUIRED;

// Use encryption if server supports it (default)
encryptionMode: EncryptionMode.OPTIONAL;

// Never use encryption
encryptionMode: EncryptionMode.DISABLED;

Client Templates

See assets/client-template.ts for a complete boilerplate.

Tooling: ctxcn (generate a typed TypeScript client)

If you are building a TypeScript app and want remote ContextVM tools to feel like local functions, use ctxcn.

High-level behavior:

  • Connects to a ContextVM server.
  • Reads tools/list schemas.
  • Generates TypeScript client code into your repo (shadcn-style: you own the generated code).

From ContextVM docs/blog references, the basic flow is:

npx @contextvm/ctxcn init
npx @contextvm/ctxcn add <server-pubkey>
npx @contextvm/ctxcn update

Use this when:

  • You want end-to-end type safety.
  • You want IDE autocomplete for server tools.
  • You want to avoid hand-writing tool interfaces.

Reference Materials

Weekly Installs
26
Repository
contextvm/cvmi
GitHub Stars
1
First Seen
Feb 12, 2026
Installed on
opencode24
gemini-cli24
github-copilot24
codex24
cursor24
amp23