Skip to main content
Glama

analyze_assets

Analyze project assets to detect usage, identify unused files, and generate optimization recommendations for RPG Maker MZ games.

Instructions

Analyze all project assets, detect usage, find unused assets, and generate optimization recommendations

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
project_pathYesProject path

Implementation Reference

  • Main tool handler: generates comprehensive asset analysis report including usage stats, unused assets, and optimization recommendations by calling analyzeProjectAssets and formatting as Markdown
    export async function generateAssetContext(projectPath: string): Promise<{ success: boolean; context?: string; error?: string }> { try { await Logger.info("Generating asset context", { projectPath }); const report = await analyzeProjectAssets(projectPath); let context = `# 🎨 アセットコンテキストレポート\n\n`; context += `**プロジェクト**: ${projectPath}\n`; context += `**生成日時**: ${new Date().toLocaleString("ja-JP")}\n\n`; context += `---\n\n`; // サマリー context += `## 📊 サマリー\n\n`; context += `- **総アセット数**: ${report.totalAssets}個\n`; context += `- **総サイズ**: ${report.totalSizeFormatted}\n`; context += `- **使用中**: ${report.assetsByUsage.used}個\n`; context += `- **未使用**: ${report.assetsByUsage.unused}個\n\n`; // タイプ別統計 context += `## 🗂️ タイプ別統計\n\n`; context += `| タイプ | 数量 |\n`; context += `|--------|------|\n`; for (const [type, count] of Object.entries(report.assetsByType)) { const icon = getTypeIcon(type); context += `| ${icon} ${type} | ${count} |\n`; } context += `\n`; // 使用状況詳細 context += `## 📋 使用状況詳細\n\n`; // 使用中のアセット const usedAssets = report.assets.filter(a => !a.isUnused); if (usedAssets.length > 0) { context += `### ✅ 使用中のアセット (${usedAssets.length}個)\n\n`; context += `| ファイル名 | タイプ | サイズ | 使用箇所 |\n`; context += `|-----------|--------|--------|----------|\n`; for (const asset of usedAssets.slice(0, 20)) { const usage = formatUsage(asset.usedBy); context += `| ${asset.filename} | ${asset.type} | ${asset.sizeFormatted} | ${usage} |\n`; } if (usedAssets.length > 20) { context += `\n*...他 ${usedAssets.length - 20}個*\n`; } context += `\n`; } // 未使用のアセット const unusedAssets = report.assets.filter(a => a.isUnused); if (unusedAssets.length > 0) { context += `### 🗑️ 未使用アセット (${unusedAssets.length}個)\n\n`; context += `| ファイル名 | タイプ | サイズ |\n`; context += `|-----------|--------|--------|\n`; for (const asset of unusedAssets.slice(0, 20)) { context += `| ${asset.filename} | ${asset.type} | ${asset.sizeFormatted} |\n`; } if (unusedAssets.length > 20) { context += `\n*...他 ${unusedAssets.length - 20}個*\n`; } context += `\n`; const unusedSize = unusedAssets.reduce((sum, a) => sum + a.size, 0); context += `💡 **未使用アセットを削除すると ${formatBytes(unusedSize)} 節約できます**\n\n`; } // 推奨事項 context += `## 💡 推奨事項\n\n`; for (const rec of report.recommendations) { context += `- ${rec}\n`; } context += `\n`; // 大きなファイル const largeAssets = report.assets .filter(a => a.size > 500 * 1024) .sort((a, b) => b.size - a.size) .slice(0, 10); if (largeAssets.length > 0) { context += `## 📦 最大ファイル (Top 10)\n\n`; context += `| ファイル名 | タイプ | サイズ | 使用状況 |\n`; context += `|-----------|--------|--------|----------|\n`; for (const asset of largeAssets) { const status = asset.isUnused ? "❌ 未使用" : "✅ 使用中"; context += `| ${asset.filename} | ${asset.type} | ${asset.sizeFormatted} | ${status} |\n`; } context += `\n`; } await Logger.info("Asset context generated", { totalAssets: report.totalAssets, used: report.assetsByUsage.used, unused: report.assetsByUsage.unused }); return { success: true, context }; } catch (error) { await Logger.error("Failed to generate asset context", { projectPath, error }); return { success: false, error: error instanceof Error ? error.message : String(error) }; } }
  • Core analysis logic: enumerates all assets in project directories, analyzes usage in database/map files, identifies unused assets
    export async function analyzeProjectAssets(projectPath: string): Promise<AssetContextReport> { await validateProjectPath(projectPath); await Logger.info("Analyzing project assets", { projectPath }); const assets: AssetInfo[] = []; const assetsByType: Record<string, number> = {}; // 画像アセット const imageTypes = [ { dir: "img/characters", type: "character" as const }, { dir: "img/faces", type: "face" as const }, { dir: "img/enemies", type: "enemy" as const }, { dir: "img/tilesets", type: "tileset" as const }, { dir: "img/battlebacks1", type: "battleback" as const }, { dir: "img/battlebacks2", type: "battleback" as const }, { dir: "img/sv_actors", type: "sv_actor" as const }, { dir: "img/pictures", type: "picture" as const }, ]; for (const { dir, type } of imageTypes) { const dirPath = path.join(projectPath, dir); try { const files = await fs.readdir(dirPath); for (const file of files) { if (file.match(/\.(png|jpg|jpeg)$/i)) { const filePath = path.join(dirPath, file); const stats = await fs.stat(filePath); const asset: AssetInfo = { filename: file, path: filePath, type, size: stats.size, sizeFormatted: formatBytes(stats.size), usedBy: {}, usageCount: 0, isUnused: true }; assets.push(asset); assetsByType[type] = (assetsByType[type] || 0) + 1; } } } catch (error) { // ディレクトリが存在しない場合はスキップ } } // 音声アセット const audioTypes = ["bgm", "bgs", "me", "se"]; for (const audioType of audioTypes) { const dirPath = path.join(projectPath, "audio", audioType); try { const files = await fs.readdir(dirPath); for (const file of files) { if (file.match(/\.(ogg|m4a|mp3)$/i)) { const filePath = path.join(dirPath, file); const stats = await fs.stat(filePath); const asset: AssetInfo = { filename: file, path: filePath, type: "audio", size: stats.size, sizeFormatted: formatBytes(stats.size), usedBy: {}, usageCount: 0, isUnused: true }; assets.push(asset); assetsByType["audio"] = (assetsByType["audio"] || 0) + 1; } } } catch (error) { // ディレクトリが存在しない場合はスキップ } } // 使用状況を分析 await analyzeAssetUsage(projectPath, assets); // 推奨事項を生成 const recommendations = generateRecommendations(assets); const totalSize = assets.reduce((sum, asset) => sum + asset.size, 0); const usedCount = assets.filter(a => !a.isUnused).length; const unusedCount = assets.filter(a => a.isUnused).length; await Logger.info("Asset analysis complete", { totalAssets: assets.length, used: usedCount, unused: unusedCount }); return { projectPath, totalAssets: assets.length, totalSize, totalSizeFormatted: formatBytes(totalSize), assetsByType, assetsByUsage: { used: usedCount, unused: unusedCount }, assets, recommendations }; }
  • src/index.ts:1461-1466 (registration)
    MCP tool handler dispatch: extracts project_path argument and calls generateAssetContext from asset-context
    case "analyze_assets": { const result = await generateAssetContext(args.project_path as string); return { content: [{ type: "text", text: result.success ? result.context! : `Error: ${result.error}` }], }; }
  • src/index.ts:810-819 (registration)
    Tool registration entry in ListTools response: defines name, description, and input schema
    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"], }, },
  • Type definition for the asset analysis report structure used by the handler functions
    export interface AssetContextReport { projectPath: string; totalAssets: number; totalSize: number; totalSizeFormatted: string; assetsByType: Record<string, number>; assetsByUsage: { used: number; unused: number; }; assets: AssetInfo[]; recommendations: string[]; }

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