convertNip19
Transform NIP-19 entities like npub, nsec, note, nprofile, nevent, and naddr into desired formats, including hex, for Nostr network operations.
Instructions
Convert any NIP-19 entity (npub, nsec, note, nprofile, nevent, naddr) to another format
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| author | No | Optional author pubkey (hex format) for nevent/naddr | |
| identifier | No | Required identifier for naddr conversion | |
| input | Yes | The NIP-19 entity or hex string to convert | |
| kind | No | Optional event kind for nevent/naddr | |
| relays | No | Optional relay URLs for complex entities (nprofile, nevent, naddr) | |
| targetType | Yes | The target format to convert to |
Implementation Reference
- index.ts:999-1049 (registration)MCP server registration of the 'convertNip19' tool, importing and using convertNip19ToolConfig and convertNip19 handler from nip19-tools// Register NIP-19 conversion tools server.tool( "convertNip19", "Convert any NIP-19 entity (npub, nsec, note, nprofile, nevent, naddr) to another format", convertNip19ToolConfig, async ({ input, targetType, relays, author, kind, identifier }) => { try { const result = await convertNip19(input, targetType, relays, author, kind, identifier); if (result.success) { let response = `Conversion successful!\n\n`; response += `Original: ${result.originalType} entity\n`; response += `Target: ${targetType}\n`; response += `Result: ${result.result}\n`; if (result.originalType && ['nprofile', 'nevent', 'naddr'].includes(result.originalType)) { response += `\nOriginal entity data:\n${formatAnalysisResult(result.originalType, result.data)}`; } return { content: [ { type: "text", text: response, }, ], }; } else { return { content: [ { type: "text", text: `Conversion failed: ${result.message}`, }, ], }; } } catch (error) { console.error("Error in convertNip19 tool:", error); return { content: [ { type: "text", text: `Error during conversion: ${error instanceof Error ? error.message : "Unknown error"}`, }, ], }; } }, );
- utils/nip19-tools.ts:4-12 (schema)Zod schema definition for convertNip19 tool input validation (convertNip19ToolConfig)// Schema for convertNip19 tool export const convertNip19ToolConfig = { input: z.string().describe("The NIP-19 entity or hex string to convert"), targetType: z.enum(['npub', 'nsec', 'note', 'hex', 'nprofile', 'nevent', 'naddr']).describe("The target format to convert to"), relays: z.array(z.string()).optional().describe("Optional relay URLs for complex entities (nprofile, nevent, naddr)"), author: z.string().optional().describe("Optional author pubkey (hex format) for nevent/naddr"), kind: z.number().optional().describe("Optional event kind for nevent/naddr"), identifier: z.string().optional().describe("Required identifier for naddr conversion"), };
- utils/nip19-tools.ts:19-64 (handler)Main handler function convertNip19 that prepares options and calls the core convertNip19Entity, handles errors and formatting/** * Convert any NIP-19 entity to another format */ export async function convertNip19( input: string, targetType: 'npub' | 'nsec' | 'note' | 'hex' | 'nprofile' | 'nevent' | 'naddr', relays?: string[], author?: string, kind?: number, identifier?: string ): Promise<{ success: boolean, message: string, result?: string, originalType?: string, data?: any }> { try { const options: ConversionInput = { input, targetType, entityData: { ...(relays && { relays }), ...(author && { author }), ...(kind && { kind }), ...(identifier && { identifier }) } }; const result = convertNip19Entity(options); if (!result.success) { return { success: false, message: result.message || 'Conversion failed' }; } return { success: true, message: result.message || 'Conversion successful', result: result.result, originalType: result.originalType, data: result.data }; } catch (error) { return { success: false, message: `Error during conversion: ${error instanceof Error ? error.message : 'Unknown error'}` }; } }
- utils/conversion.ts:153-307 (handler)Core conversion logic implementing NIP-19 decoding, type detection, security filtering, and encoding to target formats using snstr library* Convert any NIP-19 entity to any other format */ export function convertNip19Entity(options: ConversionInput): ConversionResult { try { const { input, targetType, entityData } = options; const cleanInput = input.trim(); // First, detect what type of input we have let sourceData: any; let sourceType: string | undefined; // Try to decode as NIP-19 entity first if (cleanInput.includes('1')) { try { const decoded = decode(cleanInput as `${string}1${string}`); sourceType = decoded.type; sourceData = decoded.data; } catch (e) { // Not a valid NIP-19 entity, might be hex } } // If not NIP-19, check if it's hex if (!sourceType) { if (/^[0-9a-fA-F]{64}$/.test(cleanInput)) { sourceType = 'hex'; sourceData = cleanInput.toLowerCase(); } else { return { success: false, message: 'Input is not a valid NIP-19 entity or hex string' }; } } // Apply security filtering for complex types if (['nprofile', 'nevent', 'naddr'].includes(sourceType)) { if (sourceType === 'nprofile') { sourceData = filterProfile(sourceData); } else if (sourceType === 'nevent') { sourceData = filterEvent(sourceData); } else if (sourceType === 'naddr') { sourceData = filterAddress(sourceData); } } // Now convert to target type let result: string; switch (targetType) { case 'hex': const hexResult = extractHexFromEntity(sourceType, sourceData); if (!hexResult) throw new Error('Cannot extract hex from input'); result = hexResult; break; case 'npub': const pubkeyHex = extractHexFromEntity(sourceType, sourceData); if (!pubkeyHex) throw new Error('Cannot extract pubkey from input'); result = encodePublicKey(pubkeyHex); break; case 'nsec': if (sourceType !== 'nsec' && sourceType !== 'hex') { throw new Error('Can only convert private keys to nsec format'); } const privkeyHex = sourceData; result = encodePrivateKey(privkeyHex); break; case 'note': if (sourceType === 'nevent') { result = encodeNoteId(sourceData.id); } else if (sourceType === 'note') { result = cleanInput; // Already a note } else if (sourceType === 'hex') { result = encodeNoteId(sourceData); } else { throw new Error('Cannot convert this entity type to note format'); } break; case 'nprofile': const profilePubkey = extractHexFromEntity(sourceType, sourceData); if (!profilePubkey) throw new Error('Cannot extract pubkey from input'); const profileData = { pubkey: profilePubkey, relays: entityData?.relays?.filter(url => isValidRelayUrl(url)) || [] }; result = encodeProfile(profileData); break; case 'nevent': let eventId: string; if (sourceType === 'nevent') { eventId = sourceData.id; } else if (sourceType === 'note') { eventId = sourceData; } else if (sourceType === 'hex') { eventId = sourceData; } else { throw new Error('Cannot convert this entity type to nevent format'); } const eventData = { id: eventId, relays: entityData?.relays?.filter(url => isValidRelayUrl(url)) || [], ...(entityData?.author && { author: entityData.author }), ...(entityData?.kind && { kind: entityData.kind }) }; result = encodeEvent(eventData); break; case 'naddr': if (!entityData?.identifier || !entityData?.kind) { throw new Error('naddr conversion requires identifier and kind'); } const addrPubkey = extractHexFromEntity(sourceType, sourceData); if (!addrPubkey) { if (!entityData?.author) { throw new Error('naddr conversion requires a pubkey (from input or entityData.author)'); } } const addressData = { identifier: entityData.identifier, pubkey: addrPubkey || entityData.author!, kind: entityData.kind, relays: entityData?.relays?.filter(url => isValidRelayUrl(url)) || [] }; result = encodeAddress(addressData); break; default: throw new Error(`Unsupported target type: ${targetType}`); } return { success: true, result, originalType: sourceType, targetType, message: `Successfully converted ${sourceType} to ${targetType}`, data: sourceData }; } catch (error) { return { success: false, message: `Conversion failed: ${error instanceof Error ? error.message : 'Unknown error'}` }; } }