STEP 1533 — MCP tool Msg wrapping (STEP 1569 arc 2/3)

STEP 1533 · 藤本さん directive 「実 hardware → MCP wrapping → Bluesky Msg 順」 arc 2/3 · wrapper factory + registry + 3 pilot tool + 3-tool composed plan · Rei-AIOS · 2026-08-30
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 が付与するもの

  1. PlanRunner との統合: toolHandler として registry 経由 dispatch
  2. SafetyGate pre-check: STEP 1584 rule catalog 経由 (declaredHazard + rule 双方適用)
  3. NoDataResult 自動検出: STEP 1571 の isNoDataResult で trace flag 自動設定
  4. Protocol type conformance: STEP 1576 shape 継承 (compile-time check)
  5. Registry 逆引き: name → handler の O(1) lookup + duplicate detection

3 Pilot tool

Wrapped tool原 STEPLayer / hazardProtocol shape
wrappedDiskHealthVerdict1567Layer 1 sensor / cautionsingle-verdict
wrappedShannonEntropyVerdict1499Layer 2 analytical / safesingle-verdict
wrappedPuzzleVerify1536pure computation / safeuniqueness-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)

  1. Import 元 tool: import { toolFn } from './tool-source'
  2. wrapAsMsgTool: name / description / declaredHazard / originStep / protocolShape を宣言
  3. Registry 登録: registry.register(wrappedTool)
  4. rei-mcp-server.ts の case handler は変更不要 (wrapper と registry は別 layer で共存)
  5. plan 内で使用: yield* invokeWrappedTool(wrappedTool, args, label?)

82+ 全 tool の migration は別 STEP (自動化 script + protocol shape 分類 audit)。

Test — 38/38 PASS

  1. wrapAsMsgTool factory
  2. WrappedToolRegistry (register/get/names/size)
  3. duplicate register throws
  4. Registry toolHandler dispatch
  5. createWiredRunner
  6. Wired runner runs disk_health_verdict pilot (healthy → TRUE)
  7. NoData detection through wrapper (empty input → ZERO/no_data flag)
  8. Unknown tool via CallMsg name → throw (registry miss)
  9. 3-tool composed plan (all pilots、 6 entry trace、 healthy/INFINITY/uniqueness)
  10. invokeWrappedTool yields [check, call]
  11. dryRun composition (handler not invoked, trace still recorded)

Honest scope