### NostrMCPGateway Usage Example Source: https://github.com/contextvm/contextvm-docs/blob/master/src/content/docs/gateway/overview.md Demonstrates how to create and start a NostrMCPGateway. This example configures a signer, relay pool, and an MCP server transport, then initializes and starts the gateway. ```typescript import { StdioClientTransport } from "@modelcontextprotocol/sdk/stdio"; import { NostrMCPGateway } from "@contextvm/sdk"; import { PrivateKeySigner } from "@contextvm/sdk"; import { SimpleRelayPool } from "@contextvm/sdk"; // 1. Configure the signer and relay handler for the Nostr transport const signer = new PrivateKeySigner("your-gateway-private-key"); const relayPool = new SimpleRelayPool(["wss://relay.damus.io"]); // 2. Configure the transport to connect to your existing MCP server const serverTransport = new StdioClientTransport({ command: "bun", args: ["run", "path/to/your/mcp-server.ts"], }); // 3. Create the gateway instance const gateway = new NostrMCPGateway({ mcpServerTransport: serverTransport, nostrTransportOptions: { signer, relayHandler: relayPool, isPublicServer: true, // Announce this gateway on Nostr }, }); // 4. Start the gateway await gateway.start(); console.log("Gateway is running, exposing the MCP server to Nostr."); // To stop the gateway: await gateway.stop(); ``` -------------------------------- ### Install @contextvm/sdk Source: https://github.com/contextvm/contextvm-docs/blob/master/public/llms.txt Provides the command to install the @contextvm/sdk package using NPM. This is the first step to integrating the SDK into your project. ```bash npm install @contextvm/sdk ``` -------------------------------- ### NostrMCPProxy Usage Example Source: https://github.com/contextvm/contextvm-docs/blob/master/src/content/docs/proxy/overview.md Demonstrates the creation and startup of a NostrMCPProxy. It configures a signer, relay pool, and remote server public key for the Nostr connection, and a StdioServerTransport for the local client. The proxy then starts listening for connections. ```javascript import { StdioServerTransport } from "@modelcontextprotocol/sdk/stdio"; import { NostrMCPProxy } from "@contextvm/sdk"; import { PrivateKeySigner } from "@contextvm/sdk"; import { SimpleRelayPool } from "@contextvm/sdk"; // 1. Configure the signer and relay handler for the Nostr connection const signer = new PrivateKeySigner("your-private-key"); const relayPool = new SimpleRelayPool(["wss://relay.damus.io"]); const REMOTE_SERVER_PUBKEY = "remote-server-public-key"; // 2. Configure the transport for the local client // In this case, a stdio transport that the local client can connect to const hostTransport = new StdioServerTransport(); // 3. Create the proxy instance const proxy = new NostrMCPProxy({ mcpHostTransport: hostTransport, nostrTransportOptions: { signer, relayHandler: relayPool, serverPubkey: REMOTE_SERVER_PUBKEY, }, }); // 4. Start the proxy await proxy.start(); console.log("Proxy is running. Connect your local MCP client."); // To stop the proxy: await proxy.stop(); ``` -------------------------------- ### Install ContextVM SDK Source: https://github.com/contextvm/contextvm-docs/blob/master/src/content/docs/getting-started/quick-overview.md Installs the @contextvm/sdk package using npm. This command is essential for integrating the SDK into your project. It also mentions that users of other package managers should use their respective commands. ```bash npm install @contextvm/sdk ``` -------------------------------- ### NostrServerTransport Example Source: https://github.com/contextvm/contextvm-docs/blob/master/public/llms.txt Example of setting up a NostrServerTransport to expose an MCP server's capabilities through the Nostr network. ```typescript import { NostrServerTransport } from '@contextvm/sdk'; async function exposeContextVMServer(relayUrl: string, privateKey: string, mcpServerUrl: string) { const transport = new NostrServerTransport(relayUrl, privateKey, mcpServerUrl); await transport.start(); console.log('ContextVM server exposed on Nostr'); // The transport will now listen for Nostr events and forward MCP requests return transport; } ``` -------------------------------- ### RelayHandler Interface Example Source: https://github.com/contextvm/contextvm-docs/blob/master/src/content/docs/getting-started/quick-overview.md Demonstrates the RelayHandler interface, focusing on the default SimpleRelayPool implementation and the flexibility to create custom logic for relay management, selection, and connection. ```javascript interface RelayHandler { publish(event: NostrEvent): Promise; subscribe(filters: NostrFilter[]): AsyncIterable; connect(relayUrl: string): Promise; close(relayUrl: string): Promise; } // Example of a default implementation class SimpleRelayPool implements RelayHandler { // ... implementation details ... } ``` -------------------------------- ### Pricing Tag Format and Examples Source: https://github.com/contextvm/contextvm-docs/blob/master/public/llms.txt Details the 'cap' tag format used for conveying pricing information for capabilities. It shows examples of how this tag is applied in both server announcements and capability list events to specify cost and currency. ```json ["cap", "", "", ""] ``` ```json { "kind": 11317, "content": { "tools": [ { "name": "get_weather", "description": "Get current weather information" // ... other tool properties } ] }, "tags": [["cap", "get_weather", "100", "sats"]] } ``` ```json { "kind": 25910, "pubkey": "", "content": { "result": { "tools": [ { "name": "get_weather", "description": "Get current weather information" // ... other tool properties } ], "nextCursor": "next-page-cursor" } }, "tags": [ ["e", ""], // Required: Reference to the request event ["cap", "get_weather", "100", "sats"] // Optional: Pricing metadata ] } ``` -------------------------------- ### SimpleRelayPool Usage Example Source: https://github.com/contextvm/contextvm-docs/blob/master/public/llms.txt Demonstrates how to instantiate and use the SimpleRelayPool with a list of Nostr relay URLs and integrate it with NostrClientTransport. ```typescript import { SimpleRelayPool } from "@contextvm/sdk"; import { NostrClientTransport } from "@contextvm/sdk"; // 1. Define the list of relays you want to connect to const myRelays = [ "wss://relay.damus.io", "wss://relay.primal.net", "wss://nos.lol", ]; // 2. Create an instance of the SimpleRelayPool const relayPool = new SimpleRelayPool(myRelays); // 3. Pass the instance to a transport const transport = new NostrClientTransport({ relayHandler: relayPool, // ... other options }); ``` -------------------------------- ### PrivateKeySigner Usage Example Source: https://github.com/contextvm/contextvm-docs/blob/master/public/llms.txt Demonstrates how to instantiate and use the PrivateKeySigner with a provided private key for SDK operations. ```typescript import { PrivateKeySigner } from "@contextvm/sdk"; // Replace with a securely stored private key const privateKeyHex = "your-32-byte-private-key-in-hex"; const signer = new PrivateKeySigner(privateKeyHex); // You can now pass this signer instance to a transport const transportOptions = { signer: signer, // ... other options }; ``` -------------------------------- ### NostrSigner Interface Example Source: https://github.com/contextvm/contextvm-docs/blob/master/src/content/docs/getting-started/quick-overview.md Illustrates the concept of a NostrSigner interface, highlighting the default PrivateKeySigner and the possibility of custom implementations for different signing mechanisms like Window.nostr or remote signers. ```javascript interface NostrSigner { signEvent(event: NostrEvent): Promise; getPublicKey(): Promise; } // Example of a default implementation class PrivateKeySigner implements NostrSigner { // ... implementation details ... } // Example of a custom implementation for web environments class WindowNostrSigner implements NostrSigner { // ... implementation details ... } ``` -------------------------------- ### Tool List Event with Pricing Example Source: https://github.com/contextvm/contextvm-docs/blob/master/src/content/docs/ctxvm-draft-spec.md Demonstrates how pricing information is attached to a tool list event using the 'cap' tag. This example shows a tool with a price of 100 satoshis. ```json { "kind": 11317, "content": { "tools": [ { "name": "get_weather", "description": "Get current weather information" // ... other tool properties } ] }, "tags": [["cap", "get_weather", "100", "sats"]] } ``` -------------------------------- ### NostrClientTransport Example Source: https://github.com/contextvm/contextvm-docs/blob/master/public/llms.txt Example of how to use the NostrClientTransport from the @contextvm/sdk to establish communication with a ContextVM server over Nostr. ```typescript import { NostrClientTransport } from '@contextvm/sdk'; async function connectToContextVM(relayUrl: string, privateKey: string) { const transport = new NostrClientTransport(relayUrl, privateKey); await transport.connect(); console.log('Connected to ContextVM server via Nostr'); // Now you can use the transport to send MCP messages return transport; } ``` -------------------------------- ### Capability List Event with Pricing Example Source: https://github.com/contextvm/contextvm-docs/blob/master/src/content/docs/ctxvm-draft-spec.md Shows an example of a capability list event that includes pricing metadata via the 'cap' tag within the event's tags array. ```json { "kind": 25910, "pubkey": "", "content": { "result": { "tools": [ { "name": "get_weather", "description": "Get current weather information" // ... other tool properties } ], "nextCursor": "next-page-cursor" } }, "tags": [ ["e", ""], // Required: Reference to the request event ["cap", "get_weather", "100", "sats"] // Optional: Pricing metadata ] } ``` -------------------------------- ### Custom LoggingRelayHandler Example Source: https://github.com/contextvm/contextvm-docs/blob/master/public/llms.txt An example of a custom RelayHandler that wraps SimpleRelayPool to add logging for connection, subscription, and publishing operations. ```typescript import { RelayHandler } from "@contextvm/sdk"; import { SimpleRelayPool } from "@contextvm/sdk"; import { Filter, NostrEvent } from "nostr-tools"; class LoggingRelayHandler implements RelayHandler { private readonly innerHandler: RelayHandler; constructor(relayUrls: string[]) { this.innerHandler = new SimpleRelayPool(relayUrls); console.log( `[LoggingRelayHandler] Initialized with relays: ${relayUrls.join(", ")}`, ); } async connect(): Promise { console.log("[LoggingRelayHandler] Attempting to connect..."); await this.innerHandler.connect(); console.log("[LoggingRelayHandler] Connected successfully."); } async disconnect(): Promise { console.log("[LoggingRelayHandler] Disconnecting..."); await this.innerHandler.disconnect(); console.log("[LoggingRelayHandler] Disconnected."); } publish(event: NostrEvent): void { console.log(`[LoggingRelayHandler] Publishing event kind ${event.kind}...`); this.innerHandler.publish(event); } subscribe(filters: Filter[], onEvent: (event: NostrEvent) => void): void { console.log(`[LoggingRelayHandler] Subscribing with filters:`, filters); this.innerHandler.subscribe(filters, (event) => { console.log(`[LoggingRelayHandler] Received event kind ${event.kind}`); onEvent(event); }); } unsubscribe(): void { console.log("[LoggingRelayHandler] Unsubscribing from all."); this.innerHandler.unsubscribe(); } } // Usage const loggingHandler = new LoggingRelayHandler(["wss://relay.damus.io"]); const transport = new NostrClientTransport({ relayHandler: loggingHandler, // ... other options }); ``` -------------------------------- ### Usage Example: Setting up NostrServerTransport Source: https://github.com/contextvm/contextvm-docs/blob/master/src/content/docs/transports/nostr-server-transport.md Demonstrates how to initialize and connect an McpServer using the NostrServerTransport, including configuring a signer, relay pool, and server options. ```typescript import { McpServer } from "@modelcontextprotocol/sdk"; import { NostrServerTransport } from "@contextvm/sdk"; import { PrivateKeySigner } from "@contextvm/sdk"; import { SimpleRelayPool } from "@contextvm/sdk"; // 1. Configure the signer and relay pool const signer = new PrivateKeySigner("your-server-private-key"); const relayPool = new SimpleRelayPool(["wss://relay.damus.io"]); // 2. Create the McpServer instance const mcpServer = new McpServer({ name: "demo-server", version: "1.0.0", }); // Register your server's tools, resources, etc. // mcpServer.tool(...); // 3. Create the NostrServerTransport instance const serverNostrTransport = new NostrServerTransport({ signer: signer, relayHandler: relayPool, isPublicServer: true, // Announce the server publicly serverInfo: { name: "My Awesome MCP Server", website: "https://example.com", }, }); // 4. Connect the server await mcpServer.connect(serverNostrTransport); console.log("MCP server is running and available on Nostr."); // Keep the process running... // To shut down: await mcpServer.close(); ``` -------------------------------- ### Nostr MCP Server Setup Source: https://github.com/contextvm/contextvm-docs/blob/master/src/content/docs/tutorials/client-server-communication.md Sets up an MCP server using Nostr transport, registering an 'echo' tool. It requires Nostr private keys and relay configurations. The server listens for incoming requests on the Nostr network. ```typescript import { McpServer, Tool } from "@modelcontextprotocol/sdk/server"; import { NostrServerTransport } from "@contextvm/sdk"; import { PrivateKeySigner } from "@contextvm/sdk"; import { SimpleRelayPool } from "@contextvm/sdk"; import { generateSecretKey, getPublicKey } from "nostr-tools/pure"; // --- Configuration --- // IMPORTANT: Replace with your own private key const SERVER_PRIVATE_KEY_HEX = process.env.SERVER_PRIVATE_KEY || "your-32-byte-server-private-key-in-hex"; const RELAYS = ["wss://relay.damus.io", "wss://nos.lol"]; // --- Main Server Logic --- async function main() { // 1. Setup Signer and Relay Pool const signer = new PrivateKeySigner(SERVER_PRIVATE_KEY_HEX); const relayPool = new SimpleRelayPool(RELAYS); const serverPubkey = await signer.getPublicKey(); console.log(`Server Public Key: ${serverPubkey}`); console.log("Connecting to relays..."); // 2. Create and Configure the MCP Server const mcpServer = new McpServer({ name: "nostr-echo-server", version: "1.0.0", }); // 3. Define a simple "echo" tool server.registerTool( "echo", { title: "Echo Tool", description: "Echoes back the provided message", inputSchema: { message: z.string() }, }, async ({ message }) => ({ content: [{ type: "text", text: `Tool echo: ${message}` }], }), ); // 4. Configure the Nostr Server Transport const serverTransport = new NostrServerTransport({ signer, relayHandler: relayPool, isPublicServer: true, // Announce this server on the Nostr network serverInfo: { name: "CTXVM Echo Server", }, }); // 5. Connect the server await mcpServer.connect(serverTransport); console.log("Server is running and listening for requests on Nostr..."); console.log("Press Ctrl+C to exit."); } main().catch((error) => { console.error("Failed to start server:", error); process.exit(1); }); ``` -------------------------------- ### ContextVM Capability Pricing Source: https://github.com/contextvm/contextvm-docs/blob/master/src/content/docs/ctxvm-draft-spec.md Details the pricing tag format for capabilities, including examples and payment handling considerations within the ContextVM protocol. ```APIDOC Pricing Tag Format: - ["price", "", "", ""] - Example: ["price", "0.01", "sats", "call"] Payment Handling: - Clients are expected to send payment events or tokens as specified by the server's pricing. - Servers validate payment before executing the capability. - Specific payment mechanisms (e.g., LNURL, specific tokens) are server-dependent. ``` -------------------------------- ### Payment Required Notification Example Source: https://github.com/contextvm/contextvm-docs/blob/master/public/llms.txt An example of a server-to-client notification (kind 25910) indicating that a payment is required. It includes payment details such as amount, currency, invoice, and a description. ```json { "kind": 25910, "pubkey": "", "content": { "method": "notifications/payment_required", "params": { "amount": 1000, "currency": "sats", "invoice": "lnbc...", "description": "Payment for tool execution" } }, "tags": [ ["p", ""], ["e", ""] ] } ``` -------------------------------- ### SimpleRelayPool Usage Example Source: https://github.com/contextvm/contextvm-docs/blob/master/src/content/docs/relay/simple-relay-pool.md Demonstrates how to instantiate and use the SimpleRelayPool with a NostrClientTransport. It involves defining relay URLs, creating the pool, and passing it to the transport. ```typescript import { SimpleRelayPool } from "@contextvm/sdk"; import { NostrClientTransport } from "@contextvm/sdk"; // 1. Define the list of relays you want to connect to const myRelays = [ "wss://relay.damus.io", "wss://relay.primal.net", "wss://nos.lol", ]; // 2. Create an instance of the SimpleRelayPool const relayPool = new SimpleRelayPool(myRelays); // 3. Pass the instance to a transport const transport = new NostrClientTransport({ relayHandler: relayPool, // ... other options }); ``` -------------------------------- ### Nostr MCP Server Setup Source: https://github.com/contextvm/contextvm-docs/blob/master/public/llms.txt Sets up an MCP server using Nostr transport. It configures a signer, relay pool, registers an 'echo' tool, and connects to the Nostr network to listen for requests. Requires a private key for the server. ```typescript import { McpServer, Tool } from "@modelcontextprotocol/sdk/server"; import { NostrServerTransport } from "@contextvm/sdk"; import { PrivateKeySigner } from "@contextvm/sdk"; import { SimpleRelayPool } from "@contextvm/sdk"; import { generateSecretKey, getPublicKey } from "nostr-tools/pure"; // --- Configuration --- // IMPORTANT: Replace with your own private key const SERVER_PRIVATE_KEY_HEX = process.env.SERVER_PRIVATE_KEY || "your-32-byte-server-private-key-in-hex"; const RELAYS = ["wss://relay.damus.io", "wss://nos.lol"]; // --- Main Server Logic --- async function main() { // 1. Setup Signer and Relay Pool const signer = new PrivateKeySigner(SERVER_PRIVATE_KEY_HEX); const relayPool = new SimpleRelayPool(RELAYS); const serverPubkey = await signer.getPublicKey(); console.log(`Server Public Key: ${serverPubkey}`); console.log("Connecting to relays..."); // 2. Create and Configure the MCP Server const mcpServer = new McpServer({ name: "nostr-echo-server", version: "1.0.0", }); // 3. Define a simple "echo" tool server.registerTool( "echo", { title: "Echo Tool", description: "Echoes back the provided message", inputSchema: { message: z.string() }, }, async ({ message }) => ({ content: [{ type: "text", text: `Tool echo: ${message}` }], }), ); // 4. Configure the Nostr Server Transport const serverTransport = new NostrServerTransport({ signer, relayHandler: relayPool, isPublicServer: true, // Announce this server on the Nostr network serverInfo: { name: "CTXVM Echo Server", }, }); // 5. Connect the server await mcpServer.connect(serverTransport); console.log("Server is running and listening for requests on Nostr..."); console.log("Press Ctrl+C to exit."); } main().catch((error) => { console.error("Failed to start server:", error); process.exit(1); }); ``` -------------------------------- ### Nostr Client Transport Usage Example Source: https://github.com/contextvm/contextvm-docs/blob/master/src/content/docs/transports/nostr-client-transport.md Demonstrates how to initialize and use the NostrClientTransport with an MCP client, including configuring the signer, relay pool, and connecting to a server. ```javascript import { Client } from "@modelcontextprotocol/sdk/client"; import { NostrClientTransport } from "@contextvm/sdk"; import { EncryptionMode } from "@contextvm/sdk"; import { PrivateKeySigner } from "@contextvm/sdk"; import { SimpleRelayPool } from "@contextvm/sdk"; // 1. Configure the signer and relay handler const signer = new PrivateKeySigner("your-private-key"); // Replace with your actual private key const relayPool = new SimpleRelayPool(["wss://relay.damus.io"]); // 2. Set the public key of the target server const REMOTE_SERVER_PUBKEY = "remote-server-public-key"; // 3. Create the transport instance const clientNostrTransport = new NostrClientTransport({ signer, relayHandler: relayPool, serverPubkey: REMOTE_SERVER_PUBKEY, encryptionMode: EncryptionMode.OPTIONAL, }); // 4. Create and connect the MCP client const mcpClient = new Client(); await mcpClient.connect(clientNostrTransport); // 5. Use the client to interact with the server const tools = await mcpClient.listTools(); console.log("Available tools:", tools); // 6. Close the connection when done // await mcpClient.close(); ``` -------------------------------- ### Nostr MCP Client Setup Source: https://github.com/contextvm/contextvm-docs/blob/master/public/llms.txt Sets up an MCP client to connect to a Nostr-based server. It configures a signer, relay pool, specifies the server's public key, and connects to the server to list tools and call the 'echo' tool. ```typescript import { Client } from "@modelcontextprotocol/sdk/client"; import { NostrClientTransport } from "@contextvm/sdk"; import { PrivateKeySigner } from "@contextvm/sdk"; import { SimpleRelayPool } from "@contextvm/sdk"; // --- Configuration --- // IMPORTANT: Replace with the server's public key from the server output const SERVER_PUBKEY = "the-public-key-printed-by-server.ts"; // IMPORTANT: Replace with your own private key const CLIENT_PRIVATE_KEY_HEX = process.env.CLIENT_PRIVATE_KEY || "your-32-byte-client-private-key-in-hex"; const RELAYS = ["wss://relay.damus.io", "wss://nos.lol"]; // --- Main Client Logic --- async function main() { // 1. Setup Signer and Relay Pool const signer = new PrivateKeySigner(CLIENT_PRIVATE_KEY_HEX); const relayPool = new SimpleRelayPool(RELAYS); console.log("Connecting to relays..."); // 2. Configure the Nostr Client Transport const clientTransport = new NostrClientTransport({ signer, relayHandler: relayPool, serverPubkey: SERVER_PUBKEY, }); // 3. Create and connect the MCP Client const mcpClient = new Client(); await mcpClient.connect(clientTransport); console.log("Connected to server!"); // 4. List the available tools console.log("\nListing available tools..."); const tools = await mcpClient.listTools(); console.log("Tools:", tools); // 5. Call the "echo" tool console.log('\nCalling the "echo" tool...'); const echoResult = await mcpClient.callTool({ name: "echo", arguments: { message: "Hello, Nostr!" }, }); console.log("Echo result:", echoResult); // 6. Close the connection await mcpClient.close(); console.log("\nConnection closed."); } main().catch((error) => { console.error("Client failed:", error); process.exit(1); }); ``` -------------------------------- ### Payment Required Notification Example Source: https://github.com/contextvm/contextvm-docs/blob/master/src/content/docs/ctxvm-draft-spec.md An example of a ContextVM notification event (kind 25910) indicating that a payment is required. It includes details like amount, currency, invoice, and a reference to the original request event. ```JSON { "kind": 25910, "pubkey": "", "content": { "method": "notifications/payment_required", "params": { "amount": 1000, "currency": "sats", "invoice": "lnbc...", "description": "Payment for tool execution" } }, "tags": [ ["p", ""], ["e", ""] ] } ``` -------------------------------- ### NostrMCPGateway Configuration and Usage Source: https://github.com/contextvm/contextvm-docs/blob/master/public/llms.txt Demonstrates how to configure and instantiate a NostrMCPGateway to expose an existing MCP server to the Nostr network. It covers setting up the signer, relay handler, MCP server transport, and starting the gateway. This is useful for decoupling services and adding Nostr capabilities to existing MCP servers. ```typescript import { StdioClientTransport } from "@modelcontextprotocol/sdk/stdio"; import { NostrMCPGateway } from "@contextvm/sdk"; import { PrivateKeySigner } from "@contextvm/sdk"; import { SimpleRelayPool } from "@contextvm/sdk"; // 1. Configure the signer and relay handler for the Nostr transport const signer = new PrivateKeySigner("your-gateway-private-key"); const relayPool = new SimpleRelayPool(["wss://relay.damus.io"]); // 2. Configure the transport to connect to your existing MCP server const serverTransport = new StdioClientTransport({ command: "bun", args: ["run", "path/to/your/mcp-server.ts"], }); // 3. Create the gateway instance const gateway = new NostrMCPGateway({ mcpServerTransport: serverTransport, nostrTransportOptions: { signer, relayHandler: relayPool, isPublicServer: true, // Announce this gateway on Nostr }, }); // 4. Start the gateway await gateway.start(); console.log("Gateway is running, exposing the MCP server to Nostr."); // To stop the gateway: await gateway.stop(); ``` -------------------------------- ### Call Tool Response Example Source: https://github.com/contextvm/contextvm-docs/blob/master/src/content/docs/ctxvm-draft-spec.md Shows the JSON structure for a response after a tool has been called. It contains the result of the tool execution, including text content and an error flag. ```json { "kind": 25910, "pubkey": "", "content": { "jsonrpc": "2.0", "id": 2, "result": { "content": [ { "type": "text", "text": "Current weather in New York:\nTemperature: 72°F\nConditions: Partly cloudy" } ], "isError": false } }, "tags": [["e", ""]] } ``` -------------------------------- ### Call Tool Request Example Source: https://github.com/contextvm/contextvm-docs/blob/master/src/content/docs/ctxvm-draft-spec.md Illustrates the JSON structure for a request to call a specific tool within ContextVM. It includes the JSON-RPC method 'tools/call' and parameters for the tool's name and arguments. ```json { "kind": 25910, "id": "", "pubkey": "", "content": { "jsonrpc": "2.0", "id": 2, "method": "tools/call", "params": { "name": "get_weather", "arguments": { "location": "New York" } } }, "tags": [["p", ""]] } ``` -------------------------------- ### Nostr MCP Proxy Example Source: https://github.com/contextvm/contextvm-docs/blob/master/public/llms.txt Demonstrates how to create a Nostr MCP Proxy that listens for a local client over standard I/O and connects to a remote server over Nostr. It includes configuration for signer, relay pool, and transport. ```typescript import { StdioServerTransport } from "@modelcontextprotocol/sdk/stdio"; import { NostrMCPProxy } from "@contextvm/sdk"; import { PrivateKeySigner } from "@contextvm/sdk"; import { SimpleRelayPool } from "@contextvm/sdk"; // 1. Configure the signer and relay handler for the Nostr connection const signer = new PrivateKeySigner("your-private-key"); const relayPool = new SimpleRelayPool(["wss://relay.damus.io"]); const REMOTE_SERVER_PUBKEY = "remote-server-public-key"; // 2. Configure the transport for the local client // In this case, a stdio transport that the local client can connect to const hostTransport = new StdioServerTransport(); // 3. Create the proxy instance const proxy = new NostrMCPProxy({ mcpHostTransport: hostTransport, nostrTransportOptions: { signer, relayHandler: relayPool, serverPubkey: REMOTE_SERVER_PUBKEY, }, }); // 4. Start the proxy await proxy.start(); console.log("Proxy is running. Connect your local MCP client."); // To stop the proxy: await proxy.stop(); ``` -------------------------------- ### NostrSigner Interface Definition Source: https://github.com/contextvm/contextvm-docs/blob/master/src/content/docs/signer/nostr-signer-interface.md Defines the core methods for signing Nostr events, including getting the public key and signing event templates. It also includes optional support for NIP-04 (deprecated) and NIP-44 encryption. ```typescript export interface NostrSigner { getPublicKey(): Promise; signEvent(event: EventTemplate): Promise; // Optional NIP-04 encryption support (deprecated) nip04?: { encrypt: (pubkey: string, plaintext: string) => Promise; decrypt: (pubkey: string, ciphertext: string) => Promise; }; // Optional NIP-44 encryption support nip44?: { encrypt: (pubkey: string, plaintext: string) => Promise; decrypt: (pubkey: string, ciphertext: string) => Promise; }; } ``` -------------------------------- ### NostrSigner Interface Definition Source: https://github.com/contextvm/contextvm-docs/blob/master/src/content/docs/core/interfaces.md Defines the core interface for cryptographic operations in the SDK, abstracting Nostr event signing. It includes methods for getting public keys and signing events, with optional support for NIP-04 and NIP-44 encryption. ```typescript export interface NostrSigner { getPublicKey(): Promise; signEvent(event: EventTemplate): Promise; // Optional NIP-04 encryption support (deprecated) nip04?: { encrypt: (pubkey: string, plaintext: string) => Promise; decrypt: (pubkey: string, ciphertext: string) => Promise; }; // Optional NIP-44 encryption support nip44?: { encrypt: (pubkey: string, plaintext: string) => Promise; decrypt: (pubkey: string, ciphertext: string) => Promise; }; } ``` -------------------------------- ### NostrMCPGateway Overview Source: https://github.com/contextvm/contextvm-docs/blob/master/src/content/docs/getting-started/quick-overview.md Explains the NostrMCPGateway, a server-side bridge that exposes an existing MCP server to the Nostr network. This allows Nostr-native clients to discover and utilize the server's capabilities, simplifying integration. ```javascript import { NostrMCPGateway } from '@contextvm/gateway'; async function exposeExistingServer(relayUrl: string, serverId: string, mcpServerInstance: any) { const gateway = new NostrMCPGateway(relayUrl, serverId, mcpServerInstance); await gateway.start(); // The MCP server is now accessible via Nostr } ``` -------------------------------- ### NostrMCPProxy Overview Source: https://github.com/contextvm/contextvm-docs/blob/master/src/content/docs/getting-started/quick-overview.md Describes the NostrMCPProxy, a client-side bridge that enables MCP clients to communicate with remote MCP servers over Nostr without requiring native Nostr support in the client. It abstracts underlying transport complexities. ```javascript import { NostrMCPProxy } from '@contextvm/proxy'; async function useRemoteService(relayUrl: string, serverId: string) { const proxy = new NostrMCPProxy(relayUrl, serverId); await proxy.connect(); // Now you can interact with the remote service as if it were local // const result = await proxy.call('remoteMethod', [arg1, arg2]); } ``` -------------------------------- ### Running the MCP Client Source: https://github.com/contextvm/contextvm-docs/blob/master/src/content/docs/tutorials/client-server-communication.md Command to execute the client script using Bun. Ensure the server is running and client configuration is updated. ```bash bun run client.ts ``` -------------------------------- ### Client Initialization Request Source: https://github.com/contextvm/contextvm-docs/blob/master/public/llms.txt The initial request sent by a client to a server to establish a connection and negotiate capabilities. It includes protocol version and client capabilities. ```json { "kind": 25910, "content": { "jsonrpc": "2.0", "id": 0, "method": "initialize", "params": { "protocolVersion": "2025-07-02", "capabilities": { "roots": { "listChanged": true }, "sampling": {} }, "clientInfo": { "name": "ExampleClient", "version": "1.0.0" } } }, "tags": [["p", ""]] } ``` -------------------------------- ### NostrMCPProxy Configuration Parameters Source: https://github.com/contextvm/contextvm-docs/blob/master/public/llms.txt Details the parameters for the NostrMCPProxyOptions interface, explaining the purpose of each configuration setting. ```APIDOC NostrMCPProxyOptions: mcpHostTransport: Transport - An instance of a server-side MCP transport that the local client will connect to. Example: new StdioServerTransport(). nostrTransportOptions: NostrTransportOptions - The full configuration object required by the NostrClientTransport. This includes the signer, relayHandler, and the remote serverPubkey. ``` -------------------------------- ### NostrSigner Interface Definition Source: https://github.com/contextvm/contextvm-docs/blob/master/public/llms.txt Defines the core methods for a Nostr signer, including getting the public key, signing events, and optional NIP-04/NIP-44 encryption. ```typescript export interface NostrSigner { getPublicKey(): Promise; signEvent(event: EventTemplate): Promise; // Optional NIP-04 encryption support (deprecated) nip04?: { encrypt: (pubkey: string, plaintext: string) => Promise; decrypt: (pubkey: string, ciphertext: string) => Promise; }; // Optional NIP-44 encryption support nip44?: { encrypt: (pubkey: string, plaintext: string) => Promise; decrypt: (pubkey: string, ciphertext: string) => Promise; }; } ``` -------------------------------- ### ContextVM Direct Discovery & Initialization Source: https://github.com/contextvm/contextvm-docs/blob/master/src/content/docs/ctxvm-draft-spec.md Defines the sequence of Nostr events for direct (private) server discovery and client initialization, including requests and responses. ```APIDOC Client Initialization Request: kind: 40010 (example) tags: - ["request_id", ""] - ["capabilities", ""] Server Initialization Response: kind: 40011 (example) tags: - ["request_id", ""] - ["status", ""] - ["message", ""] - ["session_key", ""] Client Initialized Notification: kind: 40012 (example) tags: - ["request_id", ""] - ["status", ""] ``` -------------------------------- ### Run Nostr MCP Server Source: https://github.com/contextvm/contextvm-docs/blob/master/src/content/docs/tutorials/client-server-communication.md Command to execute the TypeScript server file using bun. Ensure the private key is set either directly in the code or via the SERVER_PRIVATE_KEY environment variable. ```bash bun run server.ts ``` -------------------------------- ### NostrSigner Interface Source: https://github.com/contextvm/contextvm-docs/blob/master/public/llms.txt Defines the interface for cryptographic operations, including getting the public key and signing Nostr events. It also includes optional support for NIP-04 and NIP-44 encryption. ```typescript export interface NostrSigner { getPublicKey(): Promise; signEvent(event: EventTemplate): Promise; // Optional NIP-04 encryption support (deprecated) nip04?: { encrypt: (pubkey: string, plaintext: string) => Promise; decrypt: (pubkey: string, ciphertext: string) => Promise; }; // Optional NIP-44 encryption support nip44?: { encrypt: (pubkey: string, plaintext: string) => Promise; decrypt: (pubkey: string, ciphertext: string) => Promise; }; } ``` -------------------------------- ### ContextVM SDK Overview Source: https://github.com/contextvm/contextvm-docs/blob/master/src/content/docs/index.md Provides an overview of the @contextvm/sdk components, including Core Module, Transports (NostrClientTransport, NostrServerTransport), Proxy, Gateway, Relay, and Signer. These components facilitate communication and interoperability between Nostr and the Model Context Protocol (MCP). ```javascript import { NostrClientTransport } from '@contextvm/sdk/transports'; import { NostrServerTransport } from '@contextvm/sdk/transports'; import { Proxy } from '@contextvm/sdk/proxy'; import { Gateway } from '@contextvm/sdk/gateway'; import { Relay } from '@contextvm/sdk/relay'; import { Signer } from '@contextvm/sdk/signer'; ``` -------------------------------- ### Tools List Event Source: https://github.com/contextvm/contextvm-docs/blob/master/public/llms.txt Details the tools offered by a server, including their names, descriptions, and input schemas. This allows clients to understand and utilize server functionalities. ```json { "kind": 11317, "pubkey": "", "content": { "tools": [ { "name": "get_weather", "description": "Get current weather information for a location", "inputSchema": { "type": "object", "properties": { "location": { "type": "string", "description": "City name or zip code" } }, "required": ["location"] } } ] }, "tags": [] } ``` -------------------------------- ### Server Discovery via Announcements Source: https://github.com/contextvm/contextvm-docs/blob/master/public/llms.txt Explains how public servers use Nostr replaceable events to announce their presence and capabilities. This method allows clients to discover servers and their associated public keys for connection. ```APIDOC Public server announcements act as a service catalog, allowing clients to discover servers and their capabilities through replaceable events on the Nostr network. Providers announce their servers and capabilities by publishing events with kinds: - 11316 (server) - 11317 (tools/list) - 11318 (resources/list) - 11319 (resource templates/list) - 11320 (prompts/list) Note: The `content` field of ContextVM events contains stringified MCP messages. Examples present `content` as a JSON object for readability; it must be stringified before inclusion in a Nostr event. ``` -------------------------------- ### LoggingRelayHandler Example Source: https://github.com/contextvm/contextvm-docs/blob/master/src/content/docs/relay/custom-relay-handler.md A custom `RelayHandler` implementation in TypeScript that wraps the `SimpleRelayPool` and adds console logging for connection, publishing, and subscription events. It demonstrates the composition pattern for extending relay management logic. ```typescript import { RelayHandler } from "@contextvm/sdk"; import { SimpleRelayPool } from "@contextvm/sdk"; import { Filter, NostrEvent } from "nostr-tools"; class LoggingRelayHandler implements RelayHandler { private readonly innerHandler: RelayHandler; constructor(relayUrls: string[]) { this.innerHandler = new SimpleRelayPool(relayUrls); console.log( `[LoggingRelayHandler] Initialized with relays: ${relayUrls.join(", ")}`, ); } async connect(): Promise { console.log("[LoggingRelayHandler] Attempting to connect..."); await this.innerHandler.connect(); console.log("[LoggingRelayHandler] Connected successfully."); } async disconnect(): Promise { console.log("[LoggingRelayHandler] Disconnecting..."); await this.innerHandler.disconnect(); console.log("[LoggingRelayHandler] Disconnected."); } publish(event: NostrEvent): void { console.log(`[LoggingRelayHandler] Publishing event kind ${event.kind}...`); this.innerHandler.publish(event); } subscribe(filters: Filter[], onEvent: (event: NostrEvent) => void): void { console.log(`[LoggingRelayHandler] Subscribing with filters:`, filters); this.innerHandler.subscribe(filters, (event) => { console.log(`[LoggingRelayHandler] Received event kind ${event.kind}`); onEvent(event); }); } unsubscribe(): void { console.log("[LoggingRelayHandler] Unsubscribing from all."); this.innerHandler.unsubscribe(); } } // Usage const loggingHandler = new LoggingRelayHandler(["wss://relay.damus.io"]); const transport = new NostrClientTransport({ relayHandler: loggingHandler, // ... other options }); ``` -------------------------------- ### MCP Client Implementation Source: https://github.com/contextvm/contextvm-docs/blob/master/src/content/docs/tutorials/client-server-communication.md Sets up a Nostr client transport, connects to an MCP server, lists available tools, calls the 'echo' tool, and closes the connection. Requires server public key and client private key. ```typescript import { Client } from "@modelcontextprotocol/sdk/client"; import { NostrClientTransport } from "@contextvm/sdk"; import { PrivateKeySigner } from "@contextvm/sdk"; import { SimpleRelayPool } from "@contextvm/sdk"; // --- Configuration --- // IMPORTANT: Replace with the server's public key from the server output const SERVER_PUBKEY = "the-public-key-printed-by-server.ts"; // IMPORTANT: Replace with your own private key const CLIENT_PRIVATE_KEY_HEX = process.env.CLIENT_PRIVATE_KEY || "your-32-byte-client-private-key-in-hex"; const RELAYS = ["wss://relay.damus.io", "wss://nos.lol"]; // --- Main Client Logic --- async function main() { // 1. Setup Signer and Relay Pool const signer = new PrivateKeySigner(CLIENT_PRIVATE_KEY_HEX); const relayPool = new SimpleRelayPool(RELAYS); console.log("Connecting to relays..."); // 2. Configure the Nostr Client Transport const clientTransport = new NostrClientTransport({ signer, relayHandler: relayPool, serverPubkey: SERVER_PUBKEY, }); // 3. Create and connect the MCP Client const mcpClient = new Client(); await mcpClient.connect(clientTransport); console.log("Connected to server!"); // 4. List the available tools console.log("\nListing available tools..."); const tools = await mcpClient.listTools(); console.log("Tools:", tools); // 5. Call the "echo" tool console.log('\nCalling the "echo" tool...'); const echoResult = await mcpClient.callTool({ name: "echo", arguments: { message: "Hello, Nostr!" }, }); console.log("Echo result:", echoResult); // 6. Close the connection await mcpClient.close(); console.log("\nConnection closed."); } main().catch((error) => { console.error("Client failed:", error); process.exit(1); }); ```