Skip to main content
Glama

publishNote

Publish signed notes to Nostr relays for decentralized social networking. This tool sends authenticated content to the Nostr network.

Instructions

Publish a signed note to Nostr relays

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
signedNoteYesSigned note event to publish
relaysNoOptional list of relays to publish to

Implementation Reference

  • Core handler function that takes a signed Nostr event and publishes it to the specified relays, returning success status and count of accepting relays.
    export async function publishNote(
      signedNote: {
        id: string;
        pubkey: string;
        created_at: number;
        kind: number;
        tags: string[][];
        content: string;
        sig: string;
      },
      relays: string[] = DEFAULT_RELAYS
    ): Promise<{ success: boolean, message: string, noteId?: string }> {
      try {
        // console.error(`Preparing to publish note to ${relays.join(", ")}`);
        
        // If no relays specified, just return success with event validation
        if (relays.length === 0) {
          return {
            success: true,
            message: 'Note is valid and ready to publish (no relays specified)',
            noteId: signedNote.id,
          };
        }
        
        // Create a fresh pool for this request
        const pool = getFreshPool(relays);
        
        try {
          // Publish to relays and wait for actual relay OK responses
          const pubPromises = pool.publish(relays, signedNote);
          
          // Wait for all publish attempts to complete or timeout
          const results = await Promise.allSettled(pubPromises);
          
          // Check if at least one relay actually accepted the event
          // A fulfilled promise means relay responded, but we need to check if it accepted
          const successCount = results.filter(r => 
            r.status === 'fulfilled' && r.value.success === true
          ).length;
          
          if (successCount === 0) {
            return {
              success: false,
              message: 'Failed to publish note to any relay',
            };
          }
          
          return {
            success: true,
            message: `Note published to ${successCount}/${relays.length} relays`,
            noteId: signedNote.id,
          };
        } catch (error) {
          console.error("Error publishing note:", error);
          
          return {
            success: false,
            message: `Error publishing note: ${error instanceof Error ? error.message : "Unknown error"}`,
          };
        } finally {
          // Clean up any subscriptions and close the pool
          await pool.close();
        }
      } catch (error) {
        return {
          success: false,
          message: `Fatal error: ${error instanceof Error ? error.message : "Unknown error"}`,
        };
      }
    }
  • Zod input schema for the publishNote tool, validating the signedNote object structure and optional relays array.
    export const publishNoteToolConfig = {
      signedNote: z.object({
        id: z.string().describe("Event ID"),
        pubkey: z.string().describe("Public key of the author"),
        created_at: z.number().describe("Creation timestamp"),
        kind: z.number().describe("Event kind"),
        tags: z.array(z.array(z.string())).describe("Tags array"),
        content: z.string().describe("Content of the note"),
        sig: z.string().describe("Event signature")
      }).describe("Signed note event to publish"),
      relays: z.array(z.string()).optional().describe("Optional list of relays to publish to"),
    };
  • index.ts:1508-1559 (registration)
    MCP server registration of the 'publishNote' tool, which calls the core publishNote handler and formats the response for the MCP protocol.
    server.tool(
      "publishNote",
      "Publish a signed note to Nostr relays",
      publishNoteToolConfig,
      async ({ signedNote, relays }) => {
        try {
          const result = await publishNote(signedNote, relays);
          
          if (result.success) {
            let response = `Note published successfully!\n\n`;
            response += `${result.message}\n`;
            if (result.noteId) {
              response += `Note ID: ${result.noteId}\n`;
            }
            response += `Content: "${signedNote.content}"\n`;
            response += `Author: ${formatPubkey(signedNote.pubkey)}\n`;
            if (relays && relays.length > 0) {
              response += `Relays: ${relays.join(", ")}\n`;
            }
            
            return {
              content: [
                {
                  type: "text",
                  text: response,
                },
              ],
            };
          } else {
            return {
              content: [
                {
                  type: "text",
                  text: `Failed to publish note: ${result.message}`,
                },
              ],
            };
          }
        } catch (error) {
          console.error("Error in publishNote tool:", error);
          
          return {
            content: [
              {
                type: "text",
                text: `Error publishing note: ${error instanceof Error ? error.message : "Unknown error"}`,
              },
            ],
          };
        }
      },
    );

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/AustinKelsay/nostr-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server