レッドストーン回路の自動テストが失敗した際の切り分け・局所修正手順。CLI版の mc-cli get-blocks, interact-block, place-blocks を使ったデバッグ方法を定義する。
mc_mcp_test
test ツールと CircuitTest Python DSL の書き方。test を実行する前に start_session でセッションを開始し、その session_id を指定する。回路の自動テストを作成・実行する前に必ず読む。
含まれるファイル(1)
- SKILL.md14.9 KB
SKILL.md(原文)
インストールする前に、エージェントに与えられる指示の中身を確認できます。
Minecraft テスト実行 Skill
このスキルは、Minecraft MCPサーバーの test ツールを使用して、Python DSL(CircuitTest 基底クラス)で記述された *_test.py ファイルを実行し、ワールド内のレッドストーン回路やブロックの動作を自動検証するためのものです。
よくあるトラップ(必読)
テストコードを書く前に以下のトラップを把握し、フレームワーク/DSL誤用で5回の試行上限を枯渇させないこと。詳細は .agents/skills/tool_pitfalls/SKILL.md を参照。
setupのフェーズ配列:list[PlaceRequest]を渡す場合は各要素がPlaceRequestであること。dictのリストはNG('list' object has no attribute 'model_dump_json')。- 動的状態は書き込まない:
stateにpowered,lit,power,extended,enabled等の動的状態を明示するとブロック更新ループが壊れる。静的プロパティ(facing,delay,mode,face)のみ。 - フェーズ分離で BUD-lock 回避: ソース(レバー等)はデバイスより後のフェーズに分離。同じTickで配置するとリピーターがOFFのままロックされる。
- レバー/ボタンの
attachesは土台フェーズ後: 土台ブロックと同じフェーズで配置すると空中にレバーが置かれ設置失敗する。 interact_block後の待機: 操作後は必ずwait_ticks(2)以上待ってから観測。同期ズレで「操作が効いていない」と誤診しない。- アナログ信号は 5〜8 ブロック以内: アナログ経路にリピーターを置くと強度15に二値化される。アナログ回路内では置かない。
- facing は入力方向: repeater/comparator/observer は必ず
connectsで配置。直接blocksに手動facingは禁止。 clear_areaで自動 air クリア: テスト区域の bbox をCircuitTest.clear_area = [x1,y1,z1,x2,y2,z2]に設定すると、各テスト前に自動でminecraft:airクリアされる。setup内にair fillsを書く手間とミスを防ぐ。
推奨される setup のフェーズ配列例
単一 PlaceRequest ではなく、フェーズ配列 [PlaceRequest] を使うことで BUD-lock と空中レバーを同時に回避できる。
from mc_mcp_server.models import PlaceRequest, BlockData, AttachesData, ConnectsData
from mc_mcp_server.test_dsl import CircuitTest
class TestAndGate(CircuitTest):
# テスト区域を自動 air クリア(手動 air fills より安全)
clear_area = [8, 63, 8, 17, 66, 12]
setup = [
# フェーズ1: 土台・不透過ブロック
PlaceRequest(
blocks=[
BlockData(x=10, y=64, z=10, block="minecraft:stone"),
BlockData(x=12, y=64, z=10, block="minecraft:stone"),
BlockData(x=15, y=64, z=10, block="minecraft:redstone_lamp"),
],
),
# フェーズ2: レバー(土台フェーズ後)
PlaceRequest(
attaches=[
AttachesData(component="minecraft:lever", pos=[10, 65, 10], base=[10, 64, 10]),
AttachesData(component="minecraft:lever", pos=[12, 65, 10], base=[12, 64, 10]),
],
),
]
async def test_on_on(self):
await self.interact_block([10, 65, 10], target_state={"powered": "true"})
await self.interact_block([12, 65, 10], target_state={"powered": "true"})
await self.wait_ticks(4) # 同期ズレ回避のための待機
await self.assert_block(
15, 64, 10,
block="minecraft:redstone_lamp",
state={"lit": "true"},
)
プローブ時系列の活用
self.probe(name, pos) を使うと、1回の test 呼び出しで複数の観測点をまとめて取得できる。5回制限を本質デバッグに全振りするために積極的に活用する。
async def test_trace(self):
await self.interact_block([10, 65, 10], target_state={"powered": "true"})
await self.wait_ticks(2)
await self.probe("in_after", [11, 64, 10]) # 入力直後
await self.probe("mid", [13, 64, 10]) # 中間点
await self.probe("out", [15, 64, 10]) # 出力
await self.assert_block(15, 64, 10, block="minecraft:redstone_lamp", state={"lit": "true"})
# 結果の details に "probes" フィールドとして [in_after, mid, out] の時系列が同梱される
使用方法
テスト実行前に、必ず start_session でセッションを開始してください。
start_session はシステム側でUUIDを自動生成し、レスポンスの session_id で返します。
その後、test ツールを呼び出す際は、返された session_id を指定してください。
1. セッション開始
MCPツール start_session を呼び出します。セッションIDはシステム側で自動生成されるため、引数で指定する必要はありません。
引数
task_name: (任意) タスク名。
例
{
"task_name": "xor_gate_fix"
}
レスポンス例
{
"success": true,
"message": "セッション '550e8400-e29b-41d4-a716-446655440000' を開始しました",
"session_id": "550e8400-e29b-41d4-a716-446655440000",
"task_name": "xor_gate_fix"
}
以降の test 呼び出しでは、このレスポンスの session_id を使用してください。
2. テスト実行
MCPツール test を呼び出します。
[!WARNING]
testツールを実行する際は、必ずorigin引数(回路の起点となる絶対座標[x, y, z])を指定してください。originを省略すると、サーバー側でデフォルト値の[0, 0, 0]が使用され、テストコード内の相対座標が絶対座標として解釈されてしまい、回路の配置やテストが正しく動作しません(ワールドの高度限界外に配置されたり、動作が正常に検知できなくなったりします)。
引数
file_path: (必須)*_test.pyファイルの絶対パス。session_id: (必須)start_sessionが返したセッションID。origin: (必須) テスト時の起点となる絶対座標(例:[0, 1, 0])。必ず指定してください。
例
{
"file_path": "/tmp/.../xor_gate_test.py",
"session_id": "550e8400-e29b-41d4-a716-446655440000",
"origin": [0, 1, 0]
}
3. 実行上限に達した場合
1セッションあたり test は最大5回まで実行可能です。
6回目以降の test 呼び出しでは、以下のような応答が返ります。
{
"status": "test_limit_reached",
"session_id": "550e8400-...",
"test_count": 5,
"max_count": 5,
"message": "このセッションでの test 実行上限(5回)に達しました。修正を終了し、現状を報告してください。"
}
この応答を受け取ったら、直ちに修正作業を終了し、親エージェントに現状を報告してください。
これ以上のテスト実行、ブロック再配置、ファイル変更を行わないでください。
テストファイルの記述仕様(Python DSL)
ファイル命名規則
*_test.py で命名してください。
基本構造
from mc_mcp_server.models import PlaceRequest, BlockData, AttachesData
from mc_mcp_server.test_dsl import CircuitTest
class TestExample(CircuitTest):
# 宣言的な回路配置
setup = PlaceRequest(
blocks=[...],
attaches=[...],
)
async def test_xxx(self):
...
利用可能なメソッド
-
await self.interact_block(pos, target_state=None): 指定座標のブロックをインタラクトします。target_stateを指定すると、既に目標状態の場合は何もしません(冪等性)。 -
await self.wait_ticks(n): 指定ティック数(1tick = 50ms)待機します。 -
await self.wait_ms(ms): 指定ミリ秒数待機します。 -
await self.assert_block(x, y, z, block=..., state=...): 指定座標のブロックが期待値と一致することを検証します。 不一致の場合はAssertionFailure(構造化フィールド: 座標/期待block/期待state/実測block/実測state/reasons)を発生させます。テスト結果のfailuresに構造化データとして格納されます。 -
await self.get_block(x, y, z): 指定座標の BlockData を取得します。 -
await self.probe(name, pos): 観測点名付きでブロック状態を取得し、プローブ時系列に蓄積します。 1回のtest呼び出しで複数回呼ぶことで、すべての観測点を1つの結果にまとめて取得できます。結果のdetails[].probesに[{name, pos, block, state}]の時系列として同梱されます。5回制限を本質デバッグに全振りするために積極的に活用してください。 -
await self.place_blocks(request): PlaceRequest(またはフェーズ配列list[PlaceRequest])に基づいてブロックを配置します。
クラス変数
setup:PlaceRequest | list[PlaceRequest] | None。宣言的な回路配置。フェーズ配列を使うと BUD-lock 回避と空中レバー防止が同時にできる。reset_per_test:bool(デフォルトTrue)。各test_xxxメソッドの前にsetupを再配置する。clear_area:list[int] | None。[x1, y1, z1, x2, y2, z2]を設定すると、各テスト前にその範囲をminecraft:airで自動クリアする。setup内に air fills を書く手間とミスを防ぐ。
setup — 回路の配置
setup クラス変数に PlaceRequest を設定すると、テストクラスごとに自動で配置されます。
class TestAndGate(CircuitTest):
setup = PlaceRequest(
blocks=[
BlockData(x=10, y=64, z=10, block="minecraft:stone"),
],
attaches=[
AttachesData(
component="minecraft:lever",
pos=[10, 65, 10],
base=[10, 64, 10],
),
],
)
test_xxx — テストメソッド
test_ プレフィックスの async メソッドが順次実行されます。
インタラクトと待機
async def test_off_to_on(self):
await self.interact_block([10, 65, 10], target_state={"powered": "true"})
await self.wait_ticks(4)
await self.assert_block(
15, 64, 10,
block="minecraft:redstone_lamp",
state={"lit": "true"},
)
途中で追加配置が必要な場合
async def test_complex(self):
await self.place_blocks(PlaceRequest(
blocks=[BlockData(x=20, y=64, z=10, block="minecraft:stone")],
))
await self.wait_ticks(2)
await self.assert_block(20, 64, 10, block="minecraft:stone")
テストファイルの完全な例
from mc_mcp_server.models import PlaceRequest, BlockData, AttachesData
from mc_mcp_server.test_dsl import CircuitTest
class TestAndGate(CircuitTest):
setup = PlaceRequest(
blocks=[
BlockData(x=10, y=64, z=10, block="minecraft:stone"),
BlockData(x=12, y=64, z=10, block="minecraft:stone"),
BlockData(x=15, y=64, z=10, block="minecraft:redstone_lamp"),
],
attaches=[
AttachesData(
component="minecraft:lever",
pos=[10, 65, 10],
base=[10, 64, 10],
),
AttachesData(
component="minecraft:lever",
pos=[12, 65, 10],
base=[12, 64, 10],
),
],
)
async def test_off_off(self):
await self.interact_block([10, 65, 10], target_state={"powered": "false"})
await self.interact_block([12, 65, 10], target_state={"powered": "false"})
await self.wait_ms(200)
await self.assert_block(
15, 64, 10,
block="minecraft:redstone_lamp",
state={"lit": "false"},
)
async def test_on_on(self):
await self.interact_block([10, 65, 10], target_state={"powered": "true"})
await self.interact_block([12, 65, 10], target_state={"powered": "true"})
await self.wait_ms(200)
await self.assert_block(
15, 64, 10,
block="minecraft:redstone_lamp",
state={"lit": "true"},
)
出力サマリ
テストが完了すると、合格/不合格やエラーについてのサマリー情報がJSON形式で返されます。
{
"success": true,
"passed": 2,
"failed": 0,
"errors": 0,
"details": [
{
"name": "TestAndGate.test_off_off",
"status": "passed"
},
{
"name": "TestAndGate.test_on_on",
"status": "passed"
}
]
}
TIPS
waitの時間の目安: リピーター1段 ≒ 1tick、複数段の場合は段数 × 1tick 程度が安全です。setupはreset_per_test = True(デフォルト)の場合、各test_xxxメソッドの前に毎回再実行されます。- テストファイルは セッションごとの一時ディレクトリ 内の適切なサブディレクトリに保存するのが推奨です。
reset_per_test — テストケースごとの setup 再配置
CircuitTest には reset_per_test クラス変数があります。デフォルトは True で、各 test_xxx メソッドの実行前に setup を再配置します。これにより、テスト間の状態干渉を防ぎます。
class TestAndGate(CircuitTest):
reset_per_test = True # デフォルト値。各テスト前に setup を再配置
setup = PlaceRequest(
blocks=[...],
attaches=[...],
)
async def test_off_off(self):
...
async def test_on_on(self):
...
air クリアについて
reset_per_test = True を使う場合、setup 内にテスト区域を minecraft:air で埋める fills を含めてください。これにより、前回のテストで追加配置されたブロックや残った状態を確実にクリアできます。
setup = PlaceRequest(
fills=[
{
"start": [8, 63, 8],
"end": [17, 65, 12],
"block": "minecraft:air",
}
],
blocks=[...],
attaches=[...],
)
後方互換
reset_per_test = False を指定すると、従来の「setup をクラス全体で1回だけ実行」する挙動に戻ります。テスト間で意図的に状態を引き継ぎたい特殊な場合にのみ使用してください。
レビュー
まだレビューはありません。使ってみた感想をお寄せください。
同じリポジトリのスキル
概要と使いどころ
レッドストーン回路の自動テストが失敗した際の切り分け・局所修正手順。get_blocks, interact_block, place_blocks を使ったデバッグ方法を定義する。
agent 向けテキスト指示(skill / slash command / task プロンプト / CLAUDE.md 節 / コード生成プロンプト)を、バイアスを排した実行者に動かしてもらい、両面(実行者の自己申告 + 指示側メトリクス)で評価して反復改善する手法。改善が頭打ちになるまで回す。プロンプトや skill を新規作成・大幅改訂した直後、またはエージェントの挙動が期待通りにならない原因を指示側の曖昧さに求めたいときに使う。
Minecraft のレッドストーン回路や構造物を設計するための、JSON データモデルの仕様と設計ガイドラインです。
CLI版 mc-cli drop-items コマンドの使い方。ホッパーやコンテナに投入するアイテムを世界にドロップする時に読む。
CLI版 mc-cli fill コマンドの使い方。土台作成や範囲消去(air)を行う前に読む。