Skip to main content
Glama
plugin-manager.ts6.56 kB
import * as fs from "fs/promises"; import * as path from "path"; export interface PluginInstallRequest { projectPath: string; pluginUrl?: string; pluginName?: string; pluginSource?: string; // URL or local path or npm package enabled?: boolean; } export interface PluginConfig { name: string; status: boolean; description: string; parameters: Record<string, any>; } // Popular RPG Maker MZ plugins registry const PLUGIN_REGISTRY: Record<string, string> = { "VisuMZ_0_CoreEngine": "https://raw.githubusercontent.com/VisuStella/VisualNovelChoice/master/VisuMZ_0_CoreEngine.js", // Add more popular plugins here }; export async function installPlugin(request: PluginInstallRequest): Promise<{ success: boolean; plugin?: string; error?: string }> { try { const pluginsDir = path.join(request.projectPath, "js", "plugins"); await fs.mkdir(pluginsDir, { recursive: true }); let pluginContent: string; let pluginName: string; // Determine plugin source if (request.pluginSource) { if (request.pluginSource.startsWith("http")) { // Download from URL const response = await fetch(request.pluginSource); if (!response.ok) { return { success: false, error: `Failed to download plugin: ${response.statusText}` }; } pluginContent = await response.text(); pluginName = request.pluginName || path.basename(new URL(request.pluginSource).pathname); } else if (await fs.access(request.pluginSource).then(() => true).catch(() => false)) { // Local file pluginContent = await fs.readFile(request.pluginSource, "utf-8"); pluginName = request.pluginName || path.basename(request.pluginSource); } else { return { success: false, error: "Invalid plugin source" }; } } else if (request.pluginName && PLUGIN_REGISTRY[request.pluginName]) { // From registry const url = PLUGIN_REGISTRY[request.pluginName]; const response = await fetch(url); if (!response.ok) { return { success: false, error: `Failed to download plugin from registry` }; } pluginContent = await response.text(); pluginName = request.pluginName; } else { return { success: false, error: "No valid plugin source provided" }; } // Save plugin file const pluginPath = path.join(pluginsDir, pluginName); await fs.writeFile(pluginPath, pluginContent, "utf-8"); // Update plugins.js await updatePluginsConfig(request.projectPath, pluginName, request.enabled !== false); return { success: true, plugin: pluginName }; } catch (error) { return { success: false, error: error instanceof Error ? error.message : String(error) }; } } async function updatePluginsConfig(projectPath: string, pluginName: string, enabled: boolean): Promise<void> { const pluginsJsPath = path.join(projectPath, "js", "plugins.js"); let pluginsConfig: PluginConfig[] = []; // Read existing config if exists try { const content = await fs.readFile(pluginsJsPath, "utf-8"); const match = content.match(/var \$plugins\s*=\s*(\[[\s\S]*?\]);/); if (match) { pluginsConfig = JSON.parse(match[1]); } } catch { // File doesn't exist, will create new } // Add or update plugin const existingIndex = pluginsConfig.findIndex(p => p.name === pluginName); const pluginEntry: PluginConfig = { name: pluginName.replace(".js", ""), status: enabled, description: "", parameters: {} }; if (existingIndex >= 0) { pluginsConfig[existingIndex] = pluginEntry; } else { pluginsConfig.push(pluginEntry); } // Write back const content = `// Generated by RPG Maker MZ MCP var $plugins = ${JSON.stringify(pluginsConfig, null, 2)}; `; await fs.writeFile(pluginsJsPath, content, "utf-8"); } export async function listInstalledPlugins(projectPath: string): Promise<{ success: boolean; plugins?: PluginConfig[]; error?: string }> { try { const pluginsJsPath = path.join(projectPath, "js", "plugins.js"); const content = await fs.readFile(pluginsJsPath, "utf-8"); const match = content.match(/var \$plugins\s*=\s*(\[[\s\S]*?\]);/); if (match) { const plugins = JSON.parse(match[1]); return { success: true, plugins }; } return { success: true, plugins: [] }; } catch (error) { return { success: false, error: error instanceof Error ? error.message : String(error) }; } } export async function uninstallPlugin(projectPath: string, pluginName: string): Promise<{ success: boolean; error?: string }> { try { // Remove from plugins.js const pluginsJsPath = path.join(projectPath, "js", "plugins.js"); const content = await fs.readFile(pluginsJsPath, "utf-8"); const match = content.match(/var \$plugins\s*=\s*(\[[\s\S]*?\]);/); if (match) { let plugins = JSON.parse(match[1]); plugins = plugins.filter((p: PluginConfig) => p.name !== pluginName.replace(".js", "")); const newContent = `// Generated by RPG Maker MZ MCP\nvar $plugins = ${JSON.stringify(plugins, null, 2)};\n`; await fs.writeFile(pluginsJsPath, newContent, "utf-8"); } // Delete plugin file const pluginPath = path.join(projectPath, "js", "plugins", pluginName); await fs.unlink(pluginPath); return { success: true }; } catch (error) { return { success: false, error: error instanceof Error ? error.message : String(error) }; } } export async function enablePlugin(projectPath: string, pluginName: string, enabled: boolean): Promise<{ success: boolean; error?: string }> { try { const pluginsJsPath = path.join(projectPath, "js", "plugins.js"); const content = await fs.readFile(pluginsJsPath, "utf-8"); const match = content.match(/var \$plugins\s*=\s*(\[[\s\S]*?\]);/); if (match) { const plugins = JSON.parse(match[1]); const plugin = plugins.find((p: PluginConfig) => p.name === pluginName.replace(".js", "")); if (plugin) { plugin.status = enabled; const newContent = `// Generated by RPG Maker MZ MCP\nvar $plugins = ${JSON.stringify(plugins, null, 2)};\n`; await fs.writeFile(pluginsJsPath, newContent, "utf-8"); return { success: true }; } return { success: false, error: "Plugin not found" }; } return { success: false, error: "No plugins config found" }; } catch (error) { return { success: false, error: error instanceof Error ? error.message : String(error) }; } }

Latest Blog Posts

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/ShunsukeHayashi/rpgmaker-mz-mcp'

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