Editor MCP bridge toolset for project operations. It defines static wrapper methods that call McpGate.Run for creating, editing, deleting, reading and writing project files, managing scripts, input actions, project metadata, thumbnails, package lookups and hotload triggers.
// 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>
/// Project info and config (.sbproj), file read/write, C# script create/edit/delete, hotload, input
/// actions, and publishing metadata.
/// </summary>
[McpToolset( "bridge_project", "Project info and config (.sbproj), file read/write, C# script create/edit/delete, hotload, input actions, and publishing metadata." )]
public static class BridgeProjectTools
{
/// <summary>
/// Create a new C# component script in the project — a minimal s&box Component class (name is
/// sanitized to a valid identifier), or your exact code when content is provided. Errors if the
/// file already exists. Returns { path, created, className } — the new type is NOT live until a
/// recompile, so call trigger_hotload, then attach it with add_component_with_properties
/// (component=className).
/// </summary>
/// <param name="name">Class name for the component (e.g. 'PlayerController'). Will also be the filename.</param>
/// <param name="directory">Subdirectory under code/ to place the script (e.g. 'Components'). Defaults to 'code/'.</param>
/// <param name="description">Description of what this component does — used to generate appropriate code.</param>
/// <param name="properties">List of [Property] fields to include in the component. JSON array.</param>
/// <param name="content">Full C# file content. If provided, ignores name/properties and writes this directly.</param>
[McpTool( "create_script" )]
public static Task<object> CreateScript( string name, string directory = null, string description = null, JsonNode properties = null, string content = null )
=> McpGate.Run( "create_script", McpGate.Args( ( "name", name ), ( "directory", directory ), ( "description", description ), ( "properties", properties ), ( "content", content ) ) );
/// <summary>
/// Permanently delete a file from the project by its project-relative path (built for C# scripts,
/// but removes any file; no recycle bin, and editor undo cannot restore it). Errors if the file
/// doesn't exist. Returns a confirmation with the path — follow with trigger_hotload so the removed
/// class actually leaves the compiled assembly.
/// </summary>
/// <param name="path">Relative path to the script file to delete.</param>
[McpTool( "delete_script" )]
public static Task<object> DeleteScript( string path )
=> McpGate.Run( "delete_script", McpGate.Args( ( "path", path ) ) );
/// <summary>
/// One-call project orientation: identity (name/ident/org/type), the open scene with object count,
/// scene and prefab file lists (capped at 50 each, Libraries/.sbox excluded), code footprint
/// (.cs/.razor counts), custom Component types (up to 100, engine types excluded), and installed
/// libraries. Returns a structured summary — orient here first, then get_scene_hierarchy for the
/// scene, describe_type for components, find_broken_references for project health. Read-only.
/// </summary>
[McpTool.ReadOnly( "describe_project" )]
public static Task<object> DescribeProject()
=> McpGate.Run( "describe_project", McpGate.Args() );
/// <summary>
/// Edit an existing C# script in place via exact-text find/replace or a full-content overwrite.
/// Errors if the file or the find text isn't found (find/replace replaces ALL occurrences). Returns
/// { path, edited, operation } where operation is 'find_replace' or 'overwrite' — follow with
/// trigger_hotload so the change compiles, then get_compile_errors if in doubt.
/// </summary>
/// <param name="path">Relative path to the script file (e.g. 'code/PlayerController.cs').</param>
/// <param name="operations">List of edit operations to apply in order. JSON array.</param>
[McpTool( "edit_script" )]
public static Task<object> EditScript( string path, JsonNode operations )
=> McpGate.Run( "edit_script", McpGate.Args( ( "path", path ), ( "operations", operations ) ) );
/// <summary>
/// Register a custom named INPUT ACTION in the project so a generated game's custom verbs work in
/// play mode. Writes to <project>.sbproj → Metadata.InputSettings.Actions[]. Idempotent: if
/// the action already exists it is left alone (pass update=true to rebind its key). If the project
/// has no InputSettings yet, the full DEFAULT action set
/// (Forward/Back/Left/Right/Jump/Use/attack1/...) is seeded first so player movement/use are
/// preserved — the engine only auto-injects defaults when a game defines NONE. After adding, call
/// it from game code with Input.Pressed("name") / Input.Down("name") / Input.Released("name").
/// Note: input config is read at project load, so restart_editor (or reload the project) for a new
/// action to take effect in play mode.
/// </summary>
/// <param name="name">The action verb game code will call, e.g. "interact", "sprint", "drop". Matches Input.Pressed("interact").</param>
/// <param name="keyboardKey">Default keyboard binding, e.g. "e", "f", "space", "mouse1", "shift". Omit to add the action with no default key (player can bind it).</param>
/// <param name="group">UI group the action is listed under in the bindings menu (e.g. "Actions", "Movement", "Other"). Defaults to "Actions".</param>
/// <param name="update">If the action already exists, rebind its keyboardKey to the provided value instead of leaving it untouched. Default false (idempotent no-op when present).</param>
[McpTool( "ensure_input_action" )]
public static Task<object> EnsureInputAction( string name, string keyboardKey = null, string group = null, bool? update = null )
=> McpGate.Run( "ensure_input_action", McpGate.Args( ( "name", name ), ( "keyboardKey", keyboardKey ), ( "group", group ), ( "update", update ) ) );
/// <summary>
/// Fetch package information from the s&box package backend (Package.FetchAsync) by ident.
/// Returns { fullIdent, title, summary, description, org } — no download/rating/dependency data is
/// included. Use it to confirm a package exists and what it is before install_asset.
/// </summary>
/// <param name="ident">Package identifier (e.g. 'facepunch.flatgrass', 'myorg.mygame').</param>
[McpTool.ReadOnly( "get_package_details" )]
public static Task<object> GetPackageDetails( string ident )
=> McpGate.Run( "get_package_details", McpGate.Args( ( "ident", ident ) ) );
/// <summary>
/// Read the full project configuration from the .sbproj file including title, description, version,
/// type, package references, metadata, and raw JSON.
/// </summary>
[McpTool.ReadOnly( "get_project_config" )]
public static Task<object> GetProjectConfig()
=> McpGate.Run( "get_project_config", McpGate.Args() );
/// <summary>
/// Get information about the current s&box project — path, name, game type, dependencies, and
/// configuration.
/// </summary>
[McpTool.ReadOnly( "get_project_info" )]
public static Task<object> GetProjectInfo()
=> McpGate.Run( "get_project_info", McpGate.Args() );
/// <summary>
/// Browse the project file tree. Optionally filter by directory path and/or file extension (e.g.
/// '.cs', '.scene'). Returns { path, count, files } as project-root-relative paths — CAPPED AT 500
/// files (count reflects the truncated list, with no marker that more exist), so on large projects
/// narrow with path/extension or use find_in_project. Recursive by default.
/// </summary>
/// <param name="path">Relative directory path to list (e.g. 'code/Components'). Defaults to project root.</param>
/// <param name="extension">Filter by file extension, including the dot (e.g. '.cs', '.scene').</param>
/// <param name="recursive">Whether to list files recursively. Defaults to true.</param>
[McpTool.ReadOnly( "list_project_files" )]
public static Task<object> ListProjectFiles( string path = null, string extension = null, bool? recursive = null )
=> McpGate.Run( "list_project_files", McpGate.Args( ( "path", path ), ( "extension", extension ), ( "recursive", recursive ) ) );
/// <summary>
/// Read the contents of a file in the s&box project (scripts, scenes, configs, etc.).
/// </summary>
/// <param name="path">Relative path to the file within the project (e.g. 'code/PlayerController.cs').</param>
[McpTool.ReadOnly( "read_file" )]
public static Task<object> ReadFile( string path )
=> McpGate.Run( "read_file", McpGate.Args( ( "path", path ) ) );
/// <summary>
/// Update project configuration fields for publishing: title, description, version, type, package
/// ident, summary, visibility. Only provided fields are changed — edits string values in the
/// .sbproj file in place. Returns { updated, path } (the .sbproj path); read the result back with
/// get_project_config to confirm what actually changed.
/// </summary>
/// <param name="title">Project display title.</param>
/// <param name="description">Project description for publishing.</param>
/// <param name="version">Version string (e.g. '1.0.0', '2.1.3').</param>
/// <param name="type">Project type: 'game', 'addon', 'library', or 'template'.</param>
/// <param name="packageIdent">Package identifier (e.g. 'myorg.mygame').</param>
/// <param name="summary">Short summary for asset.party listing.</param>
/// <param name="isPublic">Whether the project is publicly visible.</param>
[McpTool( "set_project_config" )]
public static Task<object> SetProjectConfig( string title = null, string description = null, string version = null, string type = null, string packageIdent = null, string summary = null, bool? isPublic = null )
=> McpGate.Run( "set_project_config", McpGate.Args( ( "title", title ), ( "description", description ), ( "version", version ), ( "type", type ), ( "packageIdent", packageIdent ), ( "summary", summary ), ( "isPublic", isPublic ) ) );
/// <summary>
/// Set or update the project thumbnail image (thumb.png) used for publishing. Provide either a
/// source path or base64 image data.
/// </summary>
/// <param name="sourcePath">Relative path to an image file within the project to use as thumbnail.</param>
/// <param name="base64">Base64-encoded image data to write as thumbnail.</param>
/// <param name="format">Image format when using base64 mode. Defaults to 'png'. One of: png | jpg.</param>
[McpTool( "set_project_thumbnail" )]
public static Task<object> SetProjectThumbnail( string sourcePath = null, string base64 = null, string format = null )
=> McpGate.Run( "set_project_thumbnail", McpGate.Args( ( "sourcePath", sourcePath ), ( "base64", base64 ), ( "format", format ) ) );
/// <summary>
/// Force s&box to recompile and hotload all C# scripts immediately. Use after creating or
/// editing scripts to see changes in real-time.
/// </summary>
[McpTool( "trigger_hotload" )]
public static Task<object> TriggerHotload()
=> McpGate.Run( "trigger_hotload", McpGate.Args() );
/// <summary>
/// Write or overwrite a file in the s&box project (SILENTLY replaces existing content —
/// read_file first if you need to preserve it). Creates parent directories as needed; paths are
/// confined to the project root (traversal outside it is denied). Returns a confirmation with the
/// path — for C# follow with trigger_hotload so it compiles; for assets (.vmat etc.) follow with
/// recompile_asset.
/// </summary>
/// <param name="path">Relative path for the file (e.g. 'code/Components/Health.cs').</param>
/// <param name="content">The full file content to write.</param>
[McpTool( "write_file" )]
public static Task<object> WriteFile( string path, string content )
=> McpGate.Run( "write_file", McpGate.Args( ( "path", path ), ( "content", content ) ) );
}