system
Manage in-game elements like scoreboards, screen displays, and player interfaces in Minecraft Bedrock. Organize objectives, display titles, action bars, and sequences to enhance gameplay and server interactions.
Instructions
System features: scoreboards, screen displays (titles, action bars), player UI, game management
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| action | Yes | Action to perform within the category | |
| category | Yes | System category to use | |
| display_name | No | Display name for objective | |
| display_slot | No | Display slot for scoreboard | |
| fade_in | No | Fade in duration in ticks (default: 10) | |
| fade_out | No | Fade out duration in ticks (default: 20) | |
| message | No | Action bar message | |
| objective_id | No | Scoreboard objective ID | |
| player_name | No | Target player name (optional, defaults to local player) | |
| score | No | Score value | |
| sort_order | No | Sort order for scoreboard | |
| stay | No | Stay duration in ticks (default: 70) | |
| steps | No | Array of system actions for sequence. Each step should have "category" and "action" fields and relevant parameters. | |
| subtitle | No | Subtitle text | |
| title | No | Title text |
Implementation Reference
- src/tools/core/system.ts:104-148 (handler)Main handler function 'execute' that dispatches 'system' tool operations based on category: scoreboard, screen, or sequence.async execute(args: { category: string; action: string; objective_id?: string; display_name?: string; player_name?: string; score?: number; display_slot?: string; sort_order?: string; title?: string; subtitle?: string; message?: string; fade_in?: number; stay?: number; fade_out?: number; steps?: SequenceStep[]; }): Promise<ToolCallResult> { if (!this.world) { return { success: false, message: 'World not available for system operations.' }; } try { const { category, action } = args; switch (category) { case 'scoreboard': return await this.executeScoreboardOperation(action, args); case 'screen': return await this.executeScreenOperation(action, args); case 'sequence': if (!args.steps) { return this.createErrorResponse('steps array is required for sequence category'); } return await this.executeSequence(args.steps as SequenceStep[]); default: return { success: false, message: `Unknown category: ${category}. Use: scoreboard, screen, sequence` }; } } catch (error) { return { success: false, message: `System operation error: ${error instanceof Error ? error.message : String(error)}` }; } }
- src/tools/core/system.ts:12-85 (schema)Input schema defining parameters for categories (scoreboard, screen, sequence) and their actions.readonly inputSchema: InputSchema = { type: 'object', properties: { category: { type: 'string', description: 'System category to use', enum: ['scoreboard', 'screen', 'sequence'] }, action: { type: 'string', description: 'Action to perform within the category' }, // Scoreboard parameters objective_id: { type: 'string', description: 'Scoreboard objective ID' }, display_name: { type: 'string', description: 'Display name for objective' }, player_name: { type: 'string', description: 'Target player name (optional, defaults to local player)' }, score: { type: 'number', description: 'Score value' }, display_slot: { type: 'string', description: 'Display slot for scoreboard', enum: ['sidebar', 'list', 'belowname'] }, sort_order: { type: 'string', description: 'Sort order for scoreboard', enum: ['ascending', 'descending'] }, // Screen display parameters title: { type: 'string', description: 'Title text' }, subtitle: { type: 'string', description: 'Subtitle text' }, message: { type: 'string', description: 'Action bar message' }, fade_in: { type: 'number', description: 'Fade in duration in ticks (default: 10)', default: 10 }, stay: { type: 'number', description: 'Stay duration in ticks (default: 70)', default: 70 }, fade_out: { type: 'number', description: 'Fade out duration in ticks (default: 20)', default: 20 }, steps: { type: 'array', description: 'Array of system actions for sequence. Each step should have "category" and "action" fields and relevant parameters.' } }, required: ['category', 'action'] };
- src/tools/core/system.ts:150-240 (handler)Handler for scoreboard operations including create/edit/delete objectives, set/get scores, display settings.private async executeScoreboardOperation(action: string, args: any): Promise<ToolCallResult> { const scoreboard = this.world!.scoreboard; let result: any; let message: string; switch (action) { case 'list_objectives': result = await scoreboard.getObjectives(); message = 'Scoreboard objectives listed'; break; case 'create_objective': if (!args.objective_id) return { success: false, message: 'objective_id required for create_objective' }; result = await scoreboard.addObjective(args.objective_id, args.display_name); message = `Objective ${args.objective_id} created`; break; case 'remove_objective': if (!args.objective_id) return { success: false, message: 'objective_id required for remove_objective' }; result = await scoreboard.removeObjective(args.objective_id); message = `Objective ${args.objective_id} removed`; break; case 'get_score': if (!args.objective_id) return { success: false, message: 'objective_id required for get_score' }; const targetForGet = args.player_name || this.world!.localPlayer?.name; if (!targetForGet) return { success: false, message: 'No player available' }; result = await scoreboard.getScore(targetForGet, args.objective_id); message = `Score retrieved for ${targetForGet} in ${args.objective_id}: ${result}`; break; case 'set_score': if (!args.objective_id || args.score === undefined) { return { success: false, message: 'objective_id and score required for set_score' }; } const targetForSet = args.player_name || this.world!.localPlayer?.name; if (!targetForSet) return { success: false, message: 'No player available' }; result = await scoreboard.setScore(targetForSet, args.objective_id, args.score); message = `Score set to ${args.score} for ${targetForSet} in ${args.objective_id}`; break; case 'add_score': if (!args.objective_id || args.score === undefined) { return { success: false, message: 'objective_id and score required for add_score' }; } const targetForAdd = args.player_name || this.world!.localPlayer?.name; if (!targetForAdd) return { success: false, message: 'No player available' }; result = await scoreboard.addScore(targetForAdd, args.objective_id, args.score); message = `Added ${args.score} to ${targetForAdd} in ${args.objective_id}`; break; case 'remove_score': if (!args.objective_id || args.score === undefined) { return { success: false, message: 'objective_id and score required for remove_score' }; } const targetForRemove = args.player_name || this.world!.localPlayer?.name; if (!targetForRemove) return { success: false, message: 'No player available' }; result = await scoreboard.removeScore(targetForRemove, args.objective_id, args.score); message = `Removed ${args.score} from ${targetForRemove} in ${args.objective_id}`; break; case 'reset_score': const targetForReset = args.player_name || this.world!.localPlayer?.name; if (!targetForReset) return { success: false, message: 'No player available' }; await scoreboard.resetScore(targetForReset, args.objective_id); message = `Score reset for ${targetForReset}`; break; case 'set_display': if (!args.display_slot) return { success: false, message: 'display_slot required for set_display' }; await scoreboard.setDisplay(args.display_slot as any, args.objective_id, args.sort_order as any); message = `Display set for ${args.display_slot}`; break; case 'get_all_scores': const targetForAll = args.player_name || this.world!.localPlayer?.name; if (!targetForAll) return { success: false, message: 'No player available' }; result = await scoreboard.getScores(targetForAll); message = `All scores retrieved for ${targetForAll}`; break; default: return { success: false, message: `Unknown scoreboard action: ${action}` }; } return { success: true, message: message, data: { category: 'scoreboard', action, result, timestamp: Date.now() } }; }
- src/tools/core/system.ts:242-327 (handler)Handler for screen display operations like titles, subtitles, action bars with fade timings.private async executeScreenOperation(action: string, args: any): Promise<ToolCallResult> { // Get target player let player = this.world!.localPlayer; if (args.player_name) { const players = await this.world!.getPlayers(); const targetPlayer = players.find(p => p.name === args.player_name); if (!targetPlayer) { return { success: false, message: `Player ${args.player_name} not found` }; } player = targetPlayer; } // Null check for player if (!player) { return { success: false, message: 'No player available' }; } const screen = player.onScreenDisplay; let message: string; let result: any; switch (action) { case 'show_title': if (!args.title) return { success: false, message: 'title required for show_title' }; const titleOptions = { subtitle: args.subtitle, times: { fadeIn: args.fade_in || 10, stay: args.stay || 70, fadeOut: args.fade_out || 20 } }; await screen.setTitle(args.title, titleOptions); message = `Title displayed to ${player.name}: "${args.title}"`; if (args.subtitle) message += ` with subtitle: "${args.subtitle}"`; break; case 'update_subtitle': if (!args.subtitle) return { success: false, message: 'subtitle required for update_subtitle' }; await screen.updateSubtitle(args.subtitle); message = `Subtitle updated for ${player.name}: "${args.subtitle}"`; break; case 'show_action_bar': if (!args.message) return { success: false, message: 'message required for show_action_bar' }; await screen.setActionBar(args.message); message = `Action bar shown to ${player.name}: "${args.message}"`; break; case 'set_title_duration': if (args.fade_in === undefined || args.stay === undefined || args.fade_out === undefined) { return { success: false, message: 'fade_in, stay, and fade_out required for set_title_duration' }; } await screen.setTitleDuration({ fadeIn: args.fade_in, stay: args.stay, fadeOut: args.fade_out }); message = `Title duration set for ${player.name}: fadeIn=${args.fade_in}, stay=${args.stay}, fadeOut=${args.fade_out}`; break; case 'clear_title': await screen.clearTitle(); message = `Title cleared for ${player.name}`; break; case 'reset_title': await screen.resetTitle(); message = `Title reset for ${player.name}`; break; case 'check_screen_valid': result = screen.isValid; message = `Screen display validity checked for ${player.name}: ${result}`; break; default: return { success: false, message: `Unknown screen action: ${action}` }; } return { success: true, message: message, data: { category: 'screen', action, result, targetPlayer: player.name, timestamp: Date.now() } }; }
- src/server.ts:348-372 (registration)Instantiation of SystemTool in the tools array, which is later registered to MCP server.this.tools = [ // Socket-BE Core API ツール(推奨 - シンプルでAI使いやすい) new AgentTool(), new WorldTool(), new PlayerTool(), new BlocksTool(), new SystemTool(), new CameraTool(), new SequenceTool(), new MinecraftWikiTool(), // Advanced Building ツール(高レベル建築機能) new BuildCubeTool(), // ✅ 完全動作 new BuildLineTool(), // ✅ 完全動作 new BuildSphereTool(), // ✅ 完全動作 new BuildCylinderTool(), // ✅ 修正済み new BuildParaboloidTool(), // ✅ 基本動作 new BuildHyperboloidTool(), // ✅ 基本動作 new BuildRotateTool(), // ✅ 基本動作 new BuildTransformTool(), // ✅ 基本動作 new BuildTorusTool(), // ✅ 修正完了 new BuildHelixTool(), // ✅ 修正完了 new BuildEllipsoidTool(), // ✅ 修正完了 new BuildBezierTool(), // ✅ 新規追加(可変制御点ベジェ曲線) ];
- src/server.ts:30-30 (registration)Import of SystemTool class.import { SystemTool } from "./tools/core/system";
- src/server.ts:492-573 (registration)Generic registration loop that registers all tools including 'system' to the MCP server.const schemaConverter = new SchemaToZodConverter(); this.tools.forEach((tool) => { // inputSchemaをZod形式に変換(SchemaToZodConverterを使用) const zodSchema = schemaConverter.convert(tool.inputSchema); // ツールを登録 this.mcpServer.registerTool( tool.name, { title: tool.name, description: tool.description, inputSchema: zodSchema, }, async (args: any) => { try { const result = await tool.execute(args); let responseText: string; if (result.success) { // 建築ツールの場合は最適化 if (tool.name.startsWith('build_')) { const optimized = optimizeBuildResult(result); responseText = `✅ ${optimized.message}`; if (optimized.summary) { responseText += `\n\n📊 Summary:\n${JSON.stringify(optimized.summary, null, 2)}`; } } else { // 通常ツールの場合 responseText = result.message || `Tool ${tool.name} executed successfully`; if (result.data) { // データサイズチェック const dataStr = JSON.stringify(result.data, null, 2); const sizeWarning = checkResponseSize(dataStr); if (sizeWarning) { // 大きすぎる場合はデータタイプのみ表示 responseText += `\n\n${sizeWarning}`; responseText += `\nData type: ${Array.isArray(result.data) ? `Array[${result.data.length}]` : typeof result.data}`; } else { responseText += `\n\nData: ${dataStr}`; } } } } else { // エラーメッセージにヒントを追加 const errorMsg = result.message || "Tool execution failed"; const enrichedError = enrichErrorWithHints(errorMsg); responseText = `❌ ${enrichedError}`; if (result.data) { responseText += `\n\nDetails:\n${JSON.stringify(result.data, null, 2)}`; } } return { content: [ { type: "text", text: responseText, }, ], }; } catch (error) { const errorMsg = error instanceof Error ? error.message : String(error); const errorStack = error instanceof Error ? error.stack : undefined; const exceptionMessage = `Tool execution failed with exception: ${errorMsg}${errorStack ? `\n\nStack trace:\n${errorStack}` : ""}`; return { content: [ { type: "text", text: `❌ ${exceptionMessage}`, }, ], }; } } ); });