STEP 1533 — MCP tool Msg wrapping (STEP 1569 arc 2/3)
Counter drift note: 本 STEP claim 時に central STEP counter が rebase の副作用で reset されており (highest_claimed=1532 → my atomic claim = 1533)、 git history 上の highest = 1584 と drift。 STEP 番号 1533 だが narrative 上は STEP 1584 (SafetyGate) の続き 「STEP 1569 arc 2/3」。 counter 修復は auto-mode で block されたため sync ずれのまま (別 STEP で修復候補)。
目的
藤本さん directive「MCP server 全 tool の Msg wrapping (逐次 migration)」 応答。
rei-mcp-server.ts (3000+ 行、 他タブが編集中) を直接触るとリスク大なので、 wrapper factory + registry + 3 pilot tool で pattern を demonstrate、 逐次 opt-in migration 可能な形で提供。
Wrapper contract
interface WrappedToolMetadata {
name: string; // rei-mcp-server.ts の登録 name と一致
description: string;
declaredHazard: 'safe' | 'caution' | 'blocked';
originStep: number; // 元 tool の実装 STEP
protocolShape: 'single-verdict' | 'uniqueness-check' | 'uniqueness-necessity';
}
interface WrappedTool<Args, Result> {
meta: WrappedToolMetadata;
invoke: (args: Args) => Result | Promise<Result>;
makeCheckMsg(args): CheckMsg;
makeCallMsg(args, label?): CallMsg;
}
Wrapper が付与するもの
- PlanRunner との統合: toolHandler として registry 経由 dispatch
- SafetyGate pre-check: STEP 1584 rule catalog 経由 (declaredHazard + rule 双方適用)
- NoDataResult 自動検出: STEP 1571 の
isNoDataResultで trace flag 自動設定 - Protocol type conformance: STEP 1576 shape 継承 (compile-time check)
- Registry 逆引き: name → handler の O(1) lookup + duplicate detection
3 Pilot tool
| Wrapped tool | 原 STEP | Layer / hazard | Protocol shape |
|---|---|---|---|
wrappedDiskHealthVerdict | 1567 | Layer 1 sensor / caution | single-verdict |
wrappedShannonEntropyVerdict | 1499 | Layer 2 analytical / safe | single-verdict |
wrappedPuzzleVerify | 1536 | pure computation / safe | uniqueness-check |
3 pilot で hazard 2 tier (safe / caution) + protocol 2 shape をカバー。 mystery-reasoning-connector は別 tab 作物なので pilot 除外 (v0.2 candidate)。
Registry + wired runner
import { buildPilotRegistry } from './wrapped-tools';
import { createWiredRunner } from './msg-tool-wrapper';
import { productionGate } from './safety-gate';
const registry = buildPilotRegistry(); // 3 pilot 登録
const runner = createWiredRunner({ // PlanRunner + SafetyGate 統合
registry,
gate: productionGate(),
dryRun: false,
});
function* plan(): Plan {
yield* invokeWrappedTool(wrappedDiskHealthVerdict, { temperature: 40 });
yield* invokeWrappedTool(wrappedShannonEntropyVerdict, { frequencies: [3,3,3,3] });
yield* invokeWrappedTool(wrappedPuzzleVerify, {
toolName: 'disk_health_verdict', hiddenFields: [], expectedVerdict: 'TRUE'
});
}
const trace = await runner.run(plan());
// trace = 6 entries (3 pilot × [check, call] pair)
Migration guide (逐次 opt-in)
- Import 元 tool:
import { toolFn } from './tool-source' - wrapAsMsgTool: name / description / declaredHazard / originStep / protocolShape を宣言
- Registry 登録:
registry.register(wrappedTool) - rei-mcp-server.ts の case handler は変更不要 (wrapper と registry は別 layer で共存)
- plan 内で使用:
yield* invokeWrappedTool(wrappedTool, args, label?)
82+ 全 tool の migration は別 STEP (自動化 script + protocol shape 分類 audit)。
Test — 38/38 PASS
- wrapAsMsgTool factory
- WrappedToolRegistry (register/get/names/size)
- duplicate register throws
- Registry toolHandler dispatch
- createWiredRunner
- Wired runner runs disk_health_verdict pilot (healthy → TRUE)
- NoData detection through wrapper (empty input → ZERO/no_data flag)
- Unknown tool via CallMsg name → throw (registry miss)
- 3-tool composed plan (all pilots、 6 entry trace、 healthy/INFINITY/uniqueness)
- invokeWrappedTool yields [check, call]
- dryRun composition (handler not invoked, trace still recorded)
Honest scope
- 3 pilot tool のみ wrap 完了。 82+ 全 tool migration は別 STEP (自動化 script + protocol shape 分類 audit 必要)
- rei-mcp-server.ts は不変。 wrapper と registry は既存 case handler と共存可能 (二重登録リスクなし、 wrapper は plan 内 dispatch 用、 case handler は raw MCP call 用)
- mystery-reasoning-connector は別 tab 作物なので pilot 除外 (STEP 1576 protocol conformance は既に対応済、 wrap 追加は v0.2 candidate)
- counter drift = STEP 番号 1533 が narrative 上の 1585 に相当。 counter 修復は auto-mode で block、 別 STEP で対応