import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { NDKEvent, NDKPrivateKeySigner } from "@nostr-dev-kit/ndk"; import { z } from "zod"; import { getUser, saveUser } from "../config.js"; import { getWallet } from "../lib/cache/wallets.js"; import { log } from "../lib/utils/log.js"; import { ndk } from "../ndk.js"; export async function createPubkey({ username, display_name, about, }: { username: string; display_name: string; about?: string; }) { try { // Check if username already exists const existingUser = getUser(username); if (existingUser) { throw new Error(`Username "${username}" already exists`); } // Generate a new keypair for this user const signer = NDKPrivateKeySigner.generate(); // Create profile metadata event (kind 0) const profileContent = JSON.stringify({ display_name, name: display_name, about: about || "", picture: `https://robohash.org/${username}`, }); // Create the event const event = new NDKEvent(ndk, { kind: 0, content: profileContent, tags: [], }); // Sign with the new signer await event.sign(signer); // Publish the event await event.publish(); // --- Setup Cashu Wallet (NIP-60/NIP-61) --- log(`Setting up Cashu wallet for ${username}...`); try { // Use getWallet to retrieve or create a wallet for the new pubkey const wallet = await getWallet(signer.pubkey, signer); if (wallet) { log(`Cashu wallet setup complete for ${username}.`); log(` -> P2PK: ${wallet.p2pk}`); log(` -> Mints: ${wallet.mints.join(", ")}`); } else { throw new Error("Failed to create wallet"); } } catch (walletError) { console.error( `Failed to set up Cashu wallet for ${username}:`, walletError ); // Decide if this should be a fatal error for pubkey creation // For now, log the error and continue } // --- End Cashu Wallet Setup --- // Save the user to the config saveUser(username, { nsec: signer.privateKey, display_name, about: about || "", }); // Create user object for return const user = ndk.getUser({ pubkey: signer.pubkey }); // Return success message log(`Created pubkey for ${username} with public key ${signer.pubkey}`); return { user, message: `Created pubkey for ${username} with npub ${user.npub} and a NIP-60 Cashu wallet for nutzaps`, }; } catch (error: unknown) { const errorMessage = error instanceof Error ? error.message : String(error); throw new Error(`Failed to create pubkey: ${errorMessage}`); } } export function addCreatePubkeyCommand(server: McpServer) { server.tool( "create_pubkey", "Create a new keypair and save it to config", { username: z.string().describe("Username to create"), display_name: z.string().describe("Display name for the pubkey"), about: z .string() .optional() .describe("About information for this pubkey"), }, async ({ username, display_name, about }) => { const result = await createPubkey({ username, display_name, about, }); return { content: [ { type: "text", text: result.message, }, ], }; } ); }