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
JavaScript
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