server-dev

Build MCP servers that expose capabilities over the Nostr network using ContextVM. Use when creating new servers, converting existing MCP servers to ContextVM, configuring server transports, implementing access control, or setting up public server announcements.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "server-dev" with this command: npx skills add contextvm/cvmi/contextvm-cvmi-server-dev

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

OptionTypeDescription
signerNostrSignerRequired. Signs all Nostr events
relayHandlerRelayHandler | string[]Required. Relay connection manager.
serverInfoServerInfoOptional. Metadata for announcements
isPublicServerbooleanPublish server announcements. Default: false
publishRelayListbooleanPublish kind:10002 relay-list metadata
relayListUrlsstring[]Explicit relay URLs to advertise
bootstrapRelayUrlsstring[]Extra discoverability publication relays
allowedPublicKeysstring[]Whitelist client public keys
excludedCapabilitiesCapabilityExclusion[]Bypass whitelist for specific methods
injectClientPubkeybooleanInject client pubkey into _meta. Default: false
encryptionModeEncryptionModeOPTIONAL, 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

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Coding

typescript-sdk

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

client-dev

No summary provided by upstream source.

Repository SourceNeeds Review
General

concepts

No summary provided by upstream source.

Repository SourceNeeds Review
General

overview

No summary provided by upstream source.

Repository SourceNeeds Review