Editor bridge for project-related MCP tools. It defines a static class BridgeProjectTools with annotated methods that call McpGate.Run to perform project file I/O, script create/edit/delete, hotload, input action registration, project metadata/config queries and updates, thumbnail setting, and package info lookup.
// 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 ) ) );
}