Skip to main content
Glama

Nostr MCP Server

by AustinKelsay
import { jest } from '@jest/globals'; import { convertNip19, analyzeNip19 } from '../utils/nip19-tools.js'; import { generateKeypair, encodePublicKey, encodePrivateKey, encodeNoteId, encodeProfile, encodeEvent, encodeAddress } from 'snstr'; describe('NIP-19 Conversion Tools', () => { let testKeys: { publicKey: string; privateKey: string }; let testNpub: string; let testNsec: string; beforeAll(async () => { // Generate test keypair testKeys = await generateKeypair(); testNpub = encodePublicKey(testKeys.publicKey); testNsec = encodePrivateKey(testKeys.privateKey); }); describe('convertNip19', () => { describe('hex to other formats', () => { it('should convert hex pubkey to npub', async () => { const result = await convertNip19(testKeys.publicKey, 'npub'); expect(result.success).toBe(true); expect(result.result).toBe(testNpub); expect(result.originalType).toBe('hex'); expect(result.message).toContain('Successfully converted'); }); it('should convert hex to hex (no-op)', async () => { const result = await convertNip19(testKeys.publicKey, 'hex'); expect(result.success).toBe(true); expect(result.result).toBe(testKeys.publicKey); expect(result.originalType).toBe('hex'); }); it('should convert hex event ID to note', async () => { const eventId = '1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef'; const result = await convertNip19(eventId, 'note'); expect(result.success).toBe(true); expect(result.result).toMatch(/^note1/); expect(result.originalType).toBe('hex'); }); it('should convert hex to nprofile with relays', async () => { const relays = ['wss://relay.damus.io', 'wss://nos.lol']; const result = await convertNip19(testKeys.publicKey, 'nprofile', relays); expect(result.success).toBe(true); expect(result.result).toMatch(/^nprofile1/); expect(result.originalType).toBe('hex'); }); it('should convert hex to nevent with metadata', async () => { const eventId = '1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef'; const relays = ['wss://relay.damus.io']; const result = await convertNip19(eventId, 'nevent', relays, testKeys.publicKey, 1); expect(result.success).toBe(true); expect(result.result).toMatch(/^nevent1/); expect(result.originalType).toBe('hex'); }); it('should convert hex to naddr with required fields', async () => { const relays = ['wss://relay.damus.io']; const result = await convertNip19( testKeys.publicKey, 'naddr', relays, undefined, 30023, 'test-identifier' ); expect(result.success).toBe(true); expect(result.result).toMatch(/^naddr1/); expect(result.originalType).toBe('hex'); }); }); describe('npub conversions', () => { it('should convert npub to hex', async () => { const result = await convertNip19(testNpub, 'hex'); expect(result.success).toBe(true); expect(result.result).toBe(testKeys.publicKey); expect(result.originalType).toBe('npub'); }); it('should convert npub to nprofile', async () => { const relays = ['wss://relay.primal.net']; const result = await convertNip19(testNpub, 'nprofile', relays); expect(result.success).toBe(true); expect(result.result).toMatch(/^nprofile1/); expect(result.originalType).toBe('npub'); }); }); describe('nsec conversions', () => { it('should convert nsec to hex', async () => { const result = await convertNip19(testNsec, 'hex'); expect(result.success).toBe(true); expect(result.result).toBe(testKeys.privateKey); expect(result.originalType).toBe('nsec'); }); it('should handle nsec to npub conversion', async () => { const result = await convertNip19(testNsec, 'npub'); // The implementation might derive the public key from the private key // or it might fail - let's check what actually happens if (result.success) { // If it succeeds, it should return the corresponding npub expect(result.result).toMatch(/^npub1/); expect(result.originalType).toBe('nsec'); } else { // If it fails, check the error message expect(result.message).toBeDefined(); } }); }); describe('complex entity conversions', () => { it('should convert nprofile to npub', async () => { const nprofile = encodeProfile({ pubkey: testKeys.publicKey, relays: ['wss://relay.damus.io'] }); const result = await convertNip19(nprofile, 'npub'); expect(result.success).toBe(true); expect(result.result).toBe(testNpub); expect(result.originalType).toBe('nprofile'); }); it('should convert nevent to note', async () => { const eventId = '1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef'; const nevent = encodeEvent({ id: eventId, relays: ['wss://relay.damus.io'], author: testKeys.publicKey, kind: 1 }); const result = await convertNip19(nevent, 'note'); expect(result.success).toBe(true); expect(result.result).toBe(encodeNoteId(eventId)); expect(result.originalType).toBe('nevent'); }); it('should extract author from nevent to npub', async () => { const eventId = '1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef'; const nevent = encodeEvent({ id: eventId, relays: ['wss://relay.damus.io'], author: testKeys.publicKey, kind: 1 }); const result = await convertNip19(nevent, 'npub'); expect(result.success).toBe(true); expect(result.result).toBe(testNpub); expect(result.originalType).toBe('nevent'); }); it('should convert naddr to hex (pubkey)', async () => { const naddr = encodeAddress({ identifier: 'test-article', pubkey: testKeys.publicKey, kind: 30023, relays: ['wss://relay.damus.io'] }); const result = await convertNip19(naddr, 'hex'); expect(result.success).toBe(true); expect(result.result).toBe(testKeys.publicKey); expect(result.originalType).toBe('naddr'); }); }); describe('error handling', () => { it('should fail with invalid input', async () => { const result = await convertNip19('invalid_input', 'npub'); expect(result.success).toBe(false); expect(result.message).toContain('not a valid NIP-19 entity'); }); it('should handle converting note to npub', async () => { const note = encodeNoteId('1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef'); const result = await convertNip19(note, 'npub'); // Note entities don't contain pubkey information if (!result.success) { expect(result.message).toBeDefined(); } }); it('should fail naddr conversion without required fields', async () => { const result = await convertNip19(testKeys.publicKey, 'naddr'); expect(result.success).toBe(false); expect(result.message).toContain('requires identifier and kind'); }); it('should filter out invalid relay URLs', async () => { const invalidRelays = [ 'wss://valid.relay.com', 'https://invalid.relay.com', // Wrong protocol 'wss://user:pass@relay.com', // Has credentials 'invalid-url' // Not a URL ]; const result = await convertNip19(testKeys.publicKey, 'nprofile', invalidRelays); expect(result.success).toBe(true); expect(result.result).toMatch(/^nprofile1/); // Should only include the valid relay expect(result.data).toBeDefined(); }); }); }); describe('analyzeNip19', () => { it('should analyze hex string', async () => { const result = await analyzeNip19(testKeys.publicKey); expect(result.success).toBe(true); expect(result.type).toBe('hex'); expect(result.data).toBe(testKeys.publicKey); expect(result.message).toContain('Valid 64-character hex string'); }); it('should analyze npub', async () => { const result = await analyzeNip19(testNpub); expect(result.success).toBe(true); expect(result.type).toBe('npub'); expect(result.data).toBe(testKeys.publicKey); expect(result.message).toContain('Valid npub entity'); }); it('should analyze nsec', async () => { const result = await analyzeNip19(testNsec); expect(result.success).toBe(true); expect(result.type).toBe('nsec'); expect(result.data).toBe(testKeys.privateKey); expect(result.message).toContain('Valid nsec entity'); }); it('should analyze note', async () => { const eventId = '1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef'; const note = encodeNoteId(eventId); const result = await analyzeNip19(note); expect(result.success).toBe(true); expect(result.type).toBe('note'); expect(result.data).toBe(eventId); expect(result.message).toContain('Valid note entity'); }); it('should analyze nprofile with relays', async () => { const nprofile = encodeProfile({ pubkey: testKeys.publicKey, relays: ['wss://valid.relay.com'] }); const result = await analyzeNip19(nprofile); expect(result.success).toBe(true); expect(result.type).toBe('nprofile'); expect(result.data.pubkey).toBe(testKeys.publicKey); expect(result.data.relays).toEqual(['wss://valid.relay.com']); expect(result.message).toContain('Valid nprofile entity'); }); it('should analyze nevent', async () => { const eventId = '1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef'; const nevent = encodeEvent({ id: eventId, relays: ['wss://relay.damus.io'], author: testKeys.publicKey, kind: 1 }); const result = await analyzeNip19(nevent); expect(result.success).toBe(true); expect(result.type).toBe('nevent'); expect(result.data.id).toBe(eventId); expect(result.data.author).toBe(testKeys.publicKey); if (result.data.kind) expect(result.data.kind).toBe(1); expect(result.data.relays).toEqual(['wss://relay.damus.io']); expect(result.message).toContain('Valid nevent entity'); }); it('should analyze naddr', async () => { const naddr = encodeAddress({ identifier: 'test-article', pubkey: testKeys.publicKey, kind: 30023, relays: ['wss://relay.damus.io'] }); const result = await analyzeNip19(naddr); expect(result.success).toBe(true); expect(result.type).toBe('naddr'); expect(result.data.identifier).toBe('test-article'); expect(result.data.pubkey).toBe(testKeys.publicKey); expect(result.data.kind).toBe(30023); expect(result.data.relays).toEqual(['wss://relay.damus.io']); expect(result.message).toContain('Valid naddr entity'); }); it('should fail with invalid input', async () => { const result = await analyzeNip19('not_a_valid_nip19_or_hex'); expect(result.success).toBe(false); expect(result.message).toBeDefined(); expect(result.message.toLowerCase()).toContain('unknown prefix'); }); it('should fail with invalid hex (wrong length)', async () => { const result = await analyzeNip19('abcdef123456'); // Too short expect(result.success).toBe(false); expect(result.message).toBeDefined(); }); }); });

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