UNPKG

openapi-directory-mcp

Version:

Model Context Protocol server for accessing enhanced triple-source OpenAPI directory (APIs.guru + additional APIs + custom imports)

183 lines 6.23 kB
import fs from "fs"; import path from "path"; import { fileURLToPath } from "url"; // ES module compatibility - avoid conflicts in test environments const getPromptsDir = () => { try { if (typeof import.meta !== "undefined" && import.meta.url) { const __filename = fileURLToPath(import.meta.url); return path.dirname(__filename); } } catch (error) { // Fallback for test environments } // Fallback for environments where import.meta is not available return path.join(process.cwd(), "src", "prompts"); }; export class PromptRegistry { constructor() { this.categories = new Map(); this.promptsByName = new Map(); this.allPrompts = []; } register(category, prompt) { // Add to category if (!this.categories.has(category)) { this.categories.set(category, []); } this.categories.get(category).push(prompt); // Add to name lookup this.promptsByName.set(prompt.name, prompt); // Add to all prompts this.allPrompts.push(prompt); } getPrompt(name) { return this.promptsByName.get(name); } getCategory(name) { return this.categories.get(name) || []; } getAllPrompts() { return [...this.allPrompts]; } getCategories() { return Array.from(this.categories.keys()); } getCategoryMap() { return new Map(this.categories); } clear() { this.categories.clear(); this.promptsByName.clear(); this.allPrompts = []; } } export class PromptLoader { constructor() { this.registry = new PromptRegistry(); this.loaded = false; } async loadAllPrompts() { if (!this.loaded) { await this.scanAndLoadCategories(); this.loaded = true; } return this.registry.getAllPrompts(); } async scanAndLoadCategories() { const promptsDir = getPromptsDir(); try { const entries = fs.readdirSync(promptsDir, { withFileTypes: true }); for (const entry of entries) { if (entry.isDirectory() && this.isValidCategoryName(entry.name)) { await this.loadCategory(entry.name); } } } catch (error) { console.error("Error scanning prompts directory:", error); throw new Error(`Failed to scan prompts directory: ${error}`); } } async loadCategory(categoryName) { const categoryPath = path.join(getPromptsDir(), categoryName); try { const files = fs .readdirSync(categoryPath) .filter((file) => file.endsWith(".js") && !file.endsWith(".d.ts")) .filter((file) => file !== "index.js"); // Skip index files for (const file of files) { await this.loadPromptFile(categoryName, categoryPath, file); } } catch (error) { console.error(`Error loading category ${categoryName}:`, error); // Don't throw - continue loading other categories } } async loadPromptFile(categoryName, categoryPath, filename) { const filePath = path.join(categoryPath, filename); const relativePath = path.relative(getPromptsDir(), filePath); try { // Use dynamic import to load the module const module = await import(`./${relativePath.replace(/\\/g, "/")}`); let prompt; // Try different export patterns if (module.default && this.isValidPrompt(module.default)) { prompt = module.default; } else if (module.prompt && this.isValidPrompt(module.prompt)) { prompt = module.prompt; } else { // Look for any named export that's a valid prompt for (const value of Object.values(module)) { if (this.isValidPrompt(value)) { prompt = value; break; } } } if (prompt) { this.registry.register(categoryName, prompt); } else { // No valid prompt found - skip file } } catch (error) { console.error(`Error loading prompt file ${relativePath}:`, error); // Don't throw - continue loading other files } } isValidPrompt(obj) { return (obj && typeof obj === "object" && typeof obj.name === "string" && obj.name.length > 0 && typeof obj.description === "string" && obj.description.length > 0 && typeof obj.generateMessages === "function" && (obj.arguments === undefined || Array.isArray(obj.arguments))); } isValidCategoryName(name) { // Skip hidden directories, node_modules, etc. return (!name.startsWith(".") && !name.startsWith("_") && name !== "node_modules" && name !== "dist" && name !== "build"); } getRegistry() { return this.registry; } async getCategories() { if (!this.loaded) { await this.scanAndLoadCategories(); this.loaded = true; } return this.registry.getCategories().map((categoryName) => ({ name: categoryName, prompts: this.registry.getCategory(categoryName), })); } async getPromptsByCategory(categoryName) { if (!this.loaded) { await this.scanAndLoadCategories(); this.loaded = true; } return this.registry.getCategory(categoryName); } async getPrompt(name) { if (!this.loaded) { await this.scanAndLoadCategories(); this.loaded = true; } return this.registry.getPrompt(name); } } // Create a singleton instance for easy access export const promptLoader = new PromptLoader(); export const promptRegistry = promptLoader.getRegistry(); //# sourceMappingURL=loader.js.map