blocks
Perform block operations in Minecraft Bedrock, including placement, area filling, terrain queries, and surface detection, using coordinates and block IDs for precise world manipulation.
Instructions
Block operations: placement, area filling, terrain queries, single blocks, large areas, surface detection
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| action | Yes | Block operation to perform | |
| block_id | No | Block ID (e.g., minecraft:stone, minecraft:dirt, minecraft:air) | |
| mode | No | Block placement/fill mode | |
| steps | No | Array of block actions for sequence. Each step should have "type" field and relevant parameters. | |
| x | No | X coordinate | |
| x2 | No | Second X coordinate for area operations | |
| y | No | Y coordinate | |
| y2 | No | Second Y coordinate for area operations | |
| z | No | Z coordinate | |
| z2 | No | Second Z coordinate for area operations |
Implementation Reference
- src/tools/core/blocks.ts:62-197 (handler)The main execute method of BlocksTool that handles all 'blocks' tool actions: set_block, fill_area, get_top_solid_block, query_block_data, etc. This is the core handler logic.async execute(args: { action: string; x?: number; y?: number; z?: number; x2?: number; y2?: number; z2?: number; block_id?: string; mode?: string; steps?: SequenceStep[]; }): Promise<ToolCallResult> { if (!this.world) { return { success: false, message: 'World not available. Ensure Minecraft is connected.' }; } try { const { action } = args; let result: any; let message: string; switch (action) { case 'set_block': if (args.x === undefined || args.y === undefined || args.z === undefined || !args.block_id) { return { success: false, message: 'Coordinates (x,y,z) and block_id required for set_block' }; } if (!this.validateCoordinates(args.x, args.y, args.z)) { return { success: false, message: 'Invalid coordinates. Y must be between -64 and 320.' }; } const setOptions = args.mode && args.mode !== 'replace' ? { mode: args.mode as SetBlockMode } : undefined; await this.world.setBlock( { x: args.x, y: args.y, z: args.z }, this.normalizeBlockId(args.block_id), setOptions ); message = `Block ${args.block_id} set at (${args.x}, ${args.y}, ${args.z})`; if (args.mode && args.mode !== 'replace') { message += ` with mode: ${args.mode}`; } break; case 'fill_area': if (args.x === undefined || args.y === undefined || args.z === undefined || args.x2 === undefined || args.y2 === undefined || args.z2 === undefined || !args.block_id) { return { success: false, message: 'All coordinates (x,y,z,x2,y2,z2) and block_id required for fill_area' }; } if (!this.validateCoordinates(args.x, args.y, args.z) || !this.validateCoordinates(args.x2, args.y2, args.z2)) { return { success: false, message: 'Invalid coordinates. Y values must be between -64 and 320.' }; } // Calculate volume for safety check const volume = Math.abs(args.x2 - args.x + 1) * Math.abs(args.y2 - args.y + 1) * Math.abs(args.z2 - args.z + 1); if (volume > 32768) { return { success: false, message: `Area too large (${volume} blocks). Maximum is 32768 blocks.` }; } let fillOptions: any = undefined; if (args.mode && args.mode !== 'replace') { fillOptions = { mode: args.mode as FillBlocksMode }; } result = await this.world.fillBlocks( { x: args.x, y: args.y, z: args.z }, { x: args.x2, y: args.y2, z: args.z2 }, this.normalizeBlockId(args.block_id), fillOptions ); message = `Filled ${result} blocks with ${args.block_id} from (${args.x},${args.y},${args.z}) to (${args.x2},${args.y2},${args.z2})`; if (args.mode && args.mode !== 'replace') { message += ` with mode: ${args.mode}`; } break; case 'get_top_solid_block': const location = (args.x !== undefined && args.z !== undefined) ? { x: args.x, y: args.y || 320, z: args.z } : undefined; result = await this.world.getTopSolidBlock(location); if (location) { message = `Top solid block found at (${args.x}, ${result?.y || 'none'}, ${args.z})`; } else { message = 'Top solid block found at current location'; } break; case 'query_block_data': result = await this.world.queryData('block'); message = 'Block data retrieved'; break; case 'query_item_data': result = await this.world.queryData('item'); message = 'Item data retrieved'; break; case 'query_mob_data': result = await this.world.queryData('mob'); message = 'Mob data retrieved'; break; case 'sequence': if (!args.steps) { return this.createErrorResponse('steps array is required for sequence action'); } return await this.executeSequence(args.steps as SequenceStep[]); default: return { success: false, message: `Unknown action: ${action}` }; } return { success: true, message: message, data: { action, result, volume: result, timestamp: Date.now() } }; } catch (error) { return { success: false, message: `Block operation error: ${error instanceof Error ? error.message : String(error)}` }; } }
- src/tools/core/blocks.ts:13-45 (schema)Input schema definition for the 'blocks' tool, defining parameters like action, coordinates, block_id, mode, etc.readonly inputSchema: InputSchema = { type: 'object', properties: { action: { type: 'string', description: 'Block operation to perform', enum: [ 'set_block', 'fill_area', 'get_top_solid_block', 'query_block_data', 'query_item_data', 'query_mob_data', 'sequence' ] }, x: { type: 'number', description: 'X coordinate' }, y: { type: 'number', description: 'Y coordinate' }, z: { type: 'number', description: 'Z coordinate' }, x2: { type: 'number', description: 'Second X coordinate for area operations' }, y2: { type: 'number', description: 'Second Y coordinate for area operations' }, z2: { type: 'number', description: 'Second Z coordinate for area operations' }, block_id: { type: 'string', description: 'Block ID (e.g., minecraft:stone, minecraft:dirt, minecraft:air)' }, mode: { type: 'string', description: 'Block placement/fill mode', enum: ['replace', 'keep', 'destroy', 'hollow', 'outline'] }, steps: { type: 'array', description: 'Array of block actions for sequence. Each step should have "type" field and relevant parameters.' } }, required: ['action'] };
- src/server.ts:348-372 (registration)Instantiation of BlocksTool in the tools array during server initialization.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:494-573 (registration)Registration loop where BlocksTool (tool.name='blocks') is registered to the MCP server using registerTool.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}`, }, ], }; } } ); });
- src/tools/core/blocks.ts:209-219 (helper)Helper method for executing sequence steps specific to blocks tool.protected async executeSequenceStep(step: SequenceStep, index: number): Promise<ToolCallResult> { // wait ステップは基底クラスで処理される if (step.type === 'wait') { return await super.executeSequenceStep(step, index); } // ブロック特有のステップを実行 const blocksArgs = { action: step.type, ...step }; return await this.execute(blocksArgs); } }