Skip to main content
Glama
index.ts51.1 kB
#!/usr/bin/env node import { Server } from "@modelcontextprotocol/sdk/server/index.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js"; import * as fs from "fs/promises"; import * as path from "path"; import { createNewProject, createMap, updateMapTile, addEvent, updateEvent, addEventCommand, addActor, addClass, addSkill, addItem, updateDatabase } from "./game-creation-tools.js"; import { generateAssetWithGemini, generateAssetBatch, describeAsset, type AssetGenerationRequest } from "./asset-generation.js"; import { generateScenarioWithGemini, implementScenario, generateAndImplementScenario, generateScenarioVariations, type ScenarioGenerationRequest } from "./scenario-generation.js"; import { installPlugin, listInstalledPlugins, uninstallPlugin, enablePlugin } from "./plugin-manager.js"; import { optimizeAssets, getProjectSize } from "./asset-optimizer.js"; import { generateQuestSystem } from "./quest-system.js"; import { generateDialogueTree } from "./dialogue-tree.js"; import { autoBalanceStats } from "./stat-balancer.js"; import { translateProject } from "./localization.js"; import { initVersionControl, createSnapshot, createBackup } from "./versioning.js"; import { analyzePerformance } from "./profiler.js"; import { createGameAutonomously, type AutonomousCreationRequest } from "./autonomous-creator.js"; import { setupGlobalErrorHandlers, Logger } from "./error-handling.js"; import { analyzeProjectAssets, generateAssetContext, generateAssetMapping, removeUnusedAssets } from "./asset-context.js"; import { getDatabaseStatistics, searchDatabase, findByName, generateDatabaseContext } from "./database-index.js"; import { registerResource, registerPromptTemplate, getResource, listResources, listPromptTemplates, executePrompt, generatePromptFromResources, initializeDefaultPrompts } from "./resource-manager.js"; const RPGMAKER_APP_PATH = "/Users/shunsuke/Applications/RPG Maker MZ.app"; // Setup global error handlers setupGlobalErrorHandlers(); // RPG Maker MZ project structure tools const server = new Server( { name: "rpgmaker-mz-mcp", version: "0.1.0", }, { capabilities: { tools: {}, }, } ); // List available tools server.setRequestHandler(ListToolsRequestSchema, async () => { return { tools: [ { name: "list_projects", description: "List all RPG Maker MZ projects in a directory", inputSchema: { type: "object", properties: { directory: { type: "string", description: "Directory path to search for projects (defaults to ~/Documents)", }, }, }, }, { name: "read_project_info", description: "Read RPG Maker MZ project information (Game.rpgproject file)", inputSchema: { type: "object", properties: { project_path: { type: "string", description: "Path to the RPG Maker MZ project directory", }, }, required: ["project_path"], }, }, { name: "list_maps", description: "List all maps in an RPG Maker MZ project", inputSchema: { type: "object", properties: { project_path: { type: "string", description: "Path to the RPG Maker MZ project directory", }, }, required: ["project_path"], }, }, { name: "read_map", description: "Read a specific map file from an RPG Maker MZ project", inputSchema: { type: "object", properties: { project_path: { type: "string", description: "Path to the RPG Maker MZ project directory", }, map_id: { type: "string", description: "Map ID (e.g., 'Map001')", }, }, required: ["project_path", "map_id"], }, }, { name: "list_plugins", description: "List all plugins in an RPG Maker MZ project", inputSchema: { type: "object", properties: { project_path: { type: "string", description: "Path to the RPG Maker MZ project directory", }, }, required: ["project_path"], }, }, { name: "generate_project_context", description: "Generate comprehensive context documentation for an RPG Maker MZ project including structure, maps, events, and plugin information", inputSchema: { type: "object", properties: { project_path: { type: "string", description: "Path to the RPG Maker MZ project directory", }, include_maps: { type: "boolean", description: "Include detailed map information (default: true)", }, include_events: { type: "boolean", description: "Include event data (default: true)", }, include_plugins: { type: "boolean", description: "Include plugin information (default: true)", }, }, required: ["project_path"], }, }, { name: "analyze_project_structure", description: "Analyze RPG Maker MZ project structure and provide insights about maps, connections, events, and game flow", inputSchema: { type: "object", properties: { project_path: { type: "string", description: "Path to the RPG Maker MZ project directory", }, }, required: ["project_path"], }, }, { name: "extract_game_design_patterns", description: "Extract common game design patterns from the project (event patterns, map layouts, etc.)", inputSchema: { type: "object", properties: { project_path: { type: "string", description: "Path to the RPG Maker MZ project directory", }, }, required: ["project_path"], }, }, { name: "create_project", description: "Create a new RPG Maker MZ project from scratch", inputSchema: { type: "object", properties: { project_path: { type: "string", description: "Path where the project will be created", }, game_title: { type: "string", description: "Title of the game", }, }, required: ["project_path", "game_title"], }, }, { name: "create_map", description: "Create a new map in the project", inputSchema: { type: "object", properties: { project_path: { type: "string", description: "Path to the RPG Maker MZ project directory", }, map_id: { type: "number", description: "Map ID number", }, name: { type: "string", description: "Map name", }, width: { type: "number", description: "Map width in tiles (default: 17)", }, height: { type: "number", description: "Map height in tiles (default: 13)", }, }, required: ["project_path", "map_id", "name"], }, }, { name: "update_map_tile", description: "Update a tile on a map", inputSchema: { type: "object", properties: { project_path: { type: "string", description: "Path to the RPG Maker MZ project directory", }, map_id: { type: "number", description: "Map ID", }, x: { type: "number", description: "X coordinate", }, y: { type: "number", description: "Y coordinate", }, layer: { type: "number", description: "Layer index (0-5)", }, tile_id: { type: "number", description: "Tile ID from tileset", }, }, required: ["project_path", "map_id", "x", "y", "layer", "tile_id"], }, }, { name: "add_event", description: "Add a new event to a map", inputSchema: { type: "object", properties: { project_path: { type: "string", description: "Path to the RPG Maker MZ project directory", }, map_id: { type: "number", description: "Map ID", }, event_id: { type: "number", description: "Event ID", }, name: { type: "string", description: "Event name", }, x: { type: "number", description: "X coordinate", }, y: { type: "number", description: "Y coordinate", }, }, required: ["project_path", "map_id", "event_id", "name", "x", "y"], }, }, { name: "add_event_command", description: "Add a command to an event page (e.g., show text, transfer player, etc.)", inputSchema: { type: "object", properties: { project_path: { type: "string", description: "Path to the RPG Maker MZ project directory", }, map_id: { type: "number", description: "Map ID", }, event_id: { type: "number", description: "Event ID", }, page_index: { type: "number", description: "Page index (0-based)", }, code: { type: "number", description: "Command code (e.g., 101=Show Text, 201=Transfer Player, 122=Control Variables)", }, parameters: { type: "array", description: "Command parameters", }, }, required: ["project_path", "map_id", "event_id", "page_index", "code", "parameters"], }, }, { name: "add_actor", description: "Add a new actor to the database", inputSchema: { type: "object", properties: { project_path: { type: "string", description: "Path to the RPG Maker MZ project directory", }, id: { type: "number", description: "Actor ID", }, name: { type: "string", description: "Actor name", }, }, required: ["project_path", "id", "name"], }, }, { name: "add_class", description: "Add a new class to the database", inputSchema: { type: "object", properties: { project_path: { type: "string", description: "Path to the RPG Maker MZ project directory", }, id: { type: "number", description: "Class ID", }, name: { type: "string", description: "Class name", }, }, required: ["project_path", "id", "name"], }, }, { name: "add_skill", description: "Add a new skill to the database", inputSchema: { type: "object", properties: { project_path: { type: "string", description: "Path to the RPG Maker MZ project directory", }, id: { type: "number", description: "Skill ID", }, name: { type: "string", description: "Skill name", }, }, required: ["project_path", "id", "name"], }, }, { name: "add_item", description: "Add a new item to the database", inputSchema: { type: "object", properties: { project_path: { type: "string", description: "Path to the RPG Maker MZ project directory", }, id: { type: "number", description: "Item ID", }, name: { type: "string", description: "Item name", }, }, required: ["project_path", "id", "name"], }, }, { name: "update_database", description: "Update an entry in any database (Actors, Classes, Skills, Items, Weapons, Armors, etc.)", inputSchema: { type: "object", properties: { project_path: { type: "string", description: "Path to the RPG Maker MZ project directory", }, database: { type: "string", description: "Database name (e.g., 'Actors', 'Classes', 'Skills', 'Items')", }, id: { type: "number", description: "Entry ID", }, updates: { type: "object", description: "Object containing fields to update", }, }, required: ["project_path", "database", "id", "updates"], }, }, { name: "generate_asset", description: "Generate RPG Maker MZ asset using Gemini 2.5 Flash (characters, faces, tilesets, etc.)", inputSchema: { type: "object", properties: { project_path: { type: "string", description: "Path to the RPG Maker MZ project directory", }, asset_type: { type: "string", enum: ["character", "face", "tileset", "battleback", "enemy", "sv_actor", "picture"], description: "Type of asset to generate", }, prompt: { type: "string", description: "Description of the asset to generate", }, filename: { type: "string", description: "Filename for the generated asset (with extension)", }, api_key: { type: "string", description: "Gemini API key (optional, uses GEMINI_API_KEY env var if not provided)", }, }, required: ["project_path", "asset_type", "prompt", "filename"], }, }, { name: "generate_asset_batch", description: "Generate multiple RPG Maker MZ assets in batch", inputSchema: { type: "object", properties: { requests: { type: "array", description: "Array of asset generation requests", items: { type: "object", properties: { project_path: { type: "string" }, asset_type: { type: "string" }, prompt: { type: "string" }, filename: { type: "string" }, api_key: { type: "string" }, }, }, }, }, required: ["requests"], }, }, { name: "describe_asset", description: "Analyze and describe an existing RPG Maker MZ asset using Gemini 2.5 Flash", inputSchema: { type: "object", properties: { project_path: { type: "string", description: "Path to the RPG Maker MZ project directory", }, asset_type: { type: "string", description: "Type of asset", }, filename: { type: "string", description: "Filename of the asset to analyze", }, api_key: { type: "string", description: "Gemini API key (optional)", }, }, required: ["project_path", "asset_type", "filename"], }, }, { name: "generate_scenario", description: "Generate a complete RPG game scenario using Gemini AI (story, maps, characters, events, items)", inputSchema: { type: "object", properties: { project_path: { type: "string", description: "Path to the RPG Maker MZ project directory", }, theme: { type: "string", description: "Theme or genre of the game (e.g., 'fantasy adventure', 'sci-fi', 'horror')", }, style: { type: "string", description: "Style or tone (e.g., 'lighthearted', 'dark', 'comedic', 'epic')", }, length: { type: "string", enum: ["short", "medium", "long"], description: "Length of the game scenario", }, api_key: { type: "string", description: "Gemini API key (optional)", }, }, required: ["project_path", "theme", "style", "length"], }, }, { name: "implement_scenario", description: "Implement a generated scenario into the RPG Maker MZ project", inputSchema: { type: "object", properties: { project_path: { type: "string", description: "Path to the RPG Maker MZ project directory", }, scenario: { type: "object", description: "Generated scenario object", }, }, required: ["project_path", "scenario"], }, }, { name: "generate_and_implement_scenario", description: "Generate and immediately implement a complete RPG scenario (all-in-one)", inputSchema: { type: "object", properties: { project_path: { type: "string", description: "Path to the RPG Maker MZ project directory", }, theme: { type: "string", description: "Theme or genre of the game", }, style: { type: "string", description: "Style or tone", }, length: { type: "string", enum: ["short", "medium", "long"], description: "Length of the game scenario", }, api_key: { type: "string", description: "Gemini API key (optional)", }, }, required: ["project_path", "theme", "style", "length"], }, }, { name: "generate_scenario_variations", description: "Generate multiple variations of a scenario for comparison", inputSchema: { type: "object", properties: { project_path: { type: "string", description: "Path to the RPG Maker MZ project directory", }, theme: { type: "string", description: "Theme or genre", }, style: { type: "string", description: "Style or tone", }, length: { type: "string", enum: ["short", "medium", "long"], description: "Length of scenarios", }, count: { type: "number", description: "Number of variations to generate", }, api_key: { type: "string", description: "Gemini API key (optional)", }, }, required: ["project_path", "theme", "style", "length", "count"], }, }, { name: "autonomous_create_game", description: "Autonomously create a complete RPG game from a concept. This tool orchestrates all game creation steps: project setup, scenario generation, battle system, quests, assets, balancing, and optimization. Perfect for rapid game prototyping with minimal input.", inputSchema: { type: "object", properties: { project_path: { type: "string", description: "Path where the game project will be created", }, concept: { type: "string", description: "Game concept/theme (e.g., 'fantasy adventure with dragons', 'cyberpunk detective story', 'space opera epic')", }, game_title: { type: "string", description: "Game title (auto-generated from concept if not provided)", }, length: { type: "string", enum: ["short", "medium", "long"], description: "Game length - short: 1-2hrs, medium: 3-5hrs, long: 8-12hrs", }, difficulty: { type: "string", enum: ["easy", "normal", "hard"], description: "Game difficulty level", }, generate_assets: { type: "boolean", description: "Whether to generate game assets using AI (default: true)", }, asset_count: { type: "object", properties: { characters: { type: "number", description: "Number of character sprites to generate", }, enemies: { type: "number", description: "Number of enemy sprites to generate", }, tilesets: { type: "number", description: "Number of tilesets to generate", }, }, description: "Asset generation counts", }, optimize: { type: "boolean", description: "Whether to optimize the project after creation (default: true)", }, api_key: { type: "string", description: "Gemini API key (optional, uses GEMINI_API_KEY env var if not provided)", }, }, required: ["project_path", "concept"], }, }, { name: "register_resource", description: "Register a resource (template, asset, data) for reuse across the project", inputSchema: { type: "object", properties: { project_path: { type: "string", description: "Project path" }, resource_id: { type: "string", description: "Unique resource ID" }, resource_type: { type: "string", enum: ["template", "asset", "scenario", "data", "custom"], description: "Resource type" }, name: { type: "string", description: "Resource name" }, description: { type: "string", description: "Resource description" }, content: { type: "object", description: "Resource content (any JSON data)" }, tags: { type: "array", items: { type: "string" }, description: "Tags for categorization" }, }, required: ["project_path", "resource_id", "resource_type", "name", "content"], }, }, { name: "register_prompt_template", description: "Register a reusable prompt template with variable placeholders and resource references", inputSchema: { type: "object", properties: { project_path: { type: "string", description: "Project path" }, prompt_id: { type: "string", description: "Unique prompt ID" }, name: { type: "string", description: "Prompt name" }, description: { type: "string", description: "Prompt description" }, template: { type: "string", description: "Prompt template with {{variable}} placeholders" }, variables: { type: "array", items: { type: "string" }, description: "List of variable names" }, resource_refs: { type: "array", items: { type: "string" }, description: "Referenced resource IDs" }, }, required: ["project_path", "prompt_id", "name", "template", "variables"], }, }, { name: "execute_prompt", description: "Execute a prompt template with provided variables and resource references", inputSchema: { type: "object", properties: { project_path: { type: "string", description: "Project path" }, prompt_id: { type: "string", description: "Prompt template ID" }, variables: { type: "object", description: "Variables to fill in the template" }, }, required: ["project_path", "prompt_id", "variables"], }, }, { name: "list_resources", description: "List all registered resources with optional filtering", inputSchema: { type: "object", properties: { project_path: { type: "string", description: "Project path" }, type: { type: "string", description: "Filter by resource type" }, tags: { type: "array", items: { type: "string" }, description: "Filter by tags" }, }, required: ["project_path"], }, }, { name: "search_database", description: "Search game database (actors, enemies, skills, items, etc.) with filters", inputSchema: { type: "object", properties: { project_path: { type: "string", description: "Project path" }, types: { type: "array", items: { type: "string" }, description: "Database types to search" }, name_contains: { type: "string", description: "Filter by name containing text" }, id_min: { type: "number", description: "Minimum ID" }, id_max: { type: "number", description: "Maximum ID" }, }, required: ["project_path"], }, }, { name: "analyze_assets", description: "Analyze all project assets, detect usage, find unused assets, and generate optimization recommendations", inputSchema: { type: "object", properties: { project_path: { type: "string", description: "Project path" }, }, required: ["project_path"], }, }, ], }; }); // Handle tool calls server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; try { switch (name) { case "list_projects": { const searchDir = (args?.directory as string) || path.join(process.env.HOME!, "Documents"); const entries = await fs.readdir(searchDir, { withFileTypes: true }); const projects = []; for (const entry of entries) { if (entry.isDirectory()) { const projectFile = path.join(searchDir, entry.name, "Game.rpgproject"); try { await fs.access(projectFile); projects.push({ name: entry.name, path: path.join(searchDir, entry.name), }); } catch { // Not an RPG Maker project } } } return { content: [ { type: "text", text: JSON.stringify(projects, null, 2), }, ], }; } case "read_project_info": { const projectPath = args.project_path as string; const projectFile = path.join(projectPath, "Game.rpgproject"); const content = await fs.readFile(projectFile, "utf-8"); return { content: [ { type: "text", text: content, }, ], }; } case "list_maps": { const projectPath = args.project_path as string; const mapsFile = path.join(projectPath, "data", "MapInfos.json"); const content = await fs.readFile(mapsFile, "utf-8"); const maps = JSON.parse(content); return { content: [ { type: "text", text: JSON.stringify(maps, null, 2), }, ], }; } case "read_map": { const projectPath = args.project_path as string; const mapId = args.map_id as string; const mapFile = path.join(projectPath, "data", `${mapId}.json`); const content = await fs.readFile(mapFile, "utf-8"); return { content: [ { type: "text", text: content, }, ], }; } case "list_plugins": { const projectPath = args.project_path as string; const pluginsDir = path.join(projectPath, "js", "plugins"); const pluginsFile = path.join(pluginsDir, "..", "plugins.js"); let plugins = []; try { const content = await fs.readFile(pluginsFile, "utf-8"); plugins.push({ type: "config", file: "plugins.js", content }); } catch { // No plugins.js file } const files = await fs.readdir(pluginsDir); const pluginFiles = files.filter((f) => f.endsWith(".js")); return { content: [ { type: "text", text: JSON.stringify({ plugins, pluginFiles }, null, 2), }, ], }; } case "generate_project_context": { const projectPath = args.project_path as string; const includeMaps = args.include_maps !== false; const includeEvents = args.include_events !== false; const includePlugins = args.include_plugins !== false; let context = "# RPG Maker MZ Project Context\n\n"; // Project info try { const projectFile = path.join(projectPath, "Game.rpgproject"); const projectContent = await fs.readFile(projectFile, "utf-8"); context += "## Project Information\n```\n" + projectContent + "\n```\n\n"; } catch (e) { context += "## Project Information\nUnavailable\n\n"; } // System data try { const systemFile = path.join(projectPath, "data", "System.json"); const systemContent = await fs.readFile(systemFile, "utf-8"); const system = JSON.parse(systemContent); context += "## System Settings\n"; context += `- Game Title: ${system.gameTitle}\n`; context += `- Version: ${system.versionId || "N/A"}\n\n`; } catch (e) { // Skip if unavailable } // Maps if (includeMaps) { try { const mapsFile = path.join(projectPath, "data", "MapInfos.json"); const mapsContent = await fs.readFile(mapsFile, "utf-8"); const maps = JSON.parse(mapsContent); context += "## Maps\n"; for (const [id, mapInfo] of Object.entries(maps)) { if (mapInfo && typeof mapInfo === "object" && "name" in mapInfo) { context += `- Map ${id}: ${mapInfo.name}\n`; if (includeEvents) { try { const mapFile = path.join(projectPath, "data", `Map${String(id).padStart(3, "0")}.json`); const mapContent = await fs.readFile(mapFile, "utf-8"); const mapData = JSON.parse(mapContent); const eventCount = mapData.events?.filter((e: any) => e !== null).length || 0; context += ` - Events: ${eventCount}\n`; } catch { // Skip if map file unavailable } } } } context += "\n"; } catch (e) { context += "## Maps\nUnavailable\n\n"; } } // Plugins if (includePlugins) { try { const pluginsDir = path.join(projectPath, "js", "plugins"); const files = await fs.readdir(pluginsDir); const pluginFiles = files.filter((f) => f.endsWith(".js")); context += "## Plugins\n"; for (const plugin of pluginFiles) { context += `- ${plugin}\n`; } context += "\n"; } catch (e) { context += "## Plugins\nUnavailable\n\n"; } } return { content: [ { type: "text", text: context, }, ], }; } case "analyze_project_structure": { const projectPath = args.project_path as string; let analysis = "# Project Structure Analysis\n\n"; try { const mapsFile = path.join(projectPath, "data", "MapInfos.json"); const mapsContent = await fs.readFile(mapsFile, "utf-8"); const maps = JSON.parse(mapsContent); const mapCount = Object.values(maps).filter((m) => m !== null).length; analysis += `## Overview\n- Total Maps: ${mapCount}\n\n`; analysis += "## Map Hierarchy\n"; for (const [id, mapInfo] of Object.entries(maps)) { if (mapInfo && typeof mapInfo === "object" && "name" in mapInfo) { const parentId = "parentId" in mapInfo ? mapInfo.parentId : 0; const indent = parentId === 0 ? "" : " "; analysis += `${indent}- ${mapInfo.name} (ID: ${id})\n`; } } analysis += "\n"; // Event analysis let totalEvents = 0; const eventsByMap: Record<string, number> = {}; for (const [id, mapInfo] of Object.entries(maps)) { if (mapInfo && typeof mapInfo === "object" && "name" in mapInfo) { try { const mapFile = path.join(projectPath, "data", `Map${String(id).padStart(3, "0")}.json`); const mapContent = await fs.readFile(mapFile, "utf-8"); const mapData = JSON.parse(mapContent); const eventCount = mapData.events?.filter((e: any) => e !== null).length || 0; totalEvents += eventCount; if (eventCount > 0) { eventsByMap[mapInfo.name as string] = eventCount; } } catch { // Skip } } } analysis += `## Event Statistics\n- Total Events: ${totalEvents}\n\n`; if (Object.keys(eventsByMap).length > 0) { analysis += "### Events by Map\n"; for (const [mapName, count] of Object.entries(eventsByMap)) { analysis += `- ${mapName}: ${count} events\n`; } } } catch (e) { analysis += "Error analyzing project structure\n"; } return { content: [ { type: "text", text: analysis, }, ], }; } case "extract_game_design_patterns": { const projectPath = args.project_path as string; let patterns = "# Game Design Patterns\n\n"; try { const mapsFile = path.join(projectPath, "data", "MapInfos.json"); const mapsContent = await fs.readFile(mapsFile, "utf-8"); const maps = JSON.parse(mapsContent); const eventPatterns: Record<string, number> = {}; const commonEventCommands: Record<string, number> = {}; for (const [id, mapInfo] of Object.entries(maps)) { if (mapInfo && typeof mapInfo === "object" && "name" in mapInfo) { try { const mapFile = path.join(projectPath, "data", `Map${String(id).padStart(3, "0")}.json`); const mapContent = await fs.readFile(mapFile, "utf-8"); const mapData = JSON.parse(mapContent); if (mapData.events) { for (const event of mapData.events) { if (event && event.pages) { for (const page of event.pages) { if (page.list) { for (const command of page.list) { const cmdCode = command.code; commonEventCommands[cmdCode] = (commonEventCommands[cmdCode] || 0) + 1; } } } } } } } catch { // Skip } } } patterns += "## Common Event Commands\n"; const sortedCommands = Object.entries(commonEventCommands) .sort(([, a], [, b]) => b - a) .slice(0, 10); for (const [code, count] of sortedCommands) { patterns += `- Command ${code}: ${count} occurrences\n`; } } catch (e) { patterns += "Error extracting patterns\n"; } return { content: [ { type: "text", text: patterns, }, ], }; } case "create_project": { const projectPath = args.project_path as string; const gameTitle = args.game_title as string; const result = await createNewProject(projectPath, gameTitle); return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }], }; } case "create_map": { const projectPath = args.project_path as string; const mapId = args.map_id as number; const name = args.name as string; const width = (args.width as number) || 17; const height = (args.height as number) || 13; const result = await createMap(projectPath, mapId, name, width, height); return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }], }; } case "update_map_tile": { const projectPath = args.project_path as string; const mapId = args.map_id as number; const x = args.x as number; const y = args.y as number; const layer = args.layer as number; const tileId = args.tile_id as number; const result = await updateMapTile(projectPath, mapId, x, y, layer, tileId); return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }], }; } case "add_event": { const projectPath = args.project_path as string; const mapId = args.map_id as number; const eventId = args.event_id as number; const name = args.name as string; const x = args.x as number; const y = args.y as number; const result = await addEvent(projectPath, mapId, eventId, name, x, y); return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }], }; } case "add_event_command": { const projectPath = args.project_path as string; const mapId = args.map_id as number; const eventId = args.event_id as number; const pageIndex = args.page_index as number; const code = args.code as number; const parameters = args.parameters as any[]; const command = { code, indent: 0, parameters }; const result = await addEventCommand(projectPath, mapId, eventId, pageIndex, command); return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }], }; } case "add_actor": { const projectPath = args.project_path as string; const id = args.id as number; const name = args.name as string; const result = await addActor(projectPath, id, name); return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }], }; } case "add_class": { const projectPath = args.project_path as string; const id = args.id as number; const name = args.name as string; const result = await addClass(projectPath, id, name); return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }], }; } case "add_skill": { const projectPath = args.project_path as string; const id = args.id as number; const name = args.name as string; const result = await addSkill(projectPath, id, name); return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }], }; } case "add_item": { const projectPath = args.project_path as string; const id = args.id as number; const name = args.name as string; const result = await addItem(projectPath, id, name); return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }], }; } case "update_database": { const projectPath = args.project_path as string; const database = args.database as string; const id = args.id as number; const updates = args.updates as any; const result = await updateDatabase(projectPath, database, id, updates); return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }], }; } case "generate_asset": { const request: AssetGenerationRequest = { projectPath: args.project_path as string, assetType: args.asset_type as any, prompt: args.prompt as string, filename: args.filename as string, apiKey: args.api_key as string | undefined, }; const result = await generateAssetWithGemini(request); return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }], }; } case "generate_asset_batch": { const requests = args.requests as AssetGenerationRequest[]; const results = await generateAssetBatch(requests); return { content: [{ type: "text", text: JSON.stringify(results, null, 2) }], }; } case "describe_asset": { const projectPath = args.project_path as string; const assetType = args.asset_type as string; const filename = args.filename as string; const apiKey = args.api_key as string | undefined; const result = await describeAsset(projectPath, assetType, filename, apiKey); return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }], }; } case "generate_scenario": { const request: ScenarioGenerationRequest = { projectPath: args.project_path as string, theme: args.theme as string, style: args.style as string, length: args.length as "short" | "medium" | "long", apiKey: args.api_key as string | undefined, }; const result = await generateScenarioWithGemini(request); return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }], }; } case "implement_scenario": { const projectPath = args.project_path as string; const scenario = args.scenario as any; const result = await implementScenario(projectPath, scenario); return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }], }; } case "generate_and_implement_scenario": { const request: ScenarioGenerationRequest = { projectPath: args.project_path as string, theme: args.theme as string, style: args.style as string, length: args.length as "short" | "medium" | "long", apiKey: args.api_key as string | undefined, }; const result = await generateAndImplementScenario(request); return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }], }; } case "generate_scenario_variations": { const request: ScenarioGenerationRequest = { projectPath: args.project_path as string, theme: args.theme as string, style: args.style as string, length: args.length as "short" | "medium" | "long", apiKey: args.api_key as string | undefined, }; const count = args.count as number; const results = await generateScenarioVariations(request, count); return { content: [{ type: "text", text: JSON.stringify(results, null, 2) }], }; } case "autonomous_create_game": { const request: AutonomousCreationRequest = { projectPath: args.project_path as string, concept: args.concept as string, gameTitle: args.game_title as string | undefined, length: (args.length as "short" | "medium" | "long") || "medium", difficulty: (args.difficulty as "easy" | "normal" | "hard") || "normal", generateAssets: args.generate_assets !== false, assetCount: args.asset_count as any, optimize: args.optimize !== false, }; const result = await createGameAutonomously(request); if (result.success) { let report = `🎉 Game creation completed successfully!\n\n`; report += `📁 Project: ${result.projectPath}\n\n`; if (result.summary) { report += `📊 Summary:\n`; report += ` 🗺️ Maps: ${result.summary.totalMaps}\n`; report += ` 👤 Actors: ${result.summary.totalActors}\n`; report += ` 👹 Enemies: ${result.summary.totalEnemies}\n`; report += ` 📍 Events: ${result.summary.totalEvents}\n`; report += ` 🎯 Quests: ${result.summary.totalQuests}\n`; report += ` 🎨 Assets: ${result.summary.assetsGenerated}\n`; report += ` 💾 Size: ${result.summary.projectSize}\n`; report += ` ⏳ Playtime: ${result.summary.estimatedPlaytime}\n\n`; } if (result.steps) { report += `\n📋 Creation Steps:\n`; for (const step of result.steps) { const icon = step.status === "success" ? "✅" : step.status === "failed" ? "❌" : "⏭️"; report += `${icon} ${step.step}\n`; if (step.error) { report += ` Error: ${step.error}\n`; } } } report += `\n✨ Open with RPG Maker MZ: ${path.join(result.projectPath!, "Game.rpgproject")}`; return { content: [{ type: "text", text: report }], }; } else { return { content: [{ type: "text", text: `❌ Game creation failed: ${result.error}` }], isError: true, }; } } case "register_resource": { const result = await registerResource(args.project_path as string, { id: args.resource_id as string, type: args.resource_type as any, name: args.name as string, description: args.description as string, content: args.content as any, metadata: { tags: args.tags as string[] } }); return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }], }; } case "register_prompt_template": { const result = await registerPromptTemplate(args.project_path as string, { id: args.prompt_id as string, name: args.name as string, description: args.description as string, template: args.template as string, variables: args.variables as string[], resourceRefs: args.resource_refs as string[] }); return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }], }; } case "execute_prompt": { const result = await executePrompt( args.project_path as string, args.prompt_id as string, args.variables as Record<string, any> ); return { content: [{ type: "text", text: result.success ? result.prompt! : `Error: ${result.error}` }], }; } case "list_resources": { const result = await listResources(args.project_path as string, { type: args.type as any, tags: args.tags as string[] }); return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }], }; } case "search_database": { const result = await searchDatabase(args.project_path as string, { type: args.types as string[], nameContains: args.name_contains as string, idRange: { min: args.id_min as number, max: args.id_max as number } }); return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }], }; } case "analyze_assets": { const result = await generateAssetContext(args.project_path as string); return { content: [{ type: "text", text: result.success ? result.context! : `Error: ${result.error}` }], }; } default: throw new Error(`Unknown tool: ${name}`); } } catch (error) { return { content: [ { type: "text", text: `Error: ${error instanceof Error ? error.message : String(error)}`, }, ], isError: true, }; } }); // Start the server async function main() { try { await Logger.info("Starting RPG Maker MZ MCP Server"); const transport = new StdioServerTransport(); await server.connect(transport); console.error("RPG Maker MZ MCP Server running on stdio"); await Logger.info("Server started successfully"); } catch (error) { await Logger.error("Failed to start server", { error }); throw error; } } main().catch(async (error) => { console.error("Server error:", error); await Logger.error("Server crashed", { error: error instanceof Error ? error.message : String(error), stack: error instanceof Error ? error.stack : undefined }); process.exit(1); });

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