This project includes two example MCP servers that demonstrate the hypermedia pattern with Nostr events.
A simple counter that publishes both raw data and UI elements.
COUNTER_SERVER_KEY=<your-hex-private-key> bun run mcp-counter- Counter Data naddr: The raw counter value (kind 30078)
- Counter UI naddr: The rendered counter display (kind 32616)
Update examples/counter.md with the naddr values from the console output.
A full chess game with board rendering and move processing.
CHESS_SERVER_KEY=<your-hex-private-key> bun run mcp-chess- Chess FEN naddr: The game state in FEN notation (kind 30078)
- Chess Board UI naddr: The rendered chess board (kind 32616)
- Server Public Key: Needed for the client to send moves
Update examples/chess.md with:
- Replace
REPLACE_WITH_CHESS_SERVER_PUBKEYwith the server's public key - Replace
REPLACE_WITH_CHESS_BOARD_NADDRwith the Chess Board UI naddr
Both servers follow the same hypermedia pattern:
- State Management: Server maintains all state (counter value, chess board)
- Dual Publishing: Each state change publishes both:
- Raw data event (kind 30078) for programmatic access
- UI element (kind 32616) as a complete Hypernote component
- MCP Tools: Expose functions that modify state and publish updates
- Live Updates: Clients subscribe to the events and update automatically
- No Callbacks: Direct actions without complex query chains
- Server Authority: All logic lives on the server
- UI Control: Server defines exactly how data is displayed
- Live by Default: Changes propagate immediately via Nostr subscriptions
- Clean Clients: Minimal client code, just display and input
To generate a new private key for testing:
import { generateSecretKey, nip19 } from 'nostr-tools'
const sk = generateSecretKey()
console.log(Buffer.from(sk).toString('hex'))Or use any Nostr client to generate a new key pair.