getLongFormNotes
Fetch long-form content from Nostr users by their public key to access detailed posts and articles shared on the decentralized social network.
Instructions
Get long-form notes (kind 30023) by public key
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| pubkey | Yes | Public key of the Nostr user (hex format or npub format) | |
| limit | No | Maximum number of notes to fetch | |
| relays | No | Optional list of relays to query |
Implementation Reference
- index.ts:791-889 (handler)The primary handler function for the getLongFormNotes MCP tool. It validates the pubkey, queries Nostr relays for kind 30023 events using pool.querySync, formats the results with metadata extraction from tags, and returns formatted text content.async ({ pubkey, limit, relays }, extra) => { // Convert npub to hex if needed const hexPubkey = npubToHex(pubkey); if (!hexPubkey) { return { content: [ { type: "text", text: "Invalid public key format. Please provide a valid hex pubkey or npub.", }, ], }; } // Generate a friendly display version of the pubkey const displayPubkey = formatPubkey(hexPubkey); const relaysToUse = relays || DEFAULT_RELAYS; // Create a fresh pool for this request const pool = getFreshPool(relaysToUse); try { console.error(`Fetching long-form notes for ${hexPubkey} from ${relaysToUse.join(", ")}`); // Query for long-form notes - snstr handles timeout internally const notes = await pool.querySync( relaysToUse, { kinds: [30023], // NIP-23 long-form content authors: [hexPubkey], limit, } as NostrFilter, { timeout: QUERY_TIMEOUT } ); if (!notes || notes.length === 0) { return { content: [ { type: "text", text: `No long-form notes found for ${displayPubkey}`, }, ], }; } // Sort notes by created_at in descending order (newest first) notes.sort((a, b) => b.created_at - a.created_at); // Format each note with enhanced metadata const formattedNotes = notes.map(note => { // Extract metadata from tags const title = note.tags.find(tag => tag[0] === "title")?.[1] || "Untitled"; const image = note.tags.find(tag => tag[0] === "image")?.[1]; const summary = note.tags.find(tag => tag[0] === "summary")?.[1]; const publishedAt = note.tags.find(tag => tag[0] === "published_at")?.[1]; const identifier = note.tags.find(tag => tag[0] === "d")?.[1]; // Format the output const lines = [ `Title: ${title}`, `Created: ${new Date(note.created_at * 1000).toLocaleString()}`, publishedAt ? `Published: ${new Date(parseInt(publishedAt) * 1000).toLocaleString()}` : null, image ? `Image: ${image}` : null, summary ? `Summary: ${summary}` : null, identifier ? `Identifier: ${identifier}` : null, `Content:`, note.content, `---`, ].filter(Boolean).join("\n"); return lines; }).join("\n\n"); return { content: [ { type: "text", text: `Found ${notes.length} long-form notes from ${displayPubkey}:\n\n${formattedNotes}`, }, ], }; } catch (error) { console.error("Error fetching long-form notes:", error); return { content: [ { type: "text", text: `Error fetching long-form notes for ${displayPubkey}: ${error instanceof Error ? error.message : "Unknown error"}`, }, ], }; } finally { // Clean up any subscriptions and close the pool await pool.close(); } } );
- note/note-tools.ts:24-28 (schema)Zod schema definition for the getLongFormNotes tool input parameters.export const getLongFormNotesToolConfig = { pubkey: z.string().describe("Public key of the Nostr user (hex format or npub format)"), limit: z.number().min(1).max(100).default(10).describe("Maximum number of notes to fetch"), relays: z.array(z.string()).optional().describe("Optional list of relays to query"), };
- index.ts:787-890 (registration)MCP server tool registration for getLongFormNotes, including name, description, schema config, and handler reference.server.tool( "getLongFormNotes", "Get long-form notes (kind 30023) by public key", getLongFormNotesToolConfig, async ({ pubkey, limit, relays }, extra) => { // Convert npub to hex if needed const hexPubkey = npubToHex(pubkey); if (!hexPubkey) { return { content: [ { type: "text", text: "Invalid public key format. Please provide a valid hex pubkey or npub.", }, ], }; } // Generate a friendly display version of the pubkey const displayPubkey = formatPubkey(hexPubkey); const relaysToUse = relays || DEFAULT_RELAYS; // Create a fresh pool for this request const pool = getFreshPool(relaysToUse); try { console.error(`Fetching long-form notes for ${hexPubkey} from ${relaysToUse.join(", ")}`); // Query for long-form notes - snstr handles timeout internally const notes = await pool.querySync( relaysToUse, { kinds: [30023], // NIP-23 long-form content authors: [hexPubkey], limit, } as NostrFilter, { timeout: QUERY_TIMEOUT } ); if (!notes || notes.length === 0) { return { content: [ { type: "text", text: `No long-form notes found for ${displayPubkey}`, }, ], }; } // Sort notes by created_at in descending order (newest first) notes.sort((a, b) => b.created_at - a.created_at); // Format each note with enhanced metadata const formattedNotes = notes.map(note => { // Extract metadata from tags const title = note.tags.find(tag => tag[0] === "title")?.[1] || "Untitled"; const image = note.tags.find(tag => tag[0] === "image")?.[1]; const summary = note.tags.find(tag => tag[0] === "summary")?.[1]; const publishedAt = note.tags.find(tag => tag[0] === "published_at")?.[1]; const identifier = note.tags.find(tag => tag[0] === "d")?.[1]; // Format the output const lines = [ `Title: ${title}`, `Created: ${new Date(note.created_at * 1000).toLocaleString()}`, publishedAt ? `Published: ${new Date(parseInt(publishedAt) * 1000).toLocaleString()}` : null, image ? `Image: ${image}` : null, summary ? `Summary: ${summary}` : null, identifier ? `Identifier: ${identifier}` : null, `Content:`, note.content, `---`, ].filter(Boolean).join("\n"); return lines; }).join("\n\n"); return { content: [ { type: "text", text: `Found ${notes.length} long-form notes from ${displayPubkey}:\n\n${formattedNotes}`, }, ], }; } catch (error) { console.error("Error fetching long-form notes:", error); return { content: [ { type: "text", text: `Error fetching long-form notes for ${displayPubkey}: ${error instanceof Error ? error.message : "Unknown error"}`, }, ], }; } finally { // Clean up any subscriptions and close the pool await pool.close(); } } );
- src/profile-notes.ts:58-76 (handler)Mock/test implementation of getLongFormNotes that generates fake long-form notes for testing purposes.export async function getLongFormNotes(pubkey: string, limit: number = 10, relays?: string[]): Promise<NostrNote[]> { const notes: NostrNote[] = []; for (let i = 0; i < limit; i++) { notes.push({ id: `longform${i}`, pubkey, content: `# Long Form Test ${i}\n\nThis is a test long-form note ${i}`, created_at: Math.floor(Date.now() / 1000) - (i * 86400), kind: 30023, tags: [ ["d", `article${i}`], ["title", `Long Form Test ${i}`] ] }); } return notes; }