Editor toolset wrapper exposing bridge validation and linting tools to the MCP gate. Provides static readonly MCP tool methods for finding broken references, inspecting networked objects, various lints (networking, Razor, sandbox), scene and save inspection, service queries, and publishing validation.
// AUTO-GENERATED by scripts/emit-mcp-wrappers.mjs — DO NOT EDIT.
// Regenerate: node scripts/extract-manifest.mjs && node scripts/emit-mcp-wrappers.mjs
// Source of truth: sbox-mcp-server/src/tools/ (zod schemas) → scripts/tools-manifest.json
using System.Text.Json.Nodes;
using System.Threading.Tasks;
using Editor.Mcp;
/// <summary>
/// Lint and validate the project: networking footguns, sandbox whitelist violations, Razor
/// transpiler footguns, scene setup issues, publishing readiness, save-file inspection, and
/// networked-object state dumps.
/// </summary>
[McpToolset( "bridge_validation", "Lint and validate the project: networking footguns, sandbox whitelist violations, Razor transpiler footguns, scene setup issues, publishing readiness, save-file inspection, and networked-object state dumps." )]
public static class BridgeValidationTools
{
/// <summary>
/// Scan the project for broken references, two layers in one call: (1) every GameObject in the open
/// scene — renderers with no Model (missing_model), component properties pointing at DESTROYED
/// GameObjects/Components (dead_gameobject_ref / dead_component_ref), null component entries whose
/// type no longer exists (missing_component); (2) every .scene/.prefab FILE — prefab references to
/// deleted/renamed files (missing_prefab_file). Returns { total, showing, truncated,
/// objectsScanned, filesScanned, issues } — each issue has { id, name, component, kind, detail }
/// (file-level issues carry the file path in name). Fix missing models with assign_model, dead refs
/// with set_property/set_component_reference, missing prefab files by fixing the path or recreating
/// via create_prefab. Read-only; safe any time. Results cap at `limit` (default 100, max 500).
/// </summary>
/// <param name="limit">Max issues to return (default 100, max 500). total still counts everything.</param>
/// <param name="scanFiles">Include the .scene/.prefab file scan for missing prefab references. Default true.</param>
[McpTool.ReadOnly( "find_broken_references" )]
public static Task<object> FindBrokenReferences( int? limit = null, bool? scanFiles = null )
=> McpGate.Run( "find_broken_references", McpGate.Args( ( "limit", limit ), ( "scanFiles", scanFiles ) ) );
/// <summary>
/// Inspect the live networking contract of a GameObject. Returns {id, name, network: {active,
/// isProxy, isOwner, isCreator, ownerId, ownerSteamId, ownerTransfer, orphaned, flags}, components:
/// [{component, fields: [{name, type, isSync, syncFlags, value}]}]} — by default only [Sync]-marked
/// fields are listed (components with none are omitted). Unlike get_network_status (session-only),
/// this is per-object — the way to verify a host-authoritative or ownership change actually
/// replicated; works in edit or play mode. Follow up with set_ownership to change the owner, or
/// networking_lint to find the code-level cause of a bad [Sync] value.
/// </summary>
/// <param name="id">GUID of the GameObject to inspect.</param>
/// <param name="allProps">Include all component properties, not just [Sync]-marked ones.</param>
[McpTool.ReadOnly( "inspect_networked_object" )]
public static Task<object> InspectNetworkedObject( string id, bool allProps = false )
=> McpGate.Run( "inspect_networked_object", McpGate.Args( ( "id", id ), ( "allProps", allProps ) ) );
/// <summary>
/// Static-scan the project's C# for the highest-frequency networking/authority bugs: a mutator that
/// writes a [Sync] field with no IsProxy/Networking.IsHost guard; money/health/score-shaped fields
/// marked plain [Sync] (should be SyncFlags.FromHost); List<>/Dictionary<> marked
/// [Sync] (should be NetList/NetDictionary); [Sync] fields typed Connection/GameObject (sync a Guid
/// instead); [Rpc.Host] methods that mutate without re-checking Rpc.Caller; and component swaps /
/// reflection writes missing Network.Refresh(). Returns findings with file:line + the suggested
/// fix.
/// </summary>
/// <param name="path">Optional sub-path under the project (e.g. 'Code/Player') to scope the scan; omit for the whole project.</param>
[McpTool.ReadOnly( "networking_lint" )]
public static Task<object> NetworkingLint( string path = null )
=> McpGate.Run( "networking_lint", McpGate.Args( ( "path", path ) ) );
/// <summary>
/// Static-scan .razor and .razor.scss files for the silent footguns that crash the Razor transpiler
/// or stylesheet engine with no useful error message: switch expressions inside @code blocks (use
/// if/else instead), non-ASCII/emoji inside @code (move to markup or a string constant),
/// PanelComponent subclasses missing a BuildHash override (panel never re-renders), and root
/// uppercase type-selector rules in .razor.scss (silently skipped -- use a class selector like
/// .my-panel). Returns { scanned, findings: [{file, line, match, advice}], clean } matching the
/// sandbox_lint shape.
/// </summary>
/// <param name="directory">Subdirectory under the project root to scan (e.g. 'UI', 'Code'). Defaults to 'Code'.</param>
[McpTool.ReadOnly( "razor_lint" )]
public static Task<object> RazorLint( string directory = null )
=> McpGate.Run( "razor_lint", McpGate.Args( ( "directory", directory ) ) );
/// <summary>
/// Static-scan the project's C# for s&box sandbox whitelist violations BEFORE they cause
/// compile errors: System.MathF (use MathX), System.Math (use MathX), Array.Clone() (use
/// .ToArray()), System.Net / raw sockets (use Sandbox.Http), System.IO.File (use FileSystem.Data),
/// and raw System.Threading.Thread (use async/Task or GameTask). Returns { scanned, findings:
/// [{file, line, match, advice}], clean }. Scope to a subdirectory with the directory param.
/// </summary>
/// <param name="directory">Subdirectory under the project root to scan (e.g. 'Code', 'Code/Player'). Defaults to 'Code'.</param>
[McpTool.ReadOnly( "sandbox_lint" )]
public static Task<object> SandboxLint( string directory = null )
=> McpGate.Run( "sandbox_lint", McpGate.Args( ( "directory", directory ) ) );
/// <summary>
/// Inspect the game's FileSystem.Data save files — the assistant is otherwise blind to persisted
/// state. action='list' (default) returns `directories` and `files` [{name, path, size}] under
/// `path` (omit path for the Data root); action='read' returns {path, length, content}, truncating
/// content at 60,000 chars; action='diff' compares two save files key-by-key, returning `diffCount`
/// and up to 200 `diffs` [{key, change: added|removed|changed}]. Use to verify a save actually
/// wrote, debug a load/migration, or confirm a sanitize/clamp ran.
/// </summary>
/// <param name="action">'list' (default) enumerates a folder; 'read' dumps one file's JSON; 'diff' compares `path` vs `pathB`. One of: list | read | diff. Default: "list".</param>
/// <param name="path">File or folder path under FileSystem.Data (e.g. 'lumber_corp2_progress' or '<folder>/steam_123.json').</param>
/// <param name="pathB">Second file path for action='diff'.</param>
[McpTool.ReadOnly( "save_inspect" )]
public static Task<object> SaveInspect( string action = "list", string path = null, string pathB = null )
=> McpGate.Run( "save_inspect", McpGate.Args( ( "action", action ), ( "path", path ), ( "pathB", pathB ) ) );
/// <summary>
/// Validate the active scene for the silent setup footguns that break controllers/physics/cameras:
/// no CameraComponent, no player controller, multiple root Rigidbodies, a Rigidbody with
/// MotionEnabled=false fighting a kinematic root, IsTrigger colliders that Scene.Trace will ignore,
/// child Rigidbodies breaking collider binding, and missing required child anchors. Returns each
/// issue with the GameObject and the exact fix.
/// </summary>
[McpTool.ReadOnly( "scene_validate" )]
public static Task<object> SceneValidate()
=> McpGate.Run( "scene_validate", McpGate.Args() );
/// <summary>
/// Read from Sandbox.Services — the cloud stats/leaderboard layer many games use as their real DB.
/// action='stats' with `name` returns the local player's stat {ident, value, sum, min, max,
/// lastValue, valueString}; without `name` it returns only the package ident plus a usage note (it
/// does NOT list stat definitions). action='leaderboard' (name required) returns {board,
/// displayName, totalEntries, count, entries} with at most `limit` entries (default 10). Read-only;
/// use to verify a Stats.Increment/SetValue path or a leaderboard wired correctly.
/// </summary>
/// <param name="action">'stats' (default) reads a local-player stat by `name`; 'leaderboard' fetches a board's top entries. One of: stats | leaderboard. Default: "stats".</param>
/// <param name="name">Stat name (action='stats') or leaderboard/board name (action='leaderboard').</param>
/// <param name="limit">Max leaderboard entries to return.</param>
[McpTool.ReadOnly( "services_query" )]
public static Task<object> ServicesQuery( string action = "stats", string name = null, int limit = 10 )
=> McpGate.Run( "services_query", McpGate.Args( ( "action", action ), ( "name", name ), ( "limit", limit ) ) );
/// <summary>
/// Validate that the project is ready for publishing. Runs four checks: .sbproj exists, at least
/// one scene, project Ident set, project Title set. Returns { valid, issueCount, issues, checks } —
/// issues are human-readable problems and each checks entry has { check, pass, detail }; fix
/// metadata gaps with set_project_config (it does NOT check compile errors — use get_compile_errors
/// for that).
/// </summary>
[McpTool.ReadOnly( "validate_project" )]
public static Task<object> ValidateProject()
=> McpGate.Run( "validate_project", McpGate.Args() );
}