client-dev

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

ContextVM Client Development

ContextVM客户端开发

Build MCP clients that connect to ContextVM servers over the Nostr network.
构建可通过Nostr网络连接到ContextVM服务器的MCP客户端。

Quick Start

快速开始

Connect to a ContextVM server:
typescript
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,
  relayHandler: relayPool,
  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" },
});
连接到ContextVM服务器:
typescript
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,
  relayHandler: relayPool,
  serverPubkey: SERVER_PUBKEY,
  encryptionMode: EncryptionMode.OPTIONAL,
});

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

await client.connect(transport);

// 使用客户端
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:
typescript
const transport = new NostrClientTransport({
  signer,
  relayHandler: relayPool,
  serverPubkey: "known-server-pubkey",
});
当你知道服务器公钥时进行连接:
typescript
const transport = new NostrClientTransport({
  signer,
  relayHandler: relayPool,
  serverPubkey: "known-server-pubkey",
});

Discovery via Announcements

通过公告发现

Find servers broadcasting on the network:
typescript
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}`);
});
查找在网络上广播的服务器:
typescript
import { CTXVM_MESSAGES_KIND, SERVER_ANNOUNCEMENT_KIND } from "@contextvm/sdk";

// 向中继查询服务器公告
await relayPool.subscribe([{ kinds: [SERVER_ANNOUNCEMENT_KIND] }], (event) => {
  const serverInfo = JSON.parse(event.content);
  console.log(`找到服务器:${serverInfo.serverInfo.name}`);
  console.log(`公钥:${event.pubkey}`);
});

NostrClientTransport Options

NostrClientTransport选项

OptionTypeDescription
signer
NostrSigner
Required. Signs all Nostr events
relayHandler
RelayHandler | string[]
Required. Relay connection manager
serverPubkey
string
Required. Target server's public key
encryptionMode
EncryptionMode
OPTIONAL
,
REQUIRED
, or
DISABLED
isStateless
boolean
Skip initialization handshake. Default:
false
logLevel
LogLevel
Logging verbosity
选项类型描述
signer
NostrSigner
必填项,对所有Nostr事件进行签名
relayHandler
RelayHandler | string[]
必填项,中继连接管理器
serverPubkey
string
必填项,目标服务器的公钥
encryptionMode
EncryptionMode
可选值为
OPTIONAL
REQUIRED
DISABLED
isStateless
boolean
跳过初始化握手,默认值:
false
logLevel
LogLevel
日志详细程度

Stateless Mode

无状态模式

Skip the initialization handshake for faster connections:
typescript
const transport = new NostrClientTransport({
  signer,
  relayHandler: relayPool,
  serverPubkey: SERVER_PUBKEY,
  isStateless: true, // Skip initialize roundtrip
});
跳过初始化握手以实现更快的连接:
typescript
const transport = new NostrClientTransport({
  signer,
  relayHandler: relayPool,
  serverPubkey: SERVER_PUBKEY,
  isStateless: true, // 跳过初始化往返请求
});

Proxy Pattern

代理模式

Use
NostrMCPProxy
to connect existing MCP clients to ContextVM servers:
typescript
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,
    relayHandler: relayPool,
    serverPubkey: SERVER_PUBKEY,
  },
});

await proxy.start();
This allows any standard MCP client to use ContextVM servers without native support.
使用
NostrMCPProxy
将现有MCP客户端连接到ContextVM服务器:
typescript
import { NostrMCPProxy } from "@contextvm/sdk";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";

const proxy = new NostrMCPProxy({
  // 供现有客户端连接的本地传输
  mcpHostTransport: new StdioServerTransport(),

  // 远程服务器连接
  nostrTransportOptions: {
    signer,
    relayHandler: relayPool,
    serverPubkey: SERVER_PUBKEY,
  },
});

await proxy.start();
这允许任何标准MCP客户端无需原生支持即可使用ContextVM服务器。

Encryption

加密

Control encryption behavior:
typescript
// Require encrypted connections only
encryptionMode: EncryptionMode.REQUIRED;

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

// Never use encryption
encryptionMode: EncryptionMode.DISABLED;
控制加密行为:
typescript
// 仅允许加密连接
encryptionMode: EncryptionMode.REQUIRED;

// 如果服务器支持则使用加密(默认值)
encryptionMode: EncryptionMode.OPTIONAL;

// 从不使用加密
encryptionMode: EncryptionMode.DISABLED;

Client Templates

客户端模板

See
assets/client-template.ts
for a complete boilerplate.
查看
assets/client-template.ts
获取完整的样板代码。

Tooling: ctxcn (generate a typed TypeScript client)

工具:ctxcn(生成类型化TypeScript客户端)

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:
bash
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.
如果你正在构建TypeScript应用,希望远程ContextVM工具像本地函数一样使用,请使用
ctxcn
高级特性:
  • 连接到ContextVM服务器。
  • 读取
    tools/list
    模式。
  • 将TypeScript客户端代码生成到你的仓库中(shadcn风格:你拥有生成的代码)。
根据ContextVM文档/博客参考,基本流程如下:
bash
npx @contextvm/ctxcn init
npx @contextvm/ctxcn add <server-pubkey>
npx @contextvm/ctxcn update
适用于以下场景:
  • 你需要端到端的类型安全。
  • 你希望IDE能自动补全服务器工具。
  • 你希望避免手动编写工具接口。

Reference Materials

参考资料

  • references/nostr-way-without-sdks.md
    - The Nostr primitives behind CVM (raw events, JSON-RPC, manual implementation)
  • references/discovery.md
    - Server discovery patterns
  • references/proxy-pattern.md
    - Using NostrMCPProxy
  • references/stateless-mode.md
    - Stateless connection details
  • references/nostr-way-without-sdks.md
    - CVM背后的Nostr原语(原始事件、JSON-RPC、手动实现)
  • references/discovery.md
    - 服务器发现模式
  • references/proxy-pattern.md
    - 使用NostrMCPProxy
  • references/stateless-mode.md
    - 无状态连接详情