skills/contextvm/cvmi/server-dev

server-dev

SKILL.md

ContextVM Server Development

Build MCP servers that expose capabilities over Nostr using the @contextvm/sdk.

Quick Start

Create a basic ContextVM server:

import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { NostrServerTransport } from '@contextvm/sdk';
import { PrivateKeySigner } from '@contextvm/sdk';
import { ApplesauceRelayPool } from '@contextvm/sdk';

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

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

// Register tools
server.registerTool('echo', { description: 'Echo back the input' }, async ({ message }) => ({
  content: [{ type: 'text', text: `Echo: ${message}` }],
}));

const transport = new NostrServerTransport({
  signer,
  relayHandler: relayPool,
  serverInfo: {
    name: 'My ContextVM Server',
    website: 'https://example.com',
  },
});

await server.connect(transport);
console.log('Server running on Nostr');

NostrServerTransport Options

Option Type Description
signer NostrSigner Required. Signs all Nostr events
relayHandler RelayHandler | string[] Required. Relay connection manager.
serverInfo ServerInfo Optional. Metadata for announcements
isPublicServer boolean Publish server announcements. Default: false
publishRelayList boolean Publish kind:10002 relay-list metadata
relayListUrls string[] Explicit relay URLs to advertise
bootstrapRelayUrls string[] Extra discoverability publication relays
allowedPublicKeys string[] Whitelist client public keys
excludedCapabilities CapabilityExclusion[] Bypass whitelist for specific methods
injectClientPubkey boolean Inject client pubkey into _meta. Default: false
encryptionMode EncryptionMode OPTIONAL, REQUIRED, or DISABLED

Access Control

Public Key Whitelisting

Restrict which clients can connect:

const transport = new NostrServerTransport({
  signer,
  relayHandler: relayPool,
  allowedPublicKeys: ['client1-pubkey-hex', 'client2-pubkey-hex'],
});

Capability Exclusions

Allow specific operations from any client:

const transport = new NostrServerTransport({
  signer,
  relayHandler: relayPool,
  allowedPublicKeys: ['trusted-client'],
  excludedCapabilities: [
    { method: 'tools/list' }, // Anyone can list tools
    { method: 'tools/call', name: 'public_tool' }, // Specific tool is public
  ],
});

Public Server Announcements

Enable discovery by publishing replaceable events:

const transport = new NostrServerTransport({
  signer,
  relayHandler: relayPool,
  isPublicServer: true,
  publishRelayList: true,
  bootstrapRelayUrls: ['wss://relay.damus.io', 'wss://nos.lol'],
  serverInfo: {
    name: 'Weather Service',
    about: 'Get weather data worldwide',
    website: 'https://weather.example.com',
  },
});

Publishes events on kinds 11316-11320 with your server's capabilities. In the TypeScript SDK, publishRelayList is independent from isPublicServer and defaults to enabled, so relay-list metadata is published unless you explicitly opt out.

Relay-list publication strategy

  • CEP-17 is protocol-level and implementation-agnostic; the defaults below describe the TypeScript SDK behavior, not a protocol requirement
  • Use relayHandler for the relays where your server actually operates
  • Use relayListUrls only if you need to override the advertised relay list
  • Use bootstrapRelayUrls when you want broader discoverability publication without advertising those relays as operational endpoints
  • Set publishRelayList: false only if you intentionally want to disable CEP-17 relay-list publication

Client Public Key Injection

Access the client's identity in your tools:

const transport = new NostrServerTransport({
  signer,
  relayHandler: relayPool,
  injectClientPubkey: true,
});

// In your tool handler, access _meta.clientPubkey
server.registerTool("personalized", {...}, async (args, extra) => {
  const clientPubkey = extra._meta?.clientPubkey;
  // Use pubkey for personalization, rate limiting, etc.
});

Server Templates

See assets/server-template.ts for a complete starting point.

Debugging (MCP Inspector)

Use the MCP Inspector to validate your MCP server behavior (tools/resources/prompts schemas, request/response shape) before exposing it via ContextVM.

From the MCP docs, the Inspector is typically run via npx:

npx @modelcontextprotocol/inspector <command>

Practical workflow for ContextVM:

  1. Implement and test your server logic using a standard MCP transport (commonly STDIO) so it can be inspected.
  2. Use the Inspector to iterate on tool schemas and error handling.
  3. Once stable, swap the transport to NostrServerTransport.

If you need details on Inspector usage and common debugging steps, read:

Reference Materials

Weekly Installs
24
Repository
contextvm/cvmi
GitHub Stars
1
First Seen
Feb 12, 2026
Installed on
opencode20
gemini-cli20
github-copilot20
codex20
cursor20
amp19