Skip to main content
Glama

MCP-NOSTR

by pablof7z
snippets.ts6.41 kB
import type { NDKEvent } from "@nostr-dev-kit/ndk"; import { knownUsers } from "../../users.js"; import type { CodeSnippet } from "../types/index.js"; /** * Converts an NDKEvent into a CodeSnippet * @param event NDKEvent of kind 1337 * @returns CodeSnippet object */ export function toSnippet(event: NDKEvent): CodeSnippet { const title = event.tagValue("title") ?? event.tagValue("name"); const description = event.tagValue("description") ?? ""; const language = event.tagValue("l"); const tags = event.tags .filter((tag) => tag[0] === "t" && tag[1] !== undefined) .map((tag) => tag[1] as string); return { id: event.id, title: title || "Untitled", description, code: event.content, language: language || "text", pubkey: event.pubkey, createdAt: event.created_at || 0, tags, }; } /** * Converts a CodeSnippet to a formatted metadata string (without code) * @param snippet CodeSnippet object * @returns Formatted metadata string */ export function toMetadataString(snippet: CodeSnippet): string { const { title, description, language, tags, id, pubkey, createdAt } = snippet; const profile = knownUsers[pubkey]?.profile; const returns = [ `ID: ${id}`, `Title: ${title}`, `Description: ${description}`, `Language: ${language}`, `Tags: ${tags.join(", ")}`, `Created: ${new Date(createdAt * 1000).toISOString()}`, `Pubkey: ${pubkey}`, ]; if (profile?.name) returns.push(`Author: ${profile.name}`); return returns.join("\n"); } /** * Formats a single snippet for display * @param snippet The snippet to format * @returns Formatted string representation */ export function formatSnippet(snippet: CodeSnippet): string { return formatSnippets([snippet]); } /** * Formats snippets for display * @param snippets Array of code snippets * @returns Formatted string representation */ export function formatSnippets(snippets: CodeSnippet[]): string { return snippets .map((snippet) => { const author = knownUsers[snippet.pubkey]; const keys: Record<string, string> = { ID: snippet.id, Title: snippet.title, Description: snippet.description, Language: snippet.language, Tags: snippet.tags.join(", "), Code: snippet.code, Date: new Date(snippet.createdAt * 1000).toISOString(), }; if (author?.profile?.name) keys.Author = author.profile.name; return Object.entries(keys) .map(([key, value]) => `${key}: ${value}`) .join("\n"); }) .join("\n\n---\n\n"); } /** * Formats partial match snippets for display * @param snippets Array of code snippets * @returns Formatted string representation */ export function formatPartialMatches(snippets: CodeSnippet[]): string { if (snippets.length === 0) return ""; let text = "\n\nSome other events not included in this result since they had less in common with your search, here is a list of the events that had partial matches:\n\n"; text += snippets .map((snippet) => { return ` * ${snippet.title}:\n Tags: ${snippet.tags.join(", ")} (ID: ${snippet.id})`; }) .join("\n"); return text; } /** * Parses metadata from a file content string * @param fileContent String containing metadata and code sections * @returns Object with metadata and code */ export function parseMetadataFromString(fileContent: string): { metadata: { title: string; description: string; language: string; tags: string[] }; code: string } { // Match the metadata and code sections const metadataRegex = /^---METADATA---([\s\S]*?)(?=^---CODE---$)(^---CODE---$)([\s\S]*)$/m; const matches = fileContent.match(metadataRegex); if (!matches || matches.length < 4) { throw new Error("Invalid file format: metadata section not found"); } const metadataSection = matches[1] || ""; let codeSection = matches[3] || ""; // Remove leading newline from code section if present if (codeSection.startsWith("\n")) { codeSection = codeSection.substring(1); } // Parse each field with proper multiline flag const titleMatch = metadataSection.match(/^Title:\s*(.+)$/m); const title = titleMatch?.[1] ? titleMatch[1].trim() : ""; // Extract description which can be multiline but should stop at Language: or Tags: const descriptionLines = []; let inDescription = false; // Process line by line const lines = metadataSection.split('\n'); for (const line of lines) { if (line.trim().startsWith('Description:')) { inDescription = true; const content = line.replace(/^Description:\s*/, '').trim(); if (content) { descriptionLines.push(content); } } else if (line.trim().startsWith('Language:') || line.trim().startsWith('Tags:')) { inDescription = false; } else if (inDescription) { descriptionLines.push(line); } } const description = descriptionLines.join('\n').trim(); const languageMatch = metadataSection.match(/^Language:\s*(.+)$/m); const language = languageMatch?.[1] ? languageMatch[1].trim() : ""; const tagsMatch = metadataSection.match(/^Tags:\s*(.+)$/m); const tagsString = tagsMatch?.[1] ? tagsMatch[1].trim() : ""; const tags = tagsString.split(',').map(tag => tag.trim()).filter(Boolean); return { metadata: { title, description, language, tags }, code: codeSection }; } /** * Creates a string with metadata and code sections */ export function createMetadataString( title: string, description: string, language: string, tags: string[], code: string ): string { return `---METADATA--- # Edit the metadata below. Keep the format exactly as shown (Title:, Description:, Language:, Tags:) # Description needs to be at least 140 characters and Tags need at least 5 entries # Don't remove the ---METADATA--- and ---CODE--- markers! Title: ${title} Description: ${description} Language: ${language} Tags: ${tags.join(', ')} ---CODE--- ${code}`; }

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/pablof7z/mcp-code'

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