主题
Runtime MCP Target Routing Skill
Use this skill together with SCE DebugTools MCP when an Editor debug session can contain more than one simulated client. The purpose of this skill is to keep Runtime inspection and Runtime writes attached to the intended Gameplay/Wasmtime state instead of silently using the first available instance.
Scope and protocol
Connection selection has two levels: select the Editor/Runtime process by its discovered instance ID, then select a Gameplay with target_id. GUI ports are automatic; normally omit port in the outer forwarding tools. Explicit foreign ports require runtime_instance_id. See the multi-instance connection guide.
Gameplay routing selects multiple Gameplay instances inside the same Client process. It does not provide independent input focus for multiple embedded viewports and does not broker multiple independent SCE processes.
The routing field belongs to the outer Runtime MCP request envelope:
json
{
"method": "runtime.call_tool",
"params": {
"target_id": "gameplay:<GameplayUUID>",
"name": "ui.snapshot",
"arguments": {
"maxDepth": 4,
"maxNodes": 200
}
}
}target_id is not a Runtime tool argument. Keep it beside name and arguments; a field with the same name inside arguments belongs to the Runtime tool and must not be overwritten by the bridge.
Target IDs are process-local and short-lived. Treat them as opaque strings. Do not persist them in a project, put them in generated code, or reuse them after a Gameplay is destroyed or recreated.
Deterministic selection workflow
- Start or attach to the full Editor debug session through the normal
debug_*tools. - Call
runtime_list_targetswithout a target ID. - Match the returned targets in this order:
- the simulated client explicitly named by the user;
- an exact
slot_idmatch; - an exact string
player_idmatch; - a unique foreground target when it clearly matches the task.
- If exactly one target remains, remember its
target_idfor this debug session. - If more than one target remains, ask the user which simulated client to inspect. Never choose the first array item as an implicit default.
- Call
runtime_list_toolswith the selected ID, then callruntime_call_toolwith the same ID for every target-specific Runtime request. - If the debug session ends, a Gameplay is recreated, or the bridge reports a stale target, return to step 2.
Use debug.ping to verify the selected target's live identity. On updated clients, runtime_identity_source="native_gameplay" identifies the routed target_id, gameplay_uuid, project, path, slot and user. startup_arguments describes process startup and may refer to an older project. With only updated managed dependencies, runtime_identity_source="managed_game" supplies the live project/session/player and run mode; native route/path fields are null. Treat missing or null fields as unavailable and retain target discovery evidence instead of filling them from startup argv.
Example target discovery:
json
{
"tool": "runtime_list_targets",
"arguments": {
"timeout_ms": 5000
}
}Read result.targets from an outer Editor MCP response. Each target may contain:
| Field | Meaning |
|---|---|
target_id | Opaque process-local routing ID, normally gameplay:<GameplayUUID> |
gameplay_uuid | Gameplay instance identity for diagnostics |
slot_id | Editor multiplayer slot identifier |
player_id | Player identity serialized as a string to avoid integer precision loss |
map_name | Map associated with the Gameplay instance |
is_foreground | Whether the target is currently foreground |
is_editor_game | Whether the target belongs to the Editor debug session |
ready | Whether its Wasmtime Runtime state is ready for calls |
Only one target can omit target_id for backward compatibility. With multiple targets, omission must fail with runtime_target_ambiguous.
Keep one target for one verification loop
Once selected, use the same target for the whole evidence chain:
text
runtime_list_targets
-> runtime_list_tools(target_id)
-> runtime_call_tool(debug.ping, target_id)
-> runtime_call_tool(debug.list_tools, target_id)
-> runtime_call_tool(ui.snapshot or project tool, target_id)Do not mix a target-specific ui.snapshot with a target-less debug.ping; that can produce evidence from different Gameplay instances. If the user asks to compare two simulated clients, discover once, then run the same tool sequence separately for each returned ID and label the evidence with the ID/slot/player metadata.
Background visual verification
After selecting a target, inspect its runtime_list_tools schema for debug.viewport_update. If available, acquire a lease for that target before a continuous animation or visual test, keep the returned string lease_id, renew before ttl_ms expires, and release in finally. Leases are bound to Gameplay and expire by wall time; ordinary per-call TCP disconnects do not release them. A stale lease cannot be renewed on another target or a new game.
Read rendered_engine_frame from debug.viewport_update status to distinguish engine-time progression from completed viewport drawing. On targets advertising the extended screenshot schema, debug.capture_screenshot waits for a new viewport submission by default; frame_timeout_ms controls this wait and the outer timeout must also cover file completion. The result captures the selected target's full window, not a cropped viewport. Its rendered_engine_frame is a completed submission identifier, not an exact GPU readback identifier.
Treat window_minimized, window_hidden, viewport_hidden, graphics_unavailable, and viewport_frame_timeout as explicit unavailable/timeout results. The embedded viewport inherits its Editor host window's minimized/hidden state. Restore the host or show the selected tab before retrying. A lease does not activate windows, switch hidden multiplayer tabs, change input routing, or override a deliberately paused simulation.
For animation acceptance, retain both advancing rendered_engine_frame values and changing native bone positions or visible poses in completed screenshots. Advancing game time or animation ticks alone does not prove drawing. A single fresh screenshot requests its own temporary update; use a continuous lease for a sequence of visual checks. Disconnecting an unfinished screenshot request cleans up that temporary update, while explicit leases remain valid until release or expiry.
Input boundary
Target routing selects the Runtime/Wasmtime state for debug.*, ui.*, scenegraph.*, material.*, and project-specific Runtime tools. input.pointer, input.key, input.text, and input.reset still go through process-level input and are affected by the active window and foreground focus. Do not claim that two embedded viewports can receive independent simultaneous synthetic input in phase one.
For a held pointer/key sequence, keep the selected Runtime target fixed and call input.reset if the sequence is interrupted. After changing the foreground embedded viewport, rediscover targets if the client recreated Gameplay state, then verify the target with debug.ping before continuing.
Fallback commands
When native Editor MCP actions are unavailable, use the versioned SDK fallback:
powershell
.\tools\runtime-mcp\Invoke-SceRuntimeMcpClient.ps1 -ListTargets -Port $runtimePort -RuntimeInstanceId $runtimeId
.\tools\runtime-mcp\Invoke-SceRuntimeMcpClient.ps1 -ListTools -TargetId gameplay:42 -Port $runtimePort -RuntimeInstanceId $runtimeId
.\tools\runtime-mcp\Invoke-SceRuntimeMcpClient.ps1 -Tool debug.ping -TargetId gameplay:42 -Port $runtimePort -RuntimeInstanceId $runtimeId
.\tools\runtime-mcp\Invoke-SceRuntimeMcpClient.ps1 -Tool ui.snapshot -TargetId gameplay:42 -ArgumentsJson '{"maxDepth":4,"maxNodes":200}' -Port $runtimePort -RuntimeInstanceId $runtimeIdThe project-local ai/tools/Invoke-SceRuntimeMcp.ps1 is a thin shim over this shared client. Use Invoke-SceEditorMcp.ps1 when the full Editor MCP HTTP bridge is available; use the direct Runtime fallback only when the outer bridge is unavailable or is itself being diagnosed.
Error recovery
| Error | Meaning | Recovery |
|---|---|---|
runtime_target_ambiguous | Multiple Gameplay targets are active and no target was supplied | Call runtime_list_targets, select deterministically, retry with target_id |
runtime_target_not_found | The target ended or was recreated | Discover again; do not retry the stale ID |
runtime_target_routing_unavailable | Client native bridge predates target routing | Update the Client build; a single-target call without target_id may still work |
client_runtime_unavailable | No Runtime bridge is ready on the selected port | Wait for debug startup, check the port, then rediscover |
invalid_target_id | The bridge received a non-string or blank target ID | Send a non-empty string in the outer params.target_id field |
When runtime_list_targets returns an empty list, treat the Runtime as not ready or inactive; do not invent a target ID. Check the newest client log and the debug operation state before retrying.
Evidence rules
Before claiming that a specific simulated client was inspected or changed, retain:
- the target discovery result containing
target_id,slot_id, andplayer_id; - a successful
debug.pingordebug.list_toolsresponse using that same ID; - the target-specific inspection or write response;
- a fresh discovery result after any debug restart or Gameplay recreation.
For the complete Runtime tool catalog and coordinate/input semantics, read Runtime MCP 调试指南 and SCE Editor MCP 工具速查.