Getting started
--- title: Getting started description: Quickstart for enabling CEP-8 payments on a ContextVM server and client --- # Getting started This page shows the smallest end-to-end setup: - a server that charges for a single tool - a client that can pay via Lightning BOLT11 over NWC If you haven’t set up Nostr transports yet, start with the transport docs first. ## 1) Server: mark capabilities as priced Define what is paid using `pricedCapabilities`. ```ts import type { PricedCapability } from '@contextvm/sdk/payments'; export const pricedCapabilities: PricedCapability[] = [ { method: 'tools/call', name: 'my-tool', amount: 10, currencyUnit: 'sats', description: 'Example paid tool', }, ]; ``` ## 2) Server: attach payments middleware Create a processor, then wrap your server transport. ```ts import { LnBolt11NwcPaymentProcessor, withServerPayments } from '@contextvm/sdk/payments'; import { NostrServerTransport } from '@contextvm/sdk/transport'; const baseTransport = new NostrServerTransport({ signer, relayHandler, }); const processor = new LnBolt11NwcPaymentProcessor({ nwcConnectionString: process.env.NWC_SERVER_CONNECTION!, }); const paidTransport = withServerPayments(baseTransport, { processors: [processor], pricedCapabilities, }); ``` Server behavior for priced requests: 1. emits `notifications/payment_required` (correlated to the request) 2. waits for settlement verification 3. emits `notifications/payment_accepted` 4. forwards the request to the underlying MCP server ## 3) Client: attach payments middleware Create a handler and wrap your client transport. ```ts import { LnBolt11NwcPaymentHandler, withClientPayments } from '@contextvm/sdk/payments'; import { NostrClientTransport } from '@contextvm/sdk/transport'; const baseTransport = new NostrClientTransport({ signer, relayHandler, serverPubkey, }); const handler = new LnBolt11NwcPaymentHandler({ nwcConnectionString: process.env.NWC_CLIENT_CONNECTION!, }); const paidTransport = withClientPayments(baseTransport, { handlers: [handler], }); ``` Now priced calls will automatically pay when required. ## 4) Try a paid call Any request that matches `pricedCapabilities` will trigger the payment flow. ```ts await client.callTool({ name: 'my-tool', arguments: { example: true }, }); ``` ## What to read next - [Server payments](./server) - [Client payments](./client) - [Lightning over NWC](./rails/lightning-nwc)Getting started
Section titled “Getting started”This page shows the smallest end-to-end setup:
- a server that charges for a single tool
- a client that can pay via Lightning BOLT11 over NWC
If you haven’t set up Nostr transports yet, start with the transport docs first.
1) Server: mark capabilities as priced
Section titled “1) Server: mark capabilities as priced”Define what is paid using pricedCapabilities.
import type { PricedCapability } from '@contextvm/sdk/payments';
export const pricedCapabilities: PricedCapability[] = [ { method: 'tools/call', name: 'my-tool', amount: 10, currencyUnit: 'sats', description: 'Example paid tool', },];2) Server: attach payments middleware
Section titled “2) Server: attach payments middleware”Create a processor, then wrap your server transport.
import { LnBolt11NwcPaymentProcessor, withServerPayments } from '@contextvm/sdk/payments';import { NostrServerTransport } from '@contextvm/sdk/transport';
const baseTransport = new NostrServerTransport({ signer, relayHandler,});
const processor = new LnBolt11NwcPaymentProcessor({ nwcConnectionString: process.env.NWC_SERVER_CONNECTION!,});
const paidTransport = withServerPayments(baseTransport, { processors: [processor], pricedCapabilities,});Server behavior for priced requests:
- emits
notifications/payment_required(correlated to the request) - waits for settlement verification
- emits
notifications/payment_accepted - forwards the request to the underlying MCP server
3) Client: attach payments middleware
Section titled “3) Client: attach payments middleware”Create a handler and wrap your client transport.
import { LnBolt11NwcPaymentHandler, withClientPayments } from '@contextvm/sdk/payments';import { NostrClientTransport } from '@contextvm/sdk/transport';
const baseTransport = new NostrClientTransport({ signer, relayHandler, serverPubkey,});
const handler = new LnBolt11NwcPaymentHandler({ nwcConnectionString: process.env.NWC_CLIENT_CONNECTION!,});
const paidTransport = withClientPayments(baseTransport, { handlers: [handler],});Now priced calls will automatically pay when required.
4) Try a paid call
Section titled “4) Try a paid call”Any request that matches pricedCapabilities will trigger the payment flow.
await client.callTool({ name: 'my-tool', arguments: { example: true },});