> ## Documentation Index
> Fetch the complete documentation index at: https://docs.summerengine.com/llms.txt
> Use this file to discover all available pages before exploring further.

# MCP tools: build

> Build tools of the Summer Engine MCP. Scenes, nodes, scripts, project files, the planning board and Summer Studio. For each tool: what it does, what it needs, inputs, output and an example.

Scenes, nodes, scripts, project files, the planning board and Summer Studio. 71 tools. What each column means, and how to connect: [MCP tools reference](/mcp/tools-reference).

<Note>
  Generated from the tools' own definitions: the `summer-engine` npm package `3.3.0` (its MCP server's `tools/list`, `library/tools/*/resource.yaml` and `registry/generated/index.json` in [SummerEngine/summer](https://github.com/SummerEngine/summer)) and the hosted Summer Engine MCP (`src/lib/mcp/hosted` at commit `8c4351ee30`). If something here is wrong, the tool definition is wrong.
</Note>

| Tool | Needs | What it does |
| - | - | - |
| [`summer_account`](#summer_account) | Summer account | Show the signed-in Summer account: plan, spendable credits (USD), whether cloud generation is unlocked, and pricing/top-up links. |
| [`summer_add_node`](#summer_add_node) | Engine | Add a new node to the scene tree. |
| [`summer_align_distribute_3d`](#summer_align_distribute_3d) | Engine | Align or equal-space an explicit ordered list of 3D subjects along one world-space axis, then save the exact target scene. |
| [`summer_api_docs`](#summer_api_docs) | Nothing | Offline engine class-reference lookup — verify a property, method, signal, or constant BEFORE writing script code, instead of guessing names. |
| [`summer_attach_to_surface`](#summer_attach_to_surface) | Engine | Mount a piece on a surface: turn it so its given LOCAL backAxis faces into the surface (opposite the hit normal) with its upAxis kept toward worldUp, then seat its measured back face (the extreme of its visible bounds… |
| [`summer_batch`](#summer_batch) | Engine | Execute multiple operations in a single call. |
| [`summer_board_agent_cancel`](#summer_board_agent_cancel) | Summer account | Stop a queued or running board agent task. |
| [`summer_board_agent_run`](#summer_board_agent_run) | Summer account | Ask the board's own agent to work on the board, as typing in Studio does: it reads, edits, draws pictures and answers on the board. |
| [`summer_board_agent_task`](#summer_board_agent_task) | Summer account | One board agent task: its status, reply and what it changed. |
| [`summer_board_agent_tasks`](#summer_board_agent_tasks) | Summer account | The board agent's tasks on this board, with their replies. |
| [`summer_board_build`](#summer_board_build) | Summer account | Build a playable game from a saved Game Soul version (soulVersionId from summer\_board\_game\_soul), as Build in Studio does. |
| [`summer_board_build_cancel`](#summer_board_build_cancel) | Summer account | Stop a board build that has not finished. |
| [`summer_board_build_status`](#summer_board_build_status) | Summer account | One board build: status, progress and, when done, what it made. |
| [`summer_board_builds`](#summer_board_builds) | Summer account | Recent game builds from this board and whether cloud builds are available now. |
| [`summer_board_conversation`](#summer_board_conversation) | Summer account | Read the shared board conversation with server-attributed participants and timestamped pointing, plus the board agent tasks it started and their replies. |
| [`summer_board_create`](#summer_board_create) | Summer account | Create a new board, optionally for one of the user's projects (projectId from summer\_list\_projects). |
| [`summer_board_edit`](#summer_board_edit) | Summer account | Apply an explicitly requested edit as one atomic batch. |
| [`summer_board_enable_collaboration`](#summer_board_enable_collaboration) | Summer account | Turn on shared editing for an older board (the board agent, builds and conversation need it). |
| [`summer_board_events`](#summer_board_events) | Summer account | Board changes since a revision (what Studio's live view receives): each committed operation with its revision. |
| [`summer_board_game_soul`](#summer_board_game_soul) | Summer account | Read immutable Game Soul versions and their exact reference assets, for continuing game development in a local engine or code assistant. |
| [`summer_board_link_project`](#summer_board_link_project) | Summer account | Link a board to one of the user's projects (projectId from summer\_list\_projects), so the game built from it opens that project. |
| [`summer_board_list`](#summer_board_list) | Summer account | List boards this authenticated Summer user can access. |
| [`summer_board_presence`](#summer_board_presence) | Summer account | Who is on the board right now, with their selection and topic. |
| [`summer_board_project_links`](#summer_board_project_links) | Summer account | Which of the user's boards belong to which projects. |
| [`summer_board_read`](#summer_board_read) | Summer account | Read the authoritative board graph, stable item and asset IDs, current field revisions and permissions. |
| [`summer_board_save_direction`](#summer_board_save_direction) | Summer account | Save an explicitly selected game direction as an immutable Game Soul version. |
| [`summer_connect_ports`](#summer_connect_ports) | Engine | Move and turn one piece so its port meets another piece's port, facing it: pipe to pipe, duct to duct, gutter section to funnel or outlet. |
| [`summer_connect_signal`](#summer_connect_signal) | Engine | Connect a signal between two nodes so the connection is SAVED in the scene. |
| [`summer_create_scene`](#summer_create_scene) | Engine | Create a new empty scene file. |
| [`summer_get_agent_playbook`](#summer_get_agent_playbook) | Nothing | AI-first operating guide for Summer Engine MCP. |
| [`summer_get_project_context`](#summer_get_project_context) | Engine | Get essential project context before editing. |
| [`summer_get_scene_tree`](#summer_get_scene_tree) | Engine | Get a scene tree. |
| [`summer_grep`](#summer_grep) | Engine | Search project files with a regular expression (ripgrep, through the engine) and get file + line + text per match, optionally with context lines around each. |
| [`summer_input_map_bind`](#summer_input_map_bind) | Engine | Set up input controls. |
| [`summer_inspect_asset`](#summer_inspect_asset) | Engine | Measure a 3D asset file (.tscn/.scn/.glb/.gltf, or a Mesh resource) WITHOUT adding it to any scene: it is loaded and instanced off-scene in the editor, measured, and freed. |
| [`summer_inspect_node`](#summer_inspect_node) | Engine | Get all editable properties of a node with their current values, types, and resource info. |
| [`summer_inspect_resource`](#summer_inspect_resource) | Engine | Read a resource: a material, mesh, shape, texture, environment, or a scene/model file. |
| [`summer_instantiate_scene`](#summer_instantiate_scene) | Engine | Add an existing scene or 3D model as a child node. |
| [`summer_library_feedback`](#summer_library_feedback) | Nothing | Report how library entries (skills, examples, templates, collections, references, tools) worked out, so Summer can fix and re-rank them — reports fix the entries this user's own future sessions load. |
| [`summer_measure`](#summer_measure) | Engine | Measure placement between specific nodes from their visible-mesh bounds (evidence visual\_aabb). |
| [`summer_navigation_probe`](#summer_navigation_probe) | Engine | Inspect whether two explicit world-space points are connected by the targeted 3D scene's built-in Godot navigation map without changing or saving the scene. |
| [`summer_open`](#summer_open) | Engine | Open the exact summerengine.com page or Summer Engine editor surface the user wants to LOOK at, by intent name — or, with open:false, return the URL / engine op without opening anything. |
| [`summer_open_main_scene`](#summer_open_main_scene) | Engine | Open the project's configured main scene from project settings. |
| [`summer_open_scene`](#summer_open_scene) | Engine | Open a scene file in the editor. |
| [`summer_place_adjacent`](#summer_place_adjacent) | Engine | Move one node so its bounds face sits against another node's bounds face along one axis: facade modules edge to edge, a storey stacked on the one below, a cornice on a wall. |
| [`summer_project_setting`](#summer_project_setting) | Engine | Set a project setting in project.godot. |
| [`summer_raycast`](#summer_raycast) | Engine | Cast one ray from any point in an open scene, before anything is placed there: find the wall, floor or ceiling in front of a point and its normal. |
| [`summer_read_file`](#summer_read_file) | Engine | Read a text file from the engine-bound project and return its full-file sha256 receipt. |
| [`summer_read_library`](#summer_read_library) | Nothing | Load one library entry by id (\<kind>/\<slug>, as returned by summer\_search\_library). |
| [`summer_remove_node`](#summer_remove_node) | Engine | Remove a node from the scene tree. |
| [`summer_repeat_along`](#summer_repeat_along) | Engine | Instance copies of one scene along a straight line in one call: wall clamps every 0.45 m, braces every 0.8 m, fence posts, a row of window modules. |
| [`summer_replace_node`](#summer_replace_node) | Engine | Replace a node with a different scene/model or node type, keeping its parent, sibling index, name, transform and property overrides, and the children the scene added under it. |
| [`summer_replace_text`](#summer_replace_text) | Engine | Safely replace text in an existing project file through the identity-bound engine. |
| [`summer_run_editor_script`](#summer_run_editor_script) | Engine | Run a GDScript EditorScript in a FRESH HEADLESS editor spawned against the ON-DISK project. |
| [`summer_run_script`](#summer_run_script) | Engine | Run a GDScript snippet INSIDE the live editor, against the currently OPEN scene. |
| [`summer_save_scene`](#summer_save_scene) | Engine | Save an explicit scene to disk. |
| [`summer_search_library`](#summer_search_library) | Nothing | Search the Summer library — skills, tools, templates, references, examples, collections — by describing the task in plain words ('make stylized water', 'the player falls through the floor', 'which tool reads script… |
| [`summer_select_node`](#summer_select_node) | Engine | Select a node in the editor's scene tree and show it in the inspector panel. |
| [`summer_set_prop`](#summer_set_prop) | Engine | Set a property on a node. |
| [`summer_set_resource_property`](#summer_set_resource_property) | Engine | Set a nested property on a resource attached to a node. |
| [`summer_snap_to_surface`](#summer_snap_to_surface) | Engine | Move one exact 3D subject along a world-space ray until its support face sits at the requested gap from the first surface. |
| [`summer_starcast`](#summer_starcast) | Engine | Read a 3D spatial rundown for one exact node in an exact scene without moving it or saving the scene: 26 directional clearance casts (6 axes, 12 edges, 8 corners) from the subject's bounds, contact-or-overlap evidence,… |
| [`summer_start_game_task`](#summer_start_game_task) | Nothing | Start here for any substantial AI game-building task. |
| [`summer_studio_map`](#summer_studio_map) | Summer account | The map of Summer Studio: every page (destination id, title, what it is for, path) and the product guide the Studio assistant answers from. |
| [`summer_studio_open`](#summer_studio_open) | Summer account | Move the person's open Summer Studio tab to a Studio page (a destination id from summer\_studio\_map, or a /studio or /create path). |
| [`summer_studio_page`](#summer_studio_page) | Summer account | Read the person's open Summer Studio tab: its path, the fields an agent may fill (id, label, kind, value, limits, choices) and the buttons it may press (confirm buttons are the person's to press). |
| [`summer_studio_use_page`](#summer_studio_use_page) | Summer account | Fill fields and press one button on the person's open Summer Studio tab, exactly like the Studio assistant's use\_page: ids and values are checked against the page (text is trimmed to its limit, choices take their value… |
| [`summer_test_placement`](#summer_test_placement) | Engine | Ghost-test one 3D node at an explicit candidate global pose without moving it or saving the scene. |
| [`summer_ui_actions`](#summer_ui_actions) | Engine | List the editor's named actions, or invoke ONE by name exactly as its menu item / shortcut would — the primary way to drive the editor UI. |
| [`summer_ui_activate`](#summer_ui_activate) | Engine | Activate ONE editor control by its summer\_ui\_tree path through the control's own input path — a synthetic click for buttons, the public setter + signal for tabs, text fields and ranges — or dismiss a visible dialog… |
| [`summer_write_file`](#summer_write_file) | Engine | Create or safely overwrite a complete text file through the identity-bound engine. |

### summer\_account

On the hosted MCP.

Show the signed-in Summer account: plan, spendable credits (USD), whether cloud generation is unlocked, and pricing/top-up links. Free.

| | |
| - | - |
| **Needs** | Your Summer account (OAuth). In the npm MCP: `summer login --store` |
| **Hints** | `readOnlyHint` |

**Inputs:**

No inputs.

<Accordion title="Input JSON schema">
  ```json theme={null}
  {
    "type": "object",
    "properties": {}
  }
  ```
</Accordion>

**Output:** MCP text content holding JSON; errors set `isError`.

```json Example call theme={null}
{
  "name": "summer_account",
  "arguments": {}
}
```

***

### summer\_add\_node

On the local MCP (`summer-engine` npm).

Add a new node to the scene tree.

Pass the exact res\:// scenePath to mutate. The scene does not need to be the
active editor tab.

Common node types:

* 3D: Node3D, MeshInstance3D, CharacterBody3D, RigidBody3D, StaticBody3D, Camera3D, DirectionalLight3D, OmniLight3D, SpotLight3D, WorldEnvironment, CollisionShape3D, Area3D
* 2D: Node2D, Sprite2D, CharacterBody2D, RigidBody2D, StaticBody2D, Camera2D, CollisionShape2D, Area2D, TileMapLayer
* UI: Control, Label, Button, TextEdit, Panel, VBoxContainer, HBoxContainer, MarginContainer
* Audio: AudioStreamPlayer, AudioStreamPlayer3D

The parent path uses "./" prefix for relative paths from scene root. E.g., "./World" means the "World" child of the root node.

| | |
| - | - |
| **Needs** | Summer Engine open with your project |
| **Effects** | writes files, changes the open project |
| **CLI** | `summer tool add-node --args '<json>'` |

**Use when:**

* building out scene structure node by node
* "add a Camera3D / DirectionalLight3D / Area2D / Timer to this scene"
* giving the player a child node for a hitbox, sprite, or audio player

**Do not use when:**

* placing an existing .tscn prefab or imported model — [`summer_instantiate_scene`](/mcp/tools/build#summer_instantiate_scene)
* 3+ related nodes or any computed placement — [`summer_run_script`](/mcp/tools/build#summer_run_script)

**Inputs:**

| Input | Type | Required | Description |
| - | - | - | - |
| `scenePath` | string | Yes | Target scene path, e.g. 'res\://main.tscn' |
| `parent` | string | Yes | Parent node path, e.g. './World' or './World/Enemies' |
| `type` | string | Yes | Summer Engine node type, e.g. 'MeshInstance3D', 'CharacterBody3D' |
| `name` | string | Yes | Name for the new node, e.g. 'Player', 'MainCamera' |

<Accordion title="Input JSON schema">
  ```json theme={null}
  {
    "type": "object",
    "properties": {
      "scenePath": {
        "type": "string",
        "description": "Target scene path, e.g. 'res://main.tscn'"
      },
      "parent": {
        "type": "string",
        "description": "Parent node path, e.g. './World' or './World/Enemies'"
      },
      "type": {
        "type": "string",
        "description": "Summer Engine node type, e.g. 'MeshInstance3D', 'CharacterBody3D'"
      },
      "name": {
        "type": "string",
        "description": "Name for the new node, e.g. 'Player', 'MainCamera'"
      }
    },
    "required": [
      "scenePath",
      "parent",
      "type",
      "name"
    ],
    "additionalProperties": false
  }
  ```
</Accordion>

**Output:** MCP text content holding JSON; errors set `isError`.

```json Example call theme={null}
{
  "name": "summer_add_node",
  "arguments": {
    "scenePath": "res://main.tscn",
    "parent": "./World",
    "type": "MeshInstance3D",
    "name": "Player"
  }
}
```

***

### summer\_align\_distribute\_3d

On the local MCP (`summer-engine` npm).

Align or equal-space an explicit ordered list of 3D subjects along one world-space axis, then save the exact target scene.

Every anchor and extent comes from visible descendant GeometryInstance3D world AABBs (evidence: visual\_aabb). The tool never uses editor selection and fails instead of fabricating bounds. It preserves each subject's authored basis and scale, translates only along the normalized axis, and records all changed transforms in one undoable editor operation.

Alignment modes use the first ordered subject's minimum, center, or maximum projected anchor. Distribution modes keep the first and last subjects fixed and honor caller order. distribute\_gaps accounts for each subject's projected half-extent and fails if the endpoint span cannot fit non-overlapping equal gaps. The compact result returns ordered before/after origins, resolved spacing, and numeric residuals under 5 KB. On an engine build that predates AlignDistribute3D the result is a structured engine\_lacks\_op failure naming the fallback.

| | |
| - | - |
| **Needs** | Summer Engine open with your project |
| **Effects** | writes files, changes the open project |
| **CLI** | `summer tool align-distribute-3d --args '<json>'` |

**Use when:**

* lining up props, stalls, pillars, or lights along one axis
* spacing a row of objects evenly by center or by visible edge gap

**Do not use when:**

* seating objects on a surface — [`summer_snap_to_surface`](/mcp/tools/build#summer_snap_to_surface) (alignment solves one axis only)
* the subjects have no visible GeometryInstance3D descendants (the tool fails instead of fabricating bounds)

**Inputs:**

| Input | Type | Required | Description |
| - | - | - | - |
| `scenePath` | string | Yes | Exact target scene, e.g. 'res\://levels/market.tscn'. Length 1 to 512. |
| `subjectPaths` | string\[] | Yes | Two to sixteen exact nonduplicate Node3D paths in the order to align or distribute. Items 2 to 16. |
| `axis` | any\[] | Yes | Finite, non-zero world axis \[x,y,z]; normalization is automatic. Items 3 to 3. |
| `mode` | "align\_min" \| "align\_center" \| "align\_max" \| "distribute\_centers" \| "distribute\_gaps" | Yes | Alignment anchor or equal-spacing policy. |

<Accordion title="Input JSON schema">
  ```json theme={null}
  {
    "type": "object",
    "properties": {
      "scenePath": {
        "type": "string",
        "minLength": 1,
        "maxLength": 512,
        "description": "Exact target scene, e.g. 'res://levels/market.tscn'."
      },
      "subjectPaths": {
        "type": "array",
        "items": {
          "type": "string",
          "minLength": 1,
          "maxLength": 256
        },
        "minItems": 2,
        "maxItems": 16,
        "description": "Two to sixteen exact nonduplicate Node3D paths in the order to align or distribute."
      },
      "axis": {
        "type": "array",
        "minItems": 3,
        "maxItems": 3,
        "items": [
          {
            "type": "number"
          },
          {
            "type": "number"
          },
          {
            "type": "number"
          }
        ],
        "description": "Finite, non-zero world axis [x,y,z]; normalization is automatic."
      },
      "mode": {
        "type": "string",
        "enum": [
          "align_min",
          "align_center",
          "align_max",
          "distribute_centers",
          "distribute_gaps"
        ],
        "description": "Alignment anchor or equal-spacing policy."
      }
    },
    "required": [
      "scenePath",
      "subjectPaths",
      "axis",
      "mode"
    ],
    "additionalProperties": false
  }
  ```
</Accordion>

**Output:** MCP text content holding JSON; errors set `isError`.

```json Example call theme={null}
{
  "name": "summer_align_distribute_3d",
  "arguments": {
    "scenePath": "res://levels/market.tscn",
    "subjectPaths": [
      "<subjectPath>"
    ],
    "axis": [
      "<axi>"
    ],
    "mode": "align_min"
  }
}
```

***

### summer\_api\_docs

On the local MCP (`summer-engine` npm).

Offline engine class-reference lookup — verify a property, method, signal, or constant BEFORE writing script code, instead of guessing names. No engine connection needed.

Returns for a class: inherits, brief description, properties (name/type/default), method signatures, signals, constants. Pass 'member' to fetch one member (e.g. class\_name:'BoxShape3D', member:'size' -> \{name:'size', type:'Vector3', default:'Vector3(1, 1, 1)'}). Unknown names return closest-match suggestions.

Entries list only members DECLARED on that class — walk 'inherits' for inherited ones (e.g. 'position' lives on Node3D, not MeshInstance3D). Data is compiled from the engine's class reference and stamped with the engine technical base it was generated from (technical\_base in every successful result) — trust it over training memory for version-sensitive APIs; descriptions are trimmed to one line. When the bundled reference is missing from this install, the result says so (api\_docs\_not\_installed) instead of guessing.

| | |
| - | - |
| **Needs** | No open editor and no sign-in |
| **Effects** | read-only |
| **CLI** | `summer tool api-docs --args '<json>'` |

**Use when:**

* checking an exact property/method/signal/constant name or default before [`summer_run_script`](/mcp/tools/build#summer_run_script) or a .gd edit
* "does Node3D have look\_at?" / "what is the CharacterBody3D velocity property called?"
* "which signal fires when a body enters an Area3D?"

**Do not use when:**

* the bundled reference is missing from this install (the tool says api\_docs\_not\_installed) — verify against the engine with [`summer_inspect_node`](/mcp/tools/build#summer_inspect_node) instead
* you need the live value of a property on a node in the scene — [`summer_inspect_node`](/mcp/tools/build#summer_inspect_node)

**Inputs:**

| Input | Type | Required | Description |
| - | - | - | - |
| `class_name` | string | Yes | Engine class name, e.g. 'BoxShape3D', 'CharacterBody3D', 'SurfaceTool'. Case-insensitive. |
| `member` | string | No | Optional property/method/signal/constant name to fetch just that member, e.g. 'size' or 'move\_and\_slide'. |

<Accordion title="Input JSON schema">
  ```json theme={null}
  {
    "type": "object",
    "properties": {
      "class_name": {
        "type": "string",
        "description": "Engine class name, e.g. 'BoxShape3D', 'CharacterBody3D', 'SurfaceTool'. Case-insensitive."
      },
      "member": {
        "type": "string",
        "description": "Optional property/method/signal/constant name to fetch just that member, e.g. 'size' or 'move_and_slide'."
      }
    },
    "required": [
      "class_name"
    ],
    "additionalProperties": false
  }
  ```
</Accordion>

**Output:** MCP text content holding JSON; errors set `isError`. From the tool's own description: Returns for a class: inherits, brief description, properties (name/type/default), method signatures, signals, constants.

```json Example call theme={null}
{
  "name": "summer_api_docs",
  "arguments": {
    "class_name": "BoxShape3D"
  }
}
```

***

### summer\_attach\_to\_surface

On the local MCP (`summer-engine` npm).

Mount a piece on a surface: turn it so its given LOCAL backAxis faces into the surface (opposite the hit normal) with its upAxis kept toward worldUp, then seat its measured back face (the extreme of its visible bounds along backAxis, not its origin) at standoff from the surface. Pipes, gutters, lamps, AC units, signs, fire escapes. Place the piece near its mount first ([`summer_instantiate_scene`](/mcp/tools/build#summer_instantiate_scene) with position); this tool turns it and pushes it onto the surface.

Find the surface with surface (a node: the ray runs from the subject's origin to the nearest point of that node's bounds) or ray \{origin, direction} (both: the ray, and hits on other nodes are skipped). The ray is physics first; if physics finds nothing it falls back to visual AABBs and says so (the normal is then an AABB face normal). Get backAxis from [`summer_inspect_asset`](/mcp/tools/build#summer_inspect_asset) (the piece's back plane normal), not from a guess.

placeAt "current" (default): the piece keeps its height and its place along the surface and only moves along the surface normal. placeAt "hit": it also slides so the centre of its back face lands on the ray hit point.

Steps (existing ops): a read-only probe (RunSceneScript) reads the piece's bounds in its own axes and casts the ray; one SetProp turns the piece and puts its back face 5 cm in front of the planned seat; SnapToSurface sweeps it along -normal (at most standoff + 0.3) and seats it at standoff (its own physics/visual\_aabb evidence). Before saving, the seat is checked:

* with surface: the seat must be on that node (or inside it), else it is refused;
* with a ray only: a seat on another node is refused unless it lies on the hit plane (a coplanar neighbour module, warned);
* the piece must end within maxMove (default 2) of where it started; a longer planned move is refused before anything changes, and so is (with placeAt "current") a ray hit farther than maxMove along the surface from the piece (hit\_far\_from\_piece: aim at the piece, or pass placeAt "hit").
  A refused or failed seat puts the piece back where it started (restored: true), saves nothing, and names the cause: seated\_on, the seat's failure\_reason, blockers \{overlapping, overlaps, first\_contact} and a next\_step.

Returns \{seated\_on, final\_gap (collider gap from SnapToSurface), back\_face\_gap (visible back face to the hit plane), moved\_by, surface\_hit, orientation, back\_face\_offset, seat \{evidence, supportPath, finalGap, gapErrorBound, initiallyOverlapping, ...}, saved, warnings}. A warning visible\_back\_X\_into\_surface means the piece's collider sits behind its visible back: add X to standoff.

| | |
| - | - |
| **Needs** | Summer Engine open with your project |
| **Effects** | writes files, changes the open project |
| **CLI** | `summer tool attach-to-surface --args '<json>'` |

**Use when:**

* mounting a downpipe, gutter, lamp, AC unit, sign or fire escape on a facade
* turning a piece so its back faces a wall instead of guessing its rotation
* seating a piece against a surface at an exact standoff

**Do not use when:**

* seating a prop on a floor without turning it — [`summer_snap_to_surface`](/mcp/tools/build#summer_snap_to_surface)
* joining a pipe to another pipe's end — [`summer_connect_ports`](/mcp/tools/build#summer_connect_ports)

**Inputs:**

| Input | Type | Required | Description |
| - | - | - | - |
| `scenePath` | string | Yes | Exact scene to read or change, e.g. 'res\://levels/street.tscn'. It must be open in the editor (any tab). Length 1 to 512. |
| `subject` | string | Yes | Piece to mount: exact node path relative to the scene root, e.g. './Facade/Wall\_01'. Length 1 to 256. |
| `surface` | string | No | Surface node (wall, ceiling, floor). Without ray, the ray runs from the subject's origin to the nearest point of this node's bounds; with ray, hits on other nodes are skipped. The seat must land on this node: a seat on any other node is refused and the piece is put back: exact node path relative to the scene root, e.g. './Facade/Wall\_01'. Length 1 to 256. |
| `ray` | object | No | Explicit ray that finds the surface plane and its normal. Pass this or surface (or both). |
| `ray.origin` | any\[] | Yes | Ray start \[x, y, z] in scene space, e.g. a point in front of the wall. Items 3 to 3. |
| `ray.direction` | any\[] | Yes | Ray direction \[x, y, z], e.g. toward the wall. Items 3 to 3. |
| `placeAt` | "current" \| "hit" | No | current (default): the piece keeps its height and its place along the surface and only moves along the surface normal, so its measured back face ends at standoff from the surface. hit: it also slides along the surface so the centre of its back face lands on the ray hit point (its height then follows the ray). Default `"current"`. |
| `maxMove` | number | No | Refuse, changing nothing, when the piece would end farther than this from where it starts (scene units). Place the piece near its mount first; raise this only for a deliberate long move. Default `2`. Range … to 100. |
| `backAxis` | "+x" \| "-x" \| "+y" \| "-y" \| "+z" \| "-z" | No | The subject's LOCAL axis that must face into the surface, e.g. '-z' for a piece whose back is -Z. Measure it first with summer\_inspect\_asset. Default `"-z"`. |
| `upAxis` | any | No | The subject's LOCAL axis kept closest to worldUp. Must not be on the same line as backAxis. Default `"+y"`. |
| `worldUp` | any | No | World direction the upAxis should follow (projected onto the surface). Default `[0,1,0]`. |
| `standoff` | number | No | Gap between the subject's back face and the surface, in scene units. Default `0`. Range 0 to 10. |
| `maxDistance` | number | No | Maximum ray length when looking for the surface. Default `20`. Range … to 1000. |
| `collisionMask` | integer | No | Godot 3D physics layer mask for physics queries. Default `4294967295`. Range 0 to 4294967295. |

<Accordion title="Input JSON schema">
  ```json theme={null}
  {
    "type": "object",
    "properties": {
      "scenePath": {
        "type": "string",
        "minLength": 1,
        "maxLength": 512,
        "description": "Exact scene to read or change, e.g. 'res://levels/street.tscn'. It must be open in the editor (any tab)."
      },
      "subject": {
        "type": "string",
        "minLength": 1,
        "maxLength": 256,
        "description": "Piece to mount: exact node path relative to the scene root, e.g. './Facade/Wall_01'."
      },
      "surface": {
        "type": "string",
        "minLength": 1,
        "maxLength": 256,
        "description": "Surface node (wall, ceiling, floor). Without ray, the ray runs from the subject's origin to the nearest point of this node's bounds; with ray, hits on other nodes are skipped. The seat must land on this node: a seat on any other node is refused and the piece is put back: exact node path relative to the scene root, e.g. './Facade/Wall_01'."
      },
      "ray": {
        "type": "object",
        "properties": {
          "origin": {
            "type": "array",
            "minItems": 3,
            "maxItems": 3,
            "items": [
              {
                "type": "number"
              },
              {
                "$ref": "#/properties/ray/properties/origin/items/0"
              },
              {
                "$ref": "#/properties/ray/properties/origin/items/0"
              }
            ],
            "description": "Ray start [x, y, z] in scene space, e.g. a point in front of the wall."
          },
          "direction": {
            "type": "array",
            "minItems": 3,
            "maxItems": 3,
            "items": [
              {
                "$ref": "#/properties/ray/properties/origin/items/0"
              },
              {
                "$ref": "#/properties/ray/properties/origin/items/0"
              },
              {
                "$ref": "#/properties/ray/properties/origin/items/0"
              }
            ],
            "description": "Ray direction [x, y, z], e.g. toward the wall."
          }
        },
        "required": [
          "origin",
          "direction"
        ],
        "additionalProperties": false,
        "description": "Explicit ray that finds the surface plane and its normal. Pass this or surface (or both)."
      },
      "placeAt": {
        "type": "string",
        "enum": [
          "current",
          "hit"
        ],
        "default": "current",
        "description": "current (default): the piece keeps its height and its place along the surface and only moves along the surface normal, so its measured back face ends at standoff from the surface. hit: it also slides along the surface so the centre of its back face lands on the ray hit point (its height then follows the ray)."
      },
      "maxMove": {
        "type": "number",
        "exclusiveMinimum": 0,
        "maximum": 100,
        "default": 2,
        "description": "Refuse, changing nothing, when the piece would end farther than this from where it starts (scene units). Place the piece near its mount first; raise this only for a deliberate long move."
      },
      "backAxis": {
        "type": "string",
        "enum": [
          "+x",
          "-x",
          "+y",
          "-y",
          "+z",
          "-z"
        ],
        "default": "-z",
        "description": "The subject's LOCAL axis that must face into the surface, e.g. '-z' for a piece whose back is -Z. Measure it first with summer_inspect_asset."
      },
      "upAxis": {
        "$ref": "#/properties/backAxis",
        "default": "+y",
        "description": "The subject's LOCAL axis kept closest to worldUp. Must not be on the same line as backAxis."
      },
      "worldUp": {
        "$ref": "#/properties/ray/properties/direction",
        "default": [
          0,
          1,
          0
        ],
        "description": "World direction the upAxis should follow (projected onto the surface)."
      },
      "standoff": {
        "type": "number",
        "minimum": 0,
        "maximum": 10,
        "default": 0,
        "description": "Gap between the subject's back face and the surface, in scene units."
      },
      "maxDistance": {
        "type": "number",
        "exclusiveMinimum": 0,
        "maximum": 1000,
        "default": 20,
        "description": "Maximum ray length when looking for the surface."
      },
      "collisionMask": {
        "type": "integer",
        "minimum": 0,
        "maximum": 4294967295,
        "default": 4294967295,
        "description": "Godot 3D physics layer mask for physics queries."
      }
    },
    "required": [
      "scenePath",
      "subject"
    ],
    "additionalProperties": false
  }
  ```
</Accordion>

**Output:** MCP text content holding JSON; errors set `isError`. From the tool's own description: Returns \{seated\_on, final\_gap (collider gap from SnapToSurface), back\_face\_gap (visible back face to the hit plane), moved\_by, surface\_hit, orientation, back\_face\_offset, seat \{evidence, supportPath, finalGap, gapErrorBound, initiallyOverlapping, ...}, saved, warnings}.

```json Example call theme={null}
{
  "name": "summer_attach_to_surface",
  "arguments": {
    "scenePath": "res://levels/street.tscn",
    "subject": "./Facade/Wall_01"
  }
}
```

***

### summer\_batch

On the local MCP (`summer-engine` npm).

Execute multiple operations in a single call. Each op is forwarded to the engine VERBATIM, so this is also how you reach engine ops that have no dedicated tool.

UNDO: when nothing in the list forces a split (see the single-op contract below), the whole batch is ONE undo step — the user undoes everything with a single Ctrl+Z. When single-only ops are present the list is split into sequential requests and EACH chunk is its own undo step (one Ctrl+Z per chunk; the receipt shows the chunks). Use this when building something that involves multiple nodes and properties — e.g., creating a player character with collision, camera, and properties.

Each op in the array uses the same format as the individual tools:

* \{"op": "AddNode", "parent": "/", "type": "MeshInstance3D", "name": "Floor"}
* \{"op": "SetProp", "path": "Floor", "key": "position", "value": "Vector3(0, -1, 0)"}
* \{"op": "SetProp", "path": "Floor", "key": "mesh", "value": "PlaneMesh"}
* \{"op": "SetResourceProperty", "nodePath": "Floor", "resourceProperty": "mesh", "subProperty": "size", "value": "Vector2(20, 20)"}

RAW RUNTIME OPS (interactive verification — structured failure\_reason passes through verbatim):

* RunVerification — spawn a hidden, disposable game instance that runs a GDScript probe and dies (never touches the editor): \{"op": "RunVerification", "probe\_source": "...", "max\_seconds": 20}. Returns \{ok, results, frames, out\_dir}. Probe API: report(name, value) / save\_frame(name) / press(action) / key(keycode) / finish(). save\_frame REQUIRES a name argument — save\_frame() with no args is a script error. Mount scenes deferred: get\_tree().root.add\_child.call\_deferred(instance); await get\_tree().process\_frame; await settle() — a direct add\_child in \_ready can hit the parent-busy guard and capture a black frame.
* SimulateInput — inject an action/key/mouse/axis into the RUNNING game ([`summer_play`](/mcp/tools/run-and-test#summer_play) first): \{"op": "SimulateInput", "type": "action", "action": "jump", "pressed": true}. It MUST be sent alone (single-op batch). failure\_reason "not\_running" = start the game first; "unsupported" = the running game build predates the handler — fall back to RunVerification or ask the user.

A raw ReplaceNode with scene is refused (it saves the old scene reference); use [`summer_replace_node`](/mcp/tools/build#summer_replace_node).
A raw ConnectSignal is refused (the engine connects without CONNECT\_PERSIST, so the file never holds it); use [`summer_connect_signal`](/mcp/tools/build#summer_connect_signal).

REPARENTNODE KEEPS ITS SUBTREE AND IS VERIFIED: the engine's ReparentNode re-owns only the moved node, so its children and grandchildren were dropped from the saved file. A batch with ReparentNode saves first, reads the saved .tscn, sends each ReparentNode in its own request with an in-place ReparentNode (same parent, same index) per scene-owned descendant to give it back to the scene, then reads the saved file again: persisted:true / verified:true only when every moved node and descendant is at its new path; otherwise an error with failure\_reason not\_persisted. A move onto a parent that already has a child of that name is refused (failure\_reason name\_collision). The scenePath must be a .tscn, and Undo cannot share the batch.

Do not mix OpenScene with scene mutations in one batch. OpenScene is a UI action;
send it separately. scenePath selects every mutation target. The tool appends one
final SaveScene when the batch mutates a scene; if supplied explicitly, SaveScene
must appear exactly once and be the final operation. The engine requires
SaveScene, InstantiateScene, ReplaceNode, SimulateInput, the runtime reads
(GetRuntimeSceneTree/GetRuntimeNode), and the Run\*/Import\*
ops to travel as their own request, so this tool automatically splits your op
list into sequential requests around them — each split chunk is its own undo
step (NOT one step for the whole batch), and if a later chunk fails the receipt
reports exactly which earlier ops already applied.

PLACED INSTANCES: an InstantiateScene op may also carry position, rotation\_degrees, scale (\[x, y, z] or "Vector3(...)") or transform ("Transform3D(...)"); the tool sets them on the created node. One op per piece. Other ops are forwarded verbatim. Cost: each InstantiateScene is its own engine request (the engine requires it); the transforms of a run of InstantiateScene ops are then sent together (up to 200 per request) before the next other op, so N placed pieces plus the save cost about N + 2 requests and N + 2 undo steps. Every later op (a SetProp, SnapToSurface, the save) sees the pieces already placed; if an InstantiateScene fails, the pieces created before it still get their transforms.

RECEIPTS: receipt "summary" returns only counts, failures \[\{index, op, error}] (index = position in your ops list), created node paths and renames, under 5 KB with any cut declared. Use it for any batch over a few ops; the full receipt of a large batch overflows the tool-output limit.

scenePersistence.saved means the SaveScene ran; it does not prove what the file
holds. verified:true is set only where the tool read the saved file back.

| | |
| - | - |
| **Needs** | Summer Engine open with your project |
| **Effects** | writes files, changes the open project |
| **CLI** | `summer tool batch --args '<json>'` |

**Use when:**

* multi-node builds that should undo as one step (no single-only ops in the list)
* reaching engine ops that have no dedicated tool
* placing many kit pieces, one InstantiateScene op per piece with its position and rotation, read back with receipt summary

**Do not use when:**

* you need the whole list to be exactly one undo step but it contains a single-only op (the engine splits it; expect one undo step per chunk)
* connecting a signal — a raw ConnectSignal is refused; use [`summer_connect_signal`](/mcp/tools/build#summer_connect_signal)

**Inputs:**

| Input | Type | Required | Description |
| - | - | - | - |
| `scenePath` | string | No | Required when ops contains scene mutations; exact res\:// target scene path |
| `ops` | object\[] | Yes | Array of operation objects, each with 'op' plus its parameters |
| `receipt` | "full" \| "summary" | No | full (default): every engine receipt. summary: counts, failures with op index, created node paths only (under 5 KB). |

<Accordion title="Input JSON schema">
  ```json theme={null}
  {
    "type": "object",
    "properties": {
      "scenePath": {
        "type": "string",
        "description": "Required when ops contains scene mutations; exact res:// target scene path"
      },
      "ops": {
        "type": "array",
        "items": {
          "type": "object",
          "additionalProperties": {}
        },
        "description": "Array of operation objects, each with 'op' plus its parameters"
      },
      "receipt": {
        "type": "string",
        "enum": [
          "full",
          "summary"
        ],
        "description": "full (default): every engine receipt. summary: counts, failures with op index, created node paths only (under 5 KB)."
      }
    },
    "required": [
      "ops"
    ],
    "additionalProperties": false
  }
  ```
</Accordion>

**Output:** MCP text content holding JSON; errors set `isError`. From the tool's own description: Returns \{ok, results, frames, out\_dir}.

```json Example call theme={null}
{
  "name": "summer_batch",
  "arguments": {
    "ops": [
      {}
    ]
  }
}
```

***

### summer\_board\_agent\_cancel

On the hosted MCP.

Stop a queued or running board agent task. Work it already saved stays on the board.

| | |
| - | - |
| **Needs** | Your Summer account (OAuth). In the npm MCP: `summer login --store` |
| **Hints** | `idempotentHint` |

**Inputs:**

| Input | Type | Required | Description |
| - | - | - | - |
| `boardId` | string | Yes | |
| `taskId` | string | Yes | |

<Accordion title="Input JSON schema">
  ```json theme={null}
  {
    "type": "object",
    "properties": {
      "boardId": {
        "type": "string",
        "format": "uuid",
        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
      },
      "taskId": {
        "type": "string",
        "format": "uuid",
        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
      }
    },
    "required": [
      "boardId",
      "taskId"
    ]
  }
  ```
</Accordion>

**Output:** MCP text content holding JSON; errors set `isError`.

```json Example call theme={null}
{
  "name": "summer_board_agent_cancel",
  "arguments": {
    "boardId": "<boardId>",
    "taskId": "<taskId>"
  }
}
```

***

### summer\_board\_agent\_run

On the hosted MCP.

Ask the board's own agent to work on the board, as typing in Studio does: it reads, edits, draws pictures and answers on the board. Paid: spends the board sponsor's Summer credits. Needs contextRevision from [`summer_board_read`](/mcp/tools/build#summer_board_read). Returns a task; poll [`summer_board_agent_task`](/mcp/tools/build#summer_board_agent_task).

| | |
| - | - |
| **Needs** | Your Summer account (OAuth). In the npm MCP: `summer login --store` |
| **Hints** | `idempotentHint`, `openWorldHint` |

**Inputs:**

| Input | Type | Required | Description |
| - | - | - | - |
| `boardId` | string | Yes | |
| `prompt` | string | Yes | Length 1 to 20000. |
| `contextRevision` | integer | Yes | Range 0 to 9007199254740991. |
| `topicId` | string | No | Length 1 to 64. |
| `references` | object\[] | No | Items 0 to 50. |
| `references[].itemId` | string | Yes | Length 1 to 64. |
| `references[].kind` | "item" \| "group" | No | |
| `references[].assetRevision` | integer | No | Range 0 to 9007199254740991. |
| `references[].groupRevision` | integer | No | Range 0 to 9007199254740991. |
| `references[].role` | string | No | Length 0 to 500. |
| `requestId` | string | No | Stable retry key (UUID). Reuse it only to retry the identical request; omit for a new one. |

<Accordion title="Input JSON schema">
  ```json theme={null}
  {
    "type": "object",
    "properties": {
      "boardId": {
        "type": "string",
        "format": "uuid",
        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
      },
      "prompt": {
        "type": "string",
        "minLength": 1,
        "maxLength": 20000
      },
      "contextRevision": {
        "type": "integer",
        "minimum": 0,
        "maximum": 9007199254740991
      },
      "topicId": {
        "type": "string",
        "minLength": 1,
        "maxLength": 64
      },
      "references": {
        "maxItems": 50,
        "type": "array",
        "items": {
          "type": "object",
          "properties": {
            "itemId": {
              "type": "string",
              "minLength": 1,
              "maxLength": 64
            },
            "kind": {
              "type": "string",
              "enum": [
                "item",
                "group"
              ]
            },
            "assetRevision": {
              "type": "integer",
              "minimum": 0,
              "maximum": 9007199254740991
            },
            "groupRevision": {
              "type": "integer",
              "minimum": 0,
              "maximum": 9007199254740991
            },
            "role": {
              "type": "string",
              "maxLength": 500
            }
          },
          "required": [
            "itemId"
          ],
          "additionalProperties": false
        }
      },
      "requestId": {
        "description": "Stable retry key (UUID). Reuse it only to retry the identical request; omit for a new one.",
        "type": "string",
        "format": "uuid",
        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
      }
    },
    "required": [
      "boardId",
      "prompt",
      "contextRevision"
    ]
  }
  ```
</Accordion>

**Output:** MCP text content holding JSON; errors set `isError`. From the tool's own description: Returns a task; poll summer\_board\_agent\_task.

```json Example call theme={null}
{
  "name": "summer_board_agent_run",
  "arguments": {
    "boardId": "<boardId>",
    "prompt": "<prompt>",
    "contextRevision": 0
  }
}
```

***

### summer\_board\_agent\_task

On the hosted MCP.

One board agent task: its status, reply and what it changed.

| | |
| - | - |
| **Needs** | Your Summer account (OAuth). In the npm MCP: `summer login --store` |
| **Hints** | `readOnlyHint` |

**Inputs:**

| Input | Type | Required | Description |
| - | - | - | - |
| `boardId` | string | Yes | |
| `taskId` | string | Yes | |

<Accordion title="Input JSON schema">
  ```json theme={null}
  {
    "type": "object",
    "properties": {
      "boardId": {
        "type": "string",
        "format": "uuid",
        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
      },
      "taskId": {
        "type": "string",
        "format": "uuid",
        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
      }
    },
    "required": [
      "boardId",
      "taskId"
    ]
  }
  ```
</Accordion>

**Output:** MCP text content holding JSON; errors set `isError`.

```json Example call theme={null}
{
  "name": "summer_board_agent_task",
  "arguments": {
    "boardId": "<boardId>",
    "taskId": "<taskId>"
  }
}
```

***

### summer\_board\_agent\_tasks

On the hosted MCP.

The board agent's tasks on this board, with their replies.

| | |
| - | - |
| **Needs** | Your Summer account (OAuth). In the npm MCP: `summer login --store` |
| **Hints** | `readOnlyHint` |

**Inputs:**

| Input | Type | Required | Description |
| - | - | - | - |
| `boardId` | string | Yes | |

<Accordion title="Input JSON schema">
  ```json theme={null}
  {
    "type": "object",
    "properties": {
      "boardId": {
        "type": "string",
        "format": "uuid",
        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
      }
    },
    "required": [
      "boardId"
    ]
  }
  ```
</Accordion>

**Output:** MCP text content holding JSON; errors set `isError`.

```json Example call theme={null}
{
  "name": "summer_board_agent_tasks",
  "arguments": {
    "boardId": "<boardId>"
  }
}
```

***

### summer\_board\_build

On the hosted MCP.

Build a playable game from a saved Game Soul version (soulVersionId from [`summer_board_game_soul`](/mcp/tools/build#summer_board_game_soul)), as Build in Studio does. Paid: spends the board sponsor's Summer credits. Returns a build; poll [`summer_board_build_status`](/mcp/tools/build#summer_board_build_status).

| | |
| - | - |
| **Needs** | Your Summer account (OAuth). In the npm MCP: `summer login --store` |
| **Hints** | `idempotentHint`, `openWorldHint` |

**Inputs:**

| Input | Type | Required | Description |
| - | - | - | - |
| `boardId` | string | Yes | |
| `soulVersionId` | string | Yes | |
| `requestId` | string | No | Stable retry key (UUID). Reuse it only to retry the identical request; omit for a new one. |

<Accordion title="Input JSON schema">
  ```json theme={null}
  {
    "type": "object",
    "properties": {
      "boardId": {
        "type": "string",
        "format": "uuid",
        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
      },
      "soulVersionId": {
        "type": "string",
        "format": "uuid",
        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
      },
      "requestId": {
        "description": "Stable retry key (UUID). Reuse it only to retry the identical request; omit for a new one.",
        "type": "string",
        "format": "uuid",
        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
      }
    },
    "required": [
      "boardId",
      "soulVersionId"
    ]
  }
  ```
</Accordion>

**Output:** MCP text content holding JSON; errors set `isError`. From the tool's own description: Returns a build; poll summer\_board\_build\_status.

```json Example call theme={null}
{
  "name": "summer_board_build",
  "arguments": {
    "boardId": "<boardId>",
    "soulVersionId": "<soulVersionId>"
  }
}
```

***

### summer\_board\_build\_cancel

On the hosted MCP.

Stop a board build that has not finished.

| | |
| - | - |
| **Needs** | Your Summer account (OAuth). In the npm MCP: `summer login --store` |
| **Hints** | `idempotentHint` |

**Inputs:**

| Input | Type | Required | Description |
| - | - | - | - |
| `boardId` | string | Yes | |
| `buildId` | string | Yes | |

<Accordion title="Input JSON schema">
  ```json theme={null}
  {
    "type": "object",
    "properties": {
      "boardId": {
        "type": "string",
        "format": "uuid",
        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
      },
      "buildId": {
        "type": "string",
        "format": "uuid",
        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
      }
    },
    "required": [
      "boardId",
      "buildId"
    ]
  }
  ```
</Accordion>

**Output:** MCP text content holding JSON; errors set `isError`.

```json Example call theme={null}
{
  "name": "summer_board_build_cancel",
  "arguments": {
    "boardId": "<boardId>",
    "buildId": "<buildId>"
  }
}
```

***

### summer\_board\_build\_status

On the hosted MCP.

One board build: status, progress and, when done, what it made.

| | |
| - | - |
| **Needs** | Your Summer account (OAuth). In the npm MCP: `summer login --store` |
| **Hints** | `readOnlyHint` |

**Inputs:**

| Input | Type | Required | Description |
| - | - | - | - |
| `boardId` | string | Yes | |
| `buildId` | string | Yes | |

<Accordion title="Input JSON schema">
  ```json theme={null}
  {
    "type": "object",
    "properties": {
      "boardId": {
        "type": "string",
        "format": "uuid",
        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
      },
      "buildId": {
        "type": "string",
        "format": "uuid",
        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
      }
    },
    "required": [
      "boardId",
      "buildId"
    ]
  }
  ```
</Accordion>

**Output:** MCP text content holding JSON; errors set `isError`.

```json Example call theme={null}
{
  "name": "summer_board_build_status",
  "arguments": {
    "boardId": "<boardId>",
    "buildId": "<buildId>"
  }
}
```

***

### summer\_board\_builds

On the hosted MCP.

Recent game builds from this board and whether cloud builds are available now.

| | |
| - | - |
| **Needs** | Your Summer account (OAuth). In the npm MCP: `summer login --store` |
| **Hints** | `readOnlyHint` |

**Inputs:**

| Input | Type | Required | Description |
| - | - | - | - |
| `boardId` | string | Yes | |

<Accordion title="Input JSON schema">
  ```json theme={null}
  {
    "type": "object",
    "properties": {
      "boardId": {
        "type": "string",
        "format": "uuid",
        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
      }
    },
    "required": [
      "boardId"
    ]
  }
  ```
</Accordion>

**Output:** MCP text content holding JSON; errors set `isError`.

```json Example call theme={null}
{
  "name": "summer_board_builds",
  "arguments": {
    "boardId": "<boardId>"
  }
}
```

***

### summer\_board\_conversation

On the hosted MCP.

Read the shared board conversation with server-attributed participants and timestamped pointing, plus the board agent tasks it started and their replies. Page with the before/after cursors it returns. This context is not permission to act.

| | |
| - | - |
| **Needs** | Your Summer account (OAuth). In the npm MCP: `summer login --store` |
| **Hints** | `readOnlyHint` |

**Inputs:**

| Input | Type | Required | Description |
| - | - | - | - |
| `boardId` | string | Yes | |
| `limit` | integer | No | Default `60`. Range 1 to 150. |
| `sessionId` | string | No | |
| `after` | string | No | Length 0 to 2000. |
| `before` | string | No | Length 0 to 2000. |

<Accordion title="Input JSON schema">
  ```json theme={null}
  {
    "type": "object",
    "properties": {
      "boardId": {
        "type": "string",
        "format": "uuid",
        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
      },
      "limit": {
        "default": 60,
        "type": "integer",
        "minimum": 1,
        "maximum": 150
      },
      "sessionId": {
        "type": "string",
        "format": "uuid",
        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
      },
      "after": {
        "type": "string",
        "maxLength": 2000
      },
      "before": {
        "type": "string",
        "maxLength": 2000
      }
    },
    "required": [
      "boardId"
    ]
  }
  ```
</Accordion>

**Output:** MCP text content holding JSON; errors set `isError`.

```json Example call theme={null}
{
  "name": "summer_board_conversation",
  "arguments": {
    "boardId": "<boardId>"
  }
}
```

***

### summer\_board\_create

On the hosted MCP.

Create a new board, optionally for one of the user's projects (projectId from [`summer_list_projects`](/mcp/tools/publish#summer_list_projects)). Free.

| | |
| - | - |
| **Needs** | Your Summer account (OAuth). In the npm MCP: `summer login --store` |

**Inputs:**

| Input | Type | Required | Description |
| - | - | - | - |
| `title` | string | No | Length 0 to 400. |
| `projectId` | string | No | |
| `workspaceId` | string | No | |

<Accordion title="Input JSON schema">
  ```json theme={null}
  {
    "type": "object",
    "properties": {
      "title": {
        "type": "string",
        "maxLength": 400
      },
      "projectId": {
        "type": "string",
        "format": "uuid",
        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
      },
      "workspaceId": {
        "type": "string",
        "format": "uuid",
        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
      }
    }
  }
  ```
</Accordion>

**Output:** MCP text content holding JSON; errors set `isError`.

```json Example call theme={null}
{
  "name": "summer_board_create",
  "arguments": {}
}
```

***

### summer\_board\_edit

On the hosted MCP.

Apply an explicitly requested edit as one atomic batch. Never overwrite whole board snapshots. Patch expected fields must match their fieldRevisions from [`summer_board_read`](/mcp/tools/build#summer_board_read); unrelated changes merge. Reuse requestId only for the identical retry.

| | |
| - | - |
| **Needs** | Your Summer account (OAuth). In the npm MCP: `summer login --store` |
| **Hints** | `destructiveHint`, `idempotentHint` |

**Inputs:**

| Input | Type | Required | Description |
| - | - | - | - |
| `boardId` | string | Yes | |
| `batch` | object | Yes | |
| `batch.requestId` | string | Yes | |
| `batch.baseRevision` | integer | Yes | Range 0 to 9007199254740991. |
| `batch.commands` | object\[] | Yes | Items 1 to 100. |

<Accordion title="Input JSON schema">
  ```json theme={null}
  {
    "type": "object",
    "properties": {
      "boardId": {
        "type": "string",
        "format": "uuid",
        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
      },
      "batch": {
        "type": "object",
        "properties": {
          "requestId": {
            "type": "string",
            "format": "uuid",
            "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
          },
          "baseRevision": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991
          },
          "commands": {
            "minItems": 1,
            "maxItems": 100,
            "type": "array",
            "items": {
              "anyOf": [
                {
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "const": "registerType"
                    },
                    "definition": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string",
                          "minLength": 1,
                          "maxLength": 48,
                          "pattern": "^[a-zA-Z][a-zA-Z0-9_-]*$"
                        },
                        "version": {
                          "type": "integer",
                          "minimum": 1,
                          "maximum": 10000
                        },
                        "label": {
                          "type": "string",
                          "minLength": 1,
                          "maxLength": 120
                        },
                        "description": {
                          "type": "string",
                          "maxLength": 1000
                        },
                        "properties": {
                          "maxItems": 40,
                          "type": "array",
                          "items": {
                            "anyOf": [
                              {
                                "type": "object",
                                "properties": {
                                  "key": {
                                    "type": "string",
                                    "minLength": 1,
                                    "maxLength": 48,
                                    "pattern": "^[a-zA-Z][a-zA-Z0-9_-]*$"
                                  },
                                  "label": {
                                    "type": "string",
                                    "minLength": 1,
                                    "maxLength": 120
                                  },
                                  "required": {
                                    "type": "boolean"
                                  },
                                  "description": {
                                    "type": "string",
                                    "maxLength": 500
                                  },
                                  "kind": {
                                    "type": "string",
                                    "const": "text"
                                  }
                                },
                                "required": [
                                  "key",
                                  "label",
                                  "kind"
                                ],
                                "additionalProperties": false
                              },
                              {
                                "type": "object",
                                "properties": {
                                  "key": {
                                    "type": "string",
                                    "minLength": 1,
                                    "maxLength": 48,
                                    "pattern": "^[a-zA-Z][a-zA-Z0-9_-]*$"
                                  },
                                  "label": {
                                    "type": "string",
                                    "minLength": 1,
                                    "maxLength": 120
                                  },
                                  "required": {
                                    "type": "boolean"
                                  },
                                  "description": {
                                    "type": "string",
                                    "maxLength": 500
                                  },
                                  "kind": {
                                    "type": "string",
                                    "const": "number"
                                  }
                                },
                                "required": [
                                  "key",
                                  "label",
                                  "kind"
                                ],
                                "additionalProperties": false
                              },
                              {
                                "type": "object",
                                "properties": {
                                  "key": {
                                    "type": "string",
                                    "minLength": 1,
                                    "maxLength": 48,
                                    "pattern": "^[a-zA-Z][a-zA-Z0-9_-]*$"
                                  },
                                  "label": {
                                    "type": "string",
                                    "minLength": 1,
                                    "maxLength": 120
                                  },
                                  "required": {
                                    "type": "boolean"
                                  },
                                  "description": {
                                    "type": "string",
                                    "maxLength": 500
                                  },
                                  "kind": {
                                    "type": "string",
                                    "const": "boolean"
                                  }
                                },
                                "required": [
                                  "key",
                                  "label",
                                  "kind"
                                ],
                                "additionalProperties": false
                              },
                              {
                                "type": "object",
                                "properties": {
                                  "key": {
                                    "type": "string",
                                    "minLength": 1,
                                    "maxLength": 48,
                                    "pattern": "^[a-zA-Z][a-zA-Z0-9_-]*$"
                                  },
                                  "label": {
                                    "type": "string",
                                    "minLength": 1,
                                    "maxLength": 120
                                  },
                                  "required": {
                                    "type": "boolean"
                                  },
                                  "description": {
                                    "type": "string",
                                    "maxLength": 500
                                  },
                                  "kind": {
                                    "type": "string",
                                    "const": "choice"
                                  },
                                  "options": {
                                    "minItems": 1,
                                    "maxItems": 50,
                                    "type": "array",
                                    "items": {
                                      "type": "string",
                                      "minLength": 1,
                                      "maxLength": 120
                                    }
                                  }
                                },
                                "required": [
                                  "key",
                                  "label",
                                  "kind",
                                  "options"
                                ],
                                "additionalProperties": false
                              },
                              {
                                "type": "object",
                                "properties": {
                                  "key": {
                                    "type": "string",
                                    "minLength": 1,
                                    "maxLength": 48,
                                    "pattern": "^[a-zA-Z][a-zA-Z0-9_-]*$"
                                  },
                                  "label": {
                                    "type": "string",
                                    "minLength": 1,
                                    "maxLength": 120
                                  },
                                  "required": {
                                    "type": "boolean"
                                  },
                                  "description": {
                                    "type": "string",
                                    "maxLength": 500
                                  },
                                  "kind": {
                                    "type": "string",
                                    "const": "text-list"
                                  }
                                },
                                "required": [
                                  "key",
                                  "label",
                                  "kind"
                                ],
                                "additionalProperties": false
                              }
                            ]
                          }
                        },
                        "relations": {
                          "maxItems": 30,
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "key": {
                                "type": "string",
                                "minLength": 1,
                                "maxLength": 48,
                                "pattern": "^[a-zA-Z][a-zA-Z0-9_-]*$"
                              },
                              "label": {
                                "type": "string",
                                "minLength": 1,
                                "maxLength": 120
                              },
                              "targetTypeIds": {
                                "minItems": 1,
                                "maxItems": 30,
                                "type": "array",
                                "items": {
                                  "type": "string",
                                  "minLength": 1,
                                  "maxLength": 48,
                                  "pattern": "^[a-zA-Z][a-zA-Z0-9_-]*$"
                                }
                              },
                              "cardinality": {
                                "type": "string",
                                "enum": [
                                  "one",
                                  "many"
                                ]
                              },
                              "description": {
                                "type": "string",
                                "maxLength": 500
                              }
                            },
                            "required": [
                              "key",
                              "label",
                              "targetTypeIds",
                              "cardinality"
                            ],
                            "additionalProperties": false
                          }
                        }
                      },
                      "required": [
                        "id",
                        "version",
                        "label",
                        "properties",
                        "relations"
                      ],
                      "additionalProperties": false
                    }
                  },
                  "required": [
                    "type",
                    "definition"
                  ],
                  "additionalProperties": false
                },
                {
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "const": "create"
                    },
                    "collection": {
                      "type": "string",
                      "enum": [
                        "items",
                        "topics",
                        "groups",
                        "edges"
                      ]
                    },
                    "value": {
                      "type": "object",
                      "propertyNames": {
                        "type": "string"
                      },
                      "additionalProperties": {}
                    }
                  },
                  "required": [
                    "type",
                    "collection",
                    "value"
                  ],
                  "additionalProperties": false
                },
                {
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "const": "patch"
                    },
                    "collection": {
                      "type": "string",
                      "enum": [
                        "items",
                        "topics",
                        "groups",
                        "edges"
                      ]
                    },
                    "id": {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 64,
                      "pattern": "^[a-zA-Z0-9_-]+$"
                    },
                    "patch": {
                      "type": "object",
                      "propertyNames": {
                        "type": "string"
                      },
                      "additionalProperties": {}
                    },
                    "expected": {
                      "type": "object",
                      "propertyNames": {
                        "type": "string"
                      },
                      "additionalProperties": {
                        "type": "integer",
                        "minimum": 0,
                        "maximum": 9007199254740991
                      }
                    },
                    "expectedMembership": {
                      "type": "object",
                      "properties": {
                        "itemIds": {
                          "maxItems": 2000,
                          "type": "array",
                          "items": {
                            "type": "string",
                            "minLength": 1,
                            "maxLength": 64,
                            "pattern": "^[a-zA-Z0-9_-]+$"
                          }
                        },
                        "groupIds": {
                          "maxItems": 500,
                          "type": "array",
                          "items": {
                            "type": "string",
                            "minLength": 1,
                            "maxLength": 64,
                            "pattern": "^[a-zA-Z0-9_-]+$"
                          }
                        }
                      },
                      "required": [
                        "itemIds",
                        "groupIds"
                      ],
                      "additionalProperties": false
                    }
                  },
                  "required": [
                    "type",
                    "collection",
                    "id",
                    "patch",
                    "expected"
                  ],
                  "additionalProperties": false
                },
                {
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "const": "remove"
                    },
                    "collection": {
                      "type": "string",
                      "enum": [
                        "items",
                        "topics",
                        "groups",
                        "edges"
                      ]
                    },
                    "id": {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 64,
                      "pattern": "^[a-zA-Z0-9_-]+$"
                    },
                    "expectedRevision": {
                      "type": "integer",
                      "minimum": 0,
                      "maximum": 9007199254740991
                    }
                  },
                  "required": [
                    "type",
                    "collection",
                    "id",
                    "expectedRevision"
                  ],
                  "additionalProperties": false
                },
                {
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "const": "title"
                    },
                    "title": {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 200
                    },
                    "expectedRevision": {
                      "type": "integer",
                      "minimum": 0,
                      "maximum": 9007199254740991
                    }
                  },
                  "required": [
                    "type",
                    "title",
                    "expectedRevision"
                  ],
                  "additionalProperties": false
                }
              ]
            }
          }
        },
        "required": [
          "requestId",
          "baseRevision",
          "commands"
        ],
        "additionalProperties": false
      }
    },
    "required": [
      "boardId",
      "batch"
    ]
  }
  ```
</Accordion>

**Output:** MCP text content holding JSON; errors set `isError`.

```json Example call theme={null}
{
  "name": "summer_board_edit",
  "arguments": {
    "boardId": "<boardId>",
    "batch": {
      "requestId": "<requestId>",
      "baseRevision": 0,
      "commands": [
        {
          "type": "registerType",
          "definition": {}
        }
      ]
    }
  }
}
```

***

### summer\_board\_enable\_collaboration

On the hosted MCP.

Turn on shared editing for an older board (the board agent, builds and conversation need it). Safe to repeat.

| | |
| - | - |
| **Needs** | Your Summer account (OAuth). In the npm MCP: `summer login --store` |
| **Hints** | `idempotentHint` |

**Inputs:**

| Input | Type | Required | Description |
| - | - | - | - |
| `boardId` | string | Yes | |

<Accordion title="Input JSON schema">
  ```json theme={null}
  {
    "type": "object",
    "properties": {
      "boardId": {
        "type": "string",
        "format": "uuid",
        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
      }
    },
    "required": [
      "boardId"
    ]
  }
  ```
</Accordion>

**Output:** MCP text content holding JSON; errors set `isError`.

```json Example call theme={null}
{
  "name": "summer_board_enable_collaboration",
  "arguments": {
    "boardId": "<boardId>"
  }
}
```

***

### summer\_board\_events

On the hosted MCP.

Board changes since a revision (what Studio's live view receives): each committed operation with its revision. Pass the last revision you saw.

| | |
| - | - |
| **Needs** | Your Summer account (OAuth). In the npm MCP: `summer login --store` |
| **Hints** | `readOnlyHint` |

**Inputs:**

| Input | Type | Required | Description |
| - | - | - | - |
| `boardId` | string | Yes | |
| `after` | integer | No | Default `0`. Range 0 to 9007199254740991. |

<Accordion title="Input JSON schema">
  ```json theme={null}
  {
    "type": "object",
    "properties": {
      "boardId": {
        "type": "string",
        "format": "uuid",
        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
      },
      "after": {
        "default": 0,
        "type": "integer",
        "minimum": 0,
        "maximum": 9007199254740991
      }
    },
    "required": [
      "boardId"
    ]
  }
  ```
</Accordion>

**Output:** MCP text content holding JSON; errors set `isError`.

```json Example call theme={null}
{
  "name": "summer_board_events",
  "arguments": {
    "boardId": "<boardId>"
  }
}
```

***

### summer\_board\_game\_soul

On the hosted MCP.

Read immutable Game Soul versions and their exact reference assets, for continuing game development in a local engine or code assistant.

| | |
| - | - |
| **Needs** | Your Summer account (OAuth). In the npm MCP: `summer login --store` |
| **Hints** | `readOnlyHint` |

**Inputs:**

| Input | Type | Required | Description |
| - | - | - | - |
| `boardId` | string | Yes | |

<Accordion title="Input JSON schema">
  ```json theme={null}
  {
    "type": "object",
    "properties": {
      "boardId": {
        "type": "string",
        "format": "uuid",
        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
      }
    },
    "required": [
      "boardId"
    ]
  }
  ```
</Accordion>

**Output:** MCP text content holding JSON; errors set `isError`.

```json Example call theme={null}
{
  "name": "summer_board_game_soul",
  "arguments": {
    "boardId": "<boardId>"
  }
}
```

***

### summer\_board\_link\_project

On the hosted MCP.

Link a board to one of the user's projects (projectId from [`summer_list_projects`](/mcp/tools/publish#summer_list_projects)), so the game built from it opens that project.

| | |
| - | - |
| **Needs** | Your Summer account (OAuth). In the npm MCP: `summer login --store` |
| **Hints** | `idempotentHint` |

**Inputs:**

| Input | Type | Required | Description |
| - | - | - | - |
| `boardId` | string | Yes | |
| `projectId` | string | Yes | |

<Accordion title="Input JSON schema">
  ```json theme={null}
  {
    "type": "object",
    "properties": {
      "boardId": {
        "type": "string",
        "format": "uuid",
        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
      },
      "projectId": {
        "type": "string",
        "format": "uuid",
        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
      }
    },
    "required": [
      "boardId",
      "projectId"
    ]
  }
  ```
</Accordion>

**Output:** MCP text content holding JSON; errors set `isError`.

```json Example call theme={null}
{
  "name": "summer_board_link_project",
  "arguments": {
    "boardId": "<boardId>",
    "projectId": "<projectId>"
  }
}
```

***

### summer\_board\_list

On the hosted MCP.

List boards this authenticated Summer user can access.

| | |
| - | - |
| **Needs** | Your Summer account (OAuth). In the npm MCP: `summer login --store` |
| **Hints** | `readOnlyHint` |

**Inputs:**

No inputs.

<Accordion title="Input JSON schema">
  ```json theme={null}
  {
    "type": "object",
    "properties": {}
  }
  ```
</Accordion>

**Output:** MCP text content holding JSON; errors set `isError`.

```json Example call theme={null}
{
  "name": "summer_board_list",
  "arguments": {}
}
```

***

### summer\_board\_presence

On the hosted MCP.

Who is on the board right now, with their selection and topic.

| | |
| - | - |
| **Needs** | Your Summer account (OAuth). In the npm MCP: `summer login --store` |
| **Hints** | `readOnlyHint` |

**Inputs:**

| Input | Type | Required | Description |
| - | - | - | - |
| `boardId` | string | Yes | |

<Accordion title="Input JSON schema">
  ```json theme={null}
  {
    "type": "object",
    "properties": {
      "boardId": {
        "type": "string",
        "format": "uuid",
        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
      }
    },
    "required": [
      "boardId"
    ]
  }
  ```
</Accordion>

**Output:** MCP text content holding JSON; errors set `isError`.

```json Example call theme={null}
{
  "name": "summer_board_presence",
  "arguments": {
    "boardId": "<boardId>"
  }
}
```

***

### summer\_board\_project\_links

On the hosted MCP.

Which of the user's boards belong to which projects.

| | |
| - | - |
| **Needs** | Your Summer account (OAuth). In the npm MCP: `summer login --store` |
| **Hints** | `readOnlyHint` |

**Inputs:**

No inputs.

<Accordion title="Input JSON schema">
  ```json theme={null}
  {
    "type": "object",
    "properties": {}
  }
  ```
</Accordion>

**Output:** MCP text content holding JSON; errors set `isError`.

```json Example call theme={null}
{
  "name": "summer_board_project_links",
  "arguments": {}
}
```

***

### summer\_board\_read

On the hosted MCP.

Read the authoritative board graph, stable item and asset IDs, current field revisions and permissions. Re-read after conflicts.

| | |
| - | - |
| **Needs** | Your Summer account (OAuth). In the npm MCP: `summer login --store` |
| **Hints** | `readOnlyHint` |

**Inputs:**

| Input | Type | Required | Description |
| - | - | - | - |
| `boardId` | string | Yes | |

<Accordion title="Input JSON schema">
  ```json theme={null}
  {
    "type": "object",
    "properties": {
      "boardId": {
        "type": "string",
        "format": "uuid",
        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
      }
    },
    "required": [
      "boardId"
    ]
  }
  ```
</Accordion>

**Output:** MCP text content holding JSON; errors set `isError`.

```json Example call theme={null}
{
  "name": "summer_board_read",
  "arguments": {
    "boardId": "<boardId>"
  }
}
```

***

### summer\_board\_save\_direction

On the hosted MCP.

Save an explicitly selected game direction as an immutable Game Soul version. Include actual selected reference IDs. Requires the current board revision.

| | |
| - | - |
| **Needs** | Your Summer account (OAuth). In the npm MCP: `summer login --store` |
| **Hints** | `idempotentHint` |

**Inputs:**

| Input | Type | Required | Description |
| - | - | - | - |
| `boardId` | string | Yes | |
| `direction` | object | Yes | |
| `direction.requestId` | string | Yes | |
| `direction.revision` | integer | Yes | Range 0 to 9007199254740991. |
| `direction.title` | string | No | Length 1 to 200. |
| `direction.markdown` | string | Yes | Length 1 to 50000. |
| `direction.selectedItemIds` | string\[] | Yes | Items 0 to 100. |

<Accordion title="Input JSON schema">
  ```json theme={null}
  {
    "type": "object",
    "properties": {
      "boardId": {
        "type": "string",
        "format": "uuid",
        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
      },
      "direction": {
        "type": "object",
        "properties": {
          "requestId": {
            "type": "string",
            "format": "uuid",
            "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
          },
          "revision": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991
          },
          "title": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "markdown": {
            "type": "string",
            "minLength": 1,
            "maxLength": 50000
          },
          "selectedItemIds": {
            "maxItems": 100,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 64
            }
          }
        },
        "required": [
          "requestId",
          "revision",
          "markdown",
          "selectedItemIds"
        ],
        "additionalProperties": false
      }
    },
    "required": [
      "boardId",
      "direction"
    ]
  }
  ```
</Accordion>

**Output:** MCP text content holding JSON; errors set `isError`.

```json Example call theme={null}
{
  "name": "summer_board_save_direction",
  "arguments": {
    "boardId": "<boardId>",
    "direction": {
      "requestId": "<requestId>",
      "revision": 0,
      "markdown": "<markdown>",
      "selectedItemIds": [
        "<selectedItemId>"
      ]
    }
  }
}
```

***

### summer\_connect\_ports

On the local MCP (`summer-engine` npm).

Move and turn one piece so its port meets another piece's port, facing it: pipe to pipe, duct to duct, gutter section to funnel or outlet. A port is an open-loop id from [`summer_inspect_asset`](/mcp/tools/build#summer_inspect_asset) on that node's scene ("+Y" = the outermost open loop facing +Y in the piece's own axes, "+Y#2" the next one facing +Y; resolved on the live node's meshes in its own frame, so the id is the same in every pose), a Marker3D (or any Node3D) name under the node whose -Z axis points out of the port, or an open-loop index in the same stable order.

The subject turns by the shortest rotation that makes its port direction opposite the target's, then by rollDegrees about the joined axis, then moves so the ports coincide (gap along the target port's direction). rollDegrees: axis = roll\_axis in the receipt (the target port direction reversed, pointing into the target); right-hand rule, positive = counter-clockwise seen from inside the target looking back at the subject; zero = the shortest turn from the subject's CURRENT orientation, so the same value differs between start poses. Once the ports are joined, a second call turns by exactly rollDegrees (180 flips a bend's free end to the other side).

Tilt guard: a join that would tilt the subject's up axis (its local +Y) more than maxTiltDegrees (default 5) is refused before anything changes (failure\_reason tilt\_exceeds\_limit, with tilt\_degrees and ports\_within\_limit: the subject ports that would join within the limit, least tilt first). Turning about the up axis is never tilt. Pass allowTilt true for an intended tilt (a bend laid on its side).

One SetProp on transform, saved; a fresh read verifies \{distance, angle\_degrees, tilt\_degrees}. Returns \{subject\_port \{kind, id|name, index, position, direction, radius}, target\_port, roll\_axis, roll\_degrees, rotated\_degrees, tilt\_degrees, max\_tilt\_degrees, moved\_by, other\_ports, verify, warnings}. other\_ports: every other port of the subject (its other Marker3D anchors, or its other open loops for an open-loop port) with world position and outward direction AFTER the move, measured by the verify read: read where a bend's free end now points instead of measuring it. Open-loop ports are only as exact as the mesh: check direction\_ambiguous warnings and a screenshot.

| | |
| - | - |
| **Needs** | Summer Engine open with your project |
| **Effects** | writes files, changes the open project |
| **CLI** | `summer tool connect-ports --args '<json>'` |

**Use when:**

* joining a pipe, duct or gutter section end to end with the previous one
* fitting a bend, funnel or outlet onto a run
* snapping any two pieces together by named Marker3D anchors

**Do not use when:**

* mounting a piece on a wall — [`summer_attach_to_surface`](/mcp/tools/build#summer_attach_to_surface)
* putting bounds faces together without ports — [`summer_place_adjacent`](/mcp/tools/build#summer_place_adjacent)

**Inputs:**

| Input | Type | Required | Description |
| - | - | - | - |
| `scenePath` | string | Yes | Exact scene to read or change, e.g. 'res\://levels/street.tscn'. It must be open in the editor (any tab). Length 1 to 512. |
| `subject` | string | Yes | Piece to move: exact node path relative to the scene root, e.g. './Facade/Wall\_01'. Length 1 to 256. |
| `subjectPort` | string \| integer | Yes | Port on the subject: an open-loop id from summer\_inspect\_asset on that node's scene, e.g. '+Y' (the outermost open loop facing +Y in the piece's own axes) or '+Y#2' (the next one facing +Y); or a Marker3D (or any Node3D) name under the node, whose -Z axis points out of the port; or an open-loop index. Ids and indices follow the stable order (facing, then position), never the radius. |
| `target` | string | Yes | Piece that stays put: exact node path relative to the scene root, e.g. './Facade/Wall\_01'. Length 1 to 256. |
| `targetPort` | string \| integer | Yes | Port on the target: an open-loop id from summer\_inspect\_asset on that node's scene, e.g. '+Y' (the outermost open loop facing +Y in the piece's own axes) or '+Y#2' (the next one facing +Y); or a Marker3D (or any Node3D) name under the node, whose -Z axis points out of the port; or an open-loop index. Ids and indices follow the stable order (facing, then position), never the radius. |
| `gap` | number | No | Distance between the two ports along the target port's direction. 0 = touching. Default `0`. Range -1 to 10. |
| `rollDegrees` | number | No | Extra turn of the subject, in degrees, about the joined port axis, applied after the ports are lined up. Axis: the target port's direction reversed, i.e. pointing from the joint into the target (receipt roll\_axis). Sign: right-hand rule about that axis; positive turns counter-clockwise when you look back along the axis from inside the target toward the subject. Zero: the shortest turn that makes the subject's port face the target's from the subject's CURRENT orientation, so the same value gives different results from different start poses. Read other\_ports in the receipt; once the ports are joined, a second call turns by exactly rollDegrees about the joint (e.g. 180 flips a bend's free end to the other side). Default `0`. Range -360 to 360. |
| `maxTiltDegrees` | number | No | Refuse the join, changing nothing, when it would tilt the subject's up axis (its local +Y) more than this many degrees from where it points now (default 5). Turning about the up axis is never tilt. The refusal names the predicted tilt and the subject ports that would join within the limit. Default `5`. Range 0 to 180. |
| `allowTilt` | boolean | No | true: join even when the subject tilts more than maxTiltDegrees (a bend laid on its side, a sloped run). The receipt still reports tilt\_degrees. Default `false`. |
| `maxTriangles` | integer | No | Triangle budget (100-300000) per node when ports are open-loop ids or indices. Default `60000`. Range 100 to 300000. |

<Accordion title="Input JSON schema">
  ```json theme={null}
  {
    "type": "object",
    "properties": {
      "scenePath": {
        "type": "string",
        "minLength": 1,
        "maxLength": 512,
        "description": "Exact scene to read or change, e.g. 'res://levels/street.tscn'. It must be open in the editor (any tab)."
      },
      "subject": {
        "type": "string",
        "minLength": 1,
        "maxLength": 256,
        "description": "Piece to move: exact node path relative to the scene root, e.g. './Facade/Wall_01'."
      },
      "subjectPort": {
        "anyOf": [
          {
            "type": "string",
            "minLength": 1,
            "maxLength": 128
          },
          {
            "type": "integer",
            "minimum": 0,
            "maximum": 255
          }
        ],
        "description": "Port on the subject: an open-loop id from summer_inspect_asset on that node's scene, e.g. '+Y' (the outermost open loop facing +Y in the piece's own axes) or '+Y#2' (the next one facing +Y); or a Marker3D (or any Node3D) name under the node, whose -Z axis points out of the port; or an open-loop index. Ids and indices follow the stable order (facing, then position), never the radius."
      },
      "target": {
        "type": "string",
        "minLength": 1,
        "maxLength": 256,
        "description": "Piece that stays put: exact node path relative to the scene root, e.g. './Facade/Wall_01'."
      },
      "targetPort": {
        "anyOf": [
          {
            "type": "string",
            "minLength": 1,
            "maxLength": 128
          },
          {
            "type": "integer",
            "minimum": 0,
            "maximum": 255
          }
        ],
        "description": "Port on the target: an open-loop id from summer_inspect_asset on that node's scene, e.g. '+Y' (the outermost open loop facing +Y in the piece's own axes) or '+Y#2' (the next one facing +Y); or a Marker3D (or any Node3D) name under the node, whose -Z axis points out of the port; or an open-loop index. Ids and indices follow the stable order (facing, then position), never the radius."
      },
      "gap": {
        "type": "number",
        "minimum": -1,
        "maximum": 10,
        "default": 0,
        "description": "Distance between the two ports along the target port's direction. 0 = touching."
      },
      "rollDegrees": {
        "type": "number",
        "minimum": -360,
        "maximum": 360,
        "default": 0,
        "description": "Extra turn of the subject, in degrees, about the joined port axis, applied after the ports are lined up. Axis: the target port's direction reversed, i.e. pointing from the joint into the target (receipt roll_axis). Sign: right-hand rule about that axis; positive turns counter-clockwise when you look back along the axis from inside the target toward the subject. Zero: the shortest turn that makes the subject's port face the target's from the subject's CURRENT orientation, so the same value gives different results from different start poses. Read other_ports in the receipt; once the ports are joined, a second call turns by exactly rollDegrees about the joint (e.g. 180 flips a bend's free end to the other side)."
      },
      "maxTiltDegrees": {
        "type": "number",
        "minimum": 0,
        "maximum": 180,
        "default": 5,
        "description": "Refuse the join, changing nothing, when it would tilt the subject's up axis (its local +Y) more than this many degrees from where it points now (default 5). Turning about the up axis is never tilt. The refusal names the predicted tilt and the subject ports that would join within the limit."
      },
      "allowTilt": {
        "type": "boolean",
        "default": false,
        "description": "true: join even when the subject tilts more than maxTiltDegrees (a bend laid on its side, a sloped run). The receipt still reports tilt_degrees."
      },
      "maxTriangles": {
        "type": "integer",
        "minimum": 100,
        "maximum": 300000,
        "default": 60000,
        "description": "Triangle budget (100-300000) per node when ports are open-loop ids or indices."
      }
    },
    "required": [
      "scenePath",
      "subject",
      "subjectPort",
      "target",
      "targetPort"
    ],
    "additionalProperties": false
  }
  ```
</Accordion>

**Output:** MCP text content holding JSON; errors set `isError`. From the tool's own description: Returns \{subject\_port \{kind, id|name, index, position, direction, radius}, target\_port, roll\_axis, roll\_degrees, rotated\_degrees, tilt\_degrees, max\_tilt\_degrees, moved\_by, other\_ports, verify, warnings}.

```json Example call theme={null}
{
  "name": "summer_connect_ports",
  "arguments": {
    "scenePath": "res://levels/street.tscn",
    "subject": "./Facade/Wall_01",
    "subjectPort": "<subjectPort>",
    "target": "./Facade/Wall_01",
    "targetPort": "<targetPort>"
  }
}
```

***

### summer\_connect\_signal

On the local MCP (`summer-engine` npm).

Connect a signal between two nodes so the connection is SAVED in the scene. Signals are Godot's event system — they notify when something happens.

Common signals:

* "body\_entered" / "body\_exited" — Area3D/Area2D detects physics bodies
* "pressed" — Button clicked
* "timeout" — Timer finished
* "area\_entered" — Area detects another area
* "input\_event" — CollisionObject received input

The receiver should have the method (a script method, or a built-in such as queue\_free); a missing one is saved anyway and reported in warnings. scenePath must be a .tscn.

PERSISTENCE IS VERIFIED: the engine's ConnectSignal op connects without CONNECT\_PERSIST, so its connection never reached the file. This tool connects through a RunSceneScript probe with CONNECT\_PERSIST (replacing a non-persistent connection of the same pair), saves, reads the saved .tscn back and returns persisted:true / verified:true only when the \[connection] line is there; otherwise an error with failure\_reason not\_persisted. The probe runs in the active tab: a scene in a background tab is brought forward and the user's tab restored (tab\_switched). One Ctrl+Z reverts it.

| | |
| - | - |
| **Needs** | Summer Engine open with your project |
| **Effects** | writes files, changes the open project |
| **CLI** | `summer tool connect-signal --args '<json>'` |

**Use when:**

* wiring events like body\_entered, pressed, or timeout
* "when the button is pressed, call my function"
* running code when the player enters an Area3D or a Timer finishes

**Do not use when:**

* the receiver script does not define the target method yet — write it first with [`summer_write_file`](/mcp/tools/build#summer_write_file) / [`summer_replace_text`](/mcp/tools/build#summer_replace_text)
* the scene is a binary .scn — connect from [`summer_run_script`](/mcp/tools/build#summer_run_script) with CONNECT\_PERSIST, then [`summer_save_scene`](/mcp/tools/build#summer_save_scene)

**Inputs:**

| Input | Type | Required | Description |
| - | - | - | - |
| `scenePath` | string | Yes | Target scene path, e.g. 'res\://main.tscn' |
| `emitter` | string | Yes | Node that fires the signal, e.g. './Player/HitArea' |
| `signal` | string | Yes | Signal name, e.g. 'body\_entered' |
| `receiver` | string | Yes | Node with the handler script, e.g. './Player' |
| `method` | string | Yes | Method name in the receiver's script, e.g. '\_on\_hit\_area\_body\_entered' |

<Accordion title="Input JSON schema">
  ```json theme={null}
  {
    "type": "object",
    "properties": {
      "scenePath": {
        "type": "string",
        "description": "Target scene path, e.g. 'res://main.tscn'"
      },
      "emitter": {
        "type": "string",
        "description": "Node that fires the signal, e.g. './Player/HitArea'"
      },
      "signal": {
        "type": "string",
        "description": "Signal name, e.g. 'body_entered'"
      },
      "receiver": {
        "type": "string",
        "description": "Node with the handler script, e.g. './Player'"
      },
      "method": {
        "type": "string",
        "description": "Method name in the receiver's script, e.g. '_on_hit_area_body_entered'"
      }
    },
    "required": [
      "scenePath",
      "emitter",
      "signal",
      "receiver",
      "method"
    ],
    "additionalProperties": false
  }
  ```
</Accordion>

**Output:** MCP text content holding JSON; errors set `isError`.

```json Example call theme={null}
{
  "name": "summer_connect_signal",
  "arguments": {
    "scenePath": "res://main.tscn",
    "emitter": "./Player/HitArea",
    "signal": "body_entered",
    "receiver": "./Player",
    "method": "_on_hit_area_body_entered"
  }
}
```

***

### summer\_create\_scene

On the local MCP (`summer-engine` npm).

Create a new empty scene file. Writes a minimal .tscn through the identity-bound engine with a create-only guard: it fails if the path already exists, and it never touches the currently open scene.

The new scene is on disk but NOT opened. Call [`summer_open_scene`](/mcp/tools/build#summer_open_scene) to start editing it, then [`summer_add_node`](/mcp/tools/build#summer_add_node) to build it out.

Recommended workflow:

1. Call [`summer_get_project_context`](/mcp/tools/build#summer_get_project_context)
2. Call [`summer_create_scene`](/mcp/tools/build#summer_create_scene) with a new res\:// path
3. Call [`summer_open_scene`](/mcp/tools/build#summer_open_scene) with that path

| | |
| - | - |
| **Needs** | Summer Engine open with your project |
| **Effects** | writes files |
| **CLI** | `summer tool create-scene --args '<json>'` |

**Use when:**

* starting a new level, prefab, or UI scene file
* "make a new empty scene file for the enemy prefab"
* starting Level2.tscn from scratch as its own file

**Do not use when:**

* adding nodes into the currently open scene — [`summer_add_node`](/mcp/tools/build#summer_add_node)
* the file already exists — the create-only guard refuses; [`summer_open_scene`](/mcp/tools/build#summer_open_scene) it instead

**Inputs:**

| Input | Type | Required | Description |
| - | - | - | - |
| `path` | string | Yes | New scene path, e.g. 'res\://scenes/empty\_level.tscn' |
| `rootName` | string | No | Root node name for the new scene Default `"Main"`. |
| `rootType` | string | No | Root node type. Default 'Node3D' (3D scenes); common alternatives: 'Node2D' (2D scenes), 'Control' (UI scenes), 'Node' (logic-only). Default `"Node3D"`. |
| `allow_temporary_scene_mutation` | boolean | No | DEPRECATED, ignored. Scene creation no longer mutates any open scene; kept only so older callers don't break. |

<Accordion title="Input JSON schema">
  ```json theme={null}
  {
    "type": "object",
    "properties": {
      "path": {
        "type": "string",
        "description": "New scene path, e.g. 'res://scenes/empty_level.tscn'"
      },
      "rootName": {
        "type": "string",
        "default": "Main",
        "description": "Root node name for the new scene"
      },
      "rootType": {
        "type": "string",
        "default": "Node3D",
        "description": "Root node type. Default 'Node3D' (3D scenes); common alternatives: 'Node2D' (2D scenes), 'Control' (UI scenes), 'Node' (logic-only)."
      },
      "allow_temporary_scene_mutation": {
        "type": "boolean",
        "description": "DEPRECATED, ignored. Scene creation no longer mutates any open scene; kept only so older callers don't break."
      }
    },
    "required": [
      "path"
    ],
    "additionalProperties": false
  }
  ```
</Accordion>

**Output:** MCP text content holding JSON; errors set `isError`.

```json Example call theme={null}
{
  "name": "summer_create_scene",
  "arguments": {
    "path": "res://scenes/empty_level.tscn"
  }
}
```

***

### summer\_get\_agent\_playbook

On the local MCP (`summer-engine` npm).

AI-first operating guide for Summer Engine MCP.

Call this at the start of a fresh chat before touching scenes.
It returns the observe-first loop, content routing (reuse -> import ->
generate -> script), physical invariants, cost rules, the verification
ladder, honesty rules, anti-patterns, and recovery steps.

| | |
| - | - |
| **Needs** | No open editor and no sign-in |
| **Effects** | read-only |
| **CLI** | `summer tool get-agent-playbook --args '<json>'` |

**Use when:**

* at the start of a fresh session, before touching scenes
* a new chat is about to touch a project it has never seen
* the agent is unsure of Summer's safety rules or verification ladder

**Do not use when:**

* mid-task lookups of a specific tool's arguments — read that tool's description instead

**Inputs:**

No inputs.

<Accordion title="Input JSON schema">
  ```json theme={null}
  {
    "type": "object",
    "properties": {}
  }
  ```
</Accordion>

**Output:** MCP text content holding JSON; errors set `isError`.

```json Example call theme={null}
{
  "name": "summer_get_agent_playbook",
  "arguments": {}
}
```

***

### summer\_get\_project\_context

On the local MCP (`summer-engine` npm).

Get essential project context before editing. The default payload is COMPACT (a few KB):

* project name and project path, current scene path, main scene path
* sceneSummary: the open scene's root node and node count (not its tree)
* health: the engine's scalar status fields plus capability COUNTS
* projectMemory: the .summer summary — GameSoul/build-plan/memory files and
  `pin` (.summer/project.json: which template at which commit started this
  project, toolkit version, created\_at)
* warnings: capabilitySkewWarning (only when the engine build and this CLI
  have drifted apart — non-fatal; explains upcoming 'unknown op' failures),
  rebindError, summerUpdateNotice
* omitted: how to ask for each heavy block that was left out

Use this first in every fresh chat to avoid guessing scene filenames or editing the wrong scene. It also binds the session to the open project.

Heavy blocks are opt-in with include: 'scene\_tree' (the open scene's tree, up
to 200 nodes; for one subtree prefer [`summer_world_snapshot`](/mcp/tools/run-and-test#summer_world_snapshot) path\_prefix),
'capabilities' (the engine's full op lists), 'settings' (project settings in
project.data.entries, trimmed to the curated default groups: application/,
display/window/, the project's input/ actions, default gravity,
rendering/renderer/, the 2D default texture filter; the trim is declared in
settingsTruncated / totalSettings / settingsPrefixesIncluded /
settingsPrefixesExcluded). settingsPrefixes (e.g. \["audio/", "layer\_names/"])
or settingsPrefix read other settings groups and imply 'settings'.

| | |
| - | - |
| **Needs** | Summer Engine open with your project |
| **Effects** | read-only |
| **CLI** | `summer tool get-project-context --args '<json>'` |

**Use when:**

* first call in every fresh session, to avoid guessing scene filenames
* deliberately rebinding after the engine switched projects
* reading the open scene's tree, the engine's op list or project settings (include)

**Inputs:**

| Input | Type | Required | Description |
| - | - | - | - |
| `include` | "scene\_tree" \| "capabilities" \| "settings"\[] | No | Heavy blocks to add to the compact default: 'scene\_tree' (the open scene's node tree, up to 200 nodes), 'capabilities' (the engine's full op/capability lists), 'settings' (project settings, curated groups). settingsPrefix/settingsPrefixes imply 'settings'. Items 0 to 3. |
| `settingsPrefix` | string | No | Only return project settings whose key starts with this prefix, e.g. 'audio/' or 'application/config/'. Omit for the curated default set. |
| `settingsPrefixes` | string\[] | No | Several settings groups at once, e.g. \['audio/', 'layer\_names/2d\_physics/', 'input/ui\_']. Merged with settingsPrefix. Omit for the curated default set. Items 0 to 32. |

<Accordion title="Input JSON schema">
  ```json theme={null}
  {
    "type": "object",
    "properties": {
      "include": {
        "type": "array",
        "items": {
          "type": "string",
          "enum": [
            "scene_tree",
            "capabilities",
            "settings"
          ]
        },
        "maxItems": 3,
        "description": "Heavy blocks to add to the compact default: 'scene_tree' (the open scene's node tree, up to 200 nodes), 'capabilities' (the engine's full op/capability lists), 'settings' (project settings, curated groups). settingsPrefix/settingsPrefixes imply 'settings'."
      },
      "settingsPrefix": {
        "type": "string",
        "description": "Only return project settings whose key starts with this prefix, e.g. 'audio/' or 'application/config/'. Omit for the curated default set."
      },
      "settingsPrefixes": {
        "type": "array",
        "items": {
          "type": "string"
        },
        "maxItems": 32,
        "description": "Several settings groups at once, e.g. ['audio/', 'layer_names/2d_physics/', 'input/ui_']. Merged with settingsPrefix. Omit for the curated default set."
      }
    },
    "additionalProperties": false
  }
  ```
</Accordion>

**Output:** MCP text content holding JSON; errors set `isError`.

```json Example call theme={null}
{
  "name": "summer_get_project_context",
  "arguments": {}
}
```

***

### summer\_get\_scene\_tree

On the local MCP (`summer-engine` npm).

Get a scene tree. Pass scenePath to read that exact in-memory/open scene;
omit it only when you intentionally want the currently visible editor scene.
Scene mutations load their explicit target, so a follow-up targeted read does
not require OpenScene.

The engine defaults to depth 2 and limit 200 nodes and SILENTLY truncates
deeper hierarchies (the response then carries truncated: true and a visited
count lower than the real node count). Pass an explicit depth (e.g. 10) to
read a full tree — a 102-node scene returns only 61 nodes at the defaults.

| | |
| - | - |
| **Needs** | Summer Engine open with your project |
| **Effects** | read-only |
| **CLI** | `summer tool get-scene-tree --args '<json>'` |

**Use when:**

* inspecting scene structure before or after mutations
* "what nodes are in this scene?" / "how is the level structured?"
* finding the path of the player node before editing it

**Do not use when:**

* the RUNNING game's tree — [`summer_get_runtime_tree`](/mcp/tools/run-and-test#summer_get_runtime_tree)
* transforms and bounds, not just names — [`summer_world_snapshot`](/mcp/tools/run-and-test#summer_world_snapshot)

**Inputs:**

| Input | Type | Required | Description |
| - | - | - | - |
| `scenePath` | string | No | Exact res\:// scene path to inspect |
| `depth` | integer | No | Maximum tree depth to walk. Engine default is 2 — pass a larger value for deep hierarchies. |
| `limit` | integer | No | Maximum number of nodes to return. Engine default is 200. |

<Accordion title="Input JSON schema">
  ```json theme={null}
  {
    "type": "object",
    "properties": {
      "scenePath": {
        "type": "string",
        "description": "Exact res:// scene path to inspect"
      },
      "depth": {
        "type": "integer",
        "exclusiveMinimum": 0,
        "description": "Maximum tree depth to walk. Engine default is 2 — pass a larger value for deep hierarchies."
      },
      "limit": {
        "type": "integer",
        "exclusiveMinimum": 0,
        "description": "Maximum number of nodes to return. Engine default is 200."
      }
    },
    "additionalProperties": false
  }
  ```
</Accordion>

**Output:** MCP text content holding JSON; errors set `isError`.

```json Example call theme={null}
{
  "name": "summer_get_scene_tree",
  "arguments": {}
}
```

***

### summer\_grep

On the local MCP (`summer-engine` npm).

Search project files with a regular expression (ripgrep, through the engine) and get file + line + text per match, optionally with context lines around each.

Use it to find things in big files without reading them whole: every '"fits\_into"' in a kit manifest, the scenes of a kit (glob '\*.tscn'), where a signal handler is defined. Then read exactly the part you need with [`summer_read_file`](/mcp/tools/build#summer_read_file) (offset/limit, or json\_path for JSON).

* path: a res\:// directory or file (default: the whole project; .godot/ and .import/ are never searched).
* glob: ripgrep --glob filter ('\*.gd', '\*\*/\*.json', '!addons/\*\*'). Ripgrep skips files ignored by .gitignore unless a glob names them.
* context\_lines (0-10): lines before/after each match, as before\[] / after\[].
* max\_results (default 50, max 500) caps the matches; truncated:true says there were more. Lines are clipped to max\_line\_chars.
  Case-insensitive unless case\_sensitive:true. Read-only.

| | |
| - | - |
| **Needs** | Summer Engine open with your project |
| **Effects** | read-only |
| **CLI** | `summer tool grep --args '<json>'` |

**Use when:**

* finding where something is in big project files without reading them whole
* "which entries of a big JSON file list fits\_into?" / "every mount\_side entry"
* "where is \_on\_door\_body\_entered defined?" / "which scenes use this material?"

**Do not use when:**

* you already know the file and want its content — [`summer_read_file`](/mcp/tools/build#summer_read_file) (offset/limit, json\_path)
* searching the Summer library — [`summer_search_library`](/mcp/tools/build#summer_search_library)

**Inputs:**

| Input | Type | Required | Description |
| - | - | - | - |
| `pattern` | string | Yes | Ripgrep regular expression, e.g. '"fits\_into"' or 'func \_on\_.\*\_pressed' Length 1 to …. |
| `path` | string | No | Search scope: a res\:// directory or file, e.g. 'res\://kit/' or 'res\://kit/kit\_manifest.json'. Default: the whole project. |
| `glob` | string | No | File filter passed to ripgrep --glob, e.g. '\*.gd', '\*\*/\*.json', '!addons/\*\*'. A glob also reaches files .gitignore would skip. |
| `case_sensitive` | boolean | No | Match case exactly (default false: case-insensitive). |
| `context_lines` | integer | No | Lines of context before and after each match (0-10, default 0). Range 0 to 10. |
| `max_results` | integer | No | Most matches to return (default 50, max 500). truncated:true means there were more. Range … to 500. |
| `max_line_chars` | integer | No | Clip every returned line to this many characters (default 240). Range 40 to 2000. |
| `multiline` | boolean | No | Let the pattern span lines (ripgrep -U --multiline-dotall). |

<Accordion title="Input JSON schema">
  ```json theme={null}
  {
    "type": "object",
    "properties": {
      "pattern": {
        "type": "string",
        "minLength": 1,
        "description": "Ripgrep regular expression, e.g. '\"fits_into\"' or 'func _on_.*_pressed'"
      },
      "path": {
        "type": "string",
        "description": "Search scope: a res:// directory or file, e.g. 'res://kit/' or 'res://kit/kit_manifest.json'. Default: the whole project."
      },
      "glob": {
        "type": "string",
        "description": "File filter passed to ripgrep --glob, e.g. '*.gd', '**/*.json', '!addons/**'. A glob also reaches files .gitignore would skip."
      },
      "case_sensitive": {
        "type": "boolean",
        "description": "Match case exactly (default false: case-insensitive)."
      },
      "context_lines": {
        "type": "integer",
        "minimum": 0,
        "maximum": 10,
        "description": "Lines of context before and after each match (0-10, default 0)."
      },
      "max_results": {
        "type": "integer",
        "exclusiveMinimum": 0,
        "maximum": 500,
        "description": "Most matches to return (default 50, max 500). truncated:true means there were more."
      },
      "max_line_chars": {
        "type": "integer",
        "minimum": 40,
        "maximum": 2000,
        "description": "Clip every returned line to this many characters (default 240)."
      },
      "multiline": {
        "type": "boolean",
        "description": "Let the pattern span lines (ripgrep -U --multiline-dotall)."
      }
    },
    "required": [
      "pattern"
    ],
    "additionalProperties": false
  }
  ```
</Accordion>

**Output:** MCP text content holding JSON; errors set `isError`.

```json Example call theme={null}
{
  "name": "summer_grep",
  "arguments": {
    "pattern": "<pattern>"
  }
}
```

***

### summer\_input\_map\_bind

On the local MCP (`summer-engine` npm).

Set up input controls. Creates the action if it doesn't exist, then binds events to it.

Event format:

* Keyboard: \{ type: "key", key: "W" } or \{ type: "key", key: "Space" }
* Mouse button: \{ type: "mouse\_button", button: 1 } (1=left, 2=right, 3=middle)
* Common keys: "W", "A", "S", "D", "Space", "Shift", "E", "Escape", "Up", "Down", "Left", "Right"

Example: Bind jump to Space and W:
name: "jump", events: \[\{ type: "key", key: "Space" }, \{ type: "key", key: "W" }]

| | |
| - | - |
| **Needs** | Summer Engine open with your project |
| **Effects** | writes files, changes the open project |
| **CLI** | `summer tool input-map-bind --args '<json>'` |

**Use when:**

* setting up player controls like jump, move, or interact
* "make E interact" / "bind shoot to left mouse"
* adding a gamepad button for an existing action

**Do not use when:**

* reading which keys are already bound — [`summer_get_project_context`](/mcp/tools/build#summer_get_project_context) / project.godot

**Inputs:**

| Input | Type | Required | Description |
| - | - | - | - |
| `name` | string | Yes | Action name, e.g. 'jump', 'move\_forward', 'interact' |
| `events` | object\[] | Yes | Array of input event objects |

<Accordion title="Input JSON schema">
  ```json theme={null}
  {
    "type": "object",
    "properties": {
      "name": {
        "type": "string",
        "description": "Action name, e.g. 'jump', 'move_forward', 'interact'"
      },
      "events": {
        "type": "array",
        "items": {
          "type": "object",
          "additionalProperties": {}
        },
        "description": "Array of input event objects"
      }
    },
    "required": [
      "name",
      "events"
    ],
    "additionalProperties": false
  }
  ```
</Accordion>

**Output:** MCP text content holding JSON; errors set `isError`.

```json Example call theme={null}
{
  "name": "summer_input_map_bind",
  "arguments": {
    "name": "jump",
    "events": [
      {}
    ]
  }
}
```

***

### summer\_inspect\_asset

On the local MCP (`summer-engine` npm).

Measure a 3D asset file (.tscn/.scn/.glb/.gltf, or a Mesh resource) WITHOUT adding it to any scene: it is loaded and instanced off-scene in the editor, measured, and freed. Call it once per kit piece before placing it, instead of guessing size, origin or facing.

Returns (all in the asset root's own frame, the frame position/rotation apply in), the facing evidence first:

* summary \{aabb, origin \{fraction, label e.g. "x:center y:min z:min"}, plane\_pairs, port\_like\_loops \[loop ids], triangles, mesh\_count, anchor\_count, collision\_count, warnings?}. plane\_pairs: the 2 largest pairs of opposite planes (a pair under 1% of the largest one's area is left out), each \{larger, opposite (null for a single sheet), separation}; every plane \{axis (e.g. "+z", only when the normal is within about 1 degree of it), normal, offset, area, one\_sided}. one\_sided true = its material culls back faces, so the plane is invisible from behind its normal: a single sheet that is one\_sided faces along its normal and its back is the opposite axis. An oblique normal (no axis) means a baked yaw or a 45-degree corner face. warnings says when the triangle budget cut the analysis and which maxTriangles covers the whole mesh
* aabb, origin, meshes \[\{path, tris, min, max}], triangles total
* planes: the 6 largest planar face groups \{normal, offset, area, tris, cull\_back, one\_sided}; normals follow the triangle winding (outward faces). You decide the front; the tool does not label facing
* open\_loops: open boundary loops \{id, index, mesh, center, direction (outward), radius, vertices, max\_dev} in a stable order: grouped by the piece axis the direction is nearest (+X, -X, +Y, -Y, +Z, -Z; \~X/\~Y/\~Z when undecided), the outermost along that axis first, then by centre; never by radius. id names the loop by that order: "+Y" is the outermost loop facing +Y, "+Y#2" the next. [`summer_connect_ports`](/mcp/tools/build#summer_connect_ports) accepts the id (or the index); the same id names the same loop on the placed node in any pose. detail "summary" (default) lists only port-like loops (radius over 2 cm with a partner loop facing more than 60 degrees away: the ends of a pipe, duct or bend; or the one opening of an end piece, such as an outlet's socket, on its bounding-box face) and says how many it omitted; detail "full" lists every loop, including the outline of flat sheets
* anchors: Marker3D nodes \{name, path, position, forward (-Z), up}
* collision: CollisionShape3D nodes \{path, shape, size/radius/height/faces, center, min, max}
* analysis \{triangles\_analyzed, triangle\_budget, truncated}; a "truncated" object when a list was cut to fit 5 KB

maxTriangles 100-300000 (default 60000). Evidence is mesh\_triangles. Uses the existing RunSceneScript op (in the live editor, read-only); an engine without it answers engine\_lacks\_op.

| | |
| - | - |
| **Needs** | Summer Engine open with your project |
| **Effects** | read-only |
| **CLI** | `summer tool inspect-asset --args '<json>'` |

**Use when:**

* learning a kit piece's real size, origin and which way it faces before placing it
* finding a piece's front and back planes (largest planar faces with their normals) or its pipe and duct ends (open boundary loops)
* reading the Marker3D anchors or collision shapes a kit piece ships with

**Do not use when:**

* the piece is already in the scene and you need what surrounds it — [`summer_starcast`](/mcp/tools/build#summer_starcast)
* you need the measurement between two placed nodes — [`summer_measure`](/mcp/tools/build#summer_measure)

**Inputs:**

| Input | Type | Required | Description |
| - | - | - | - |
| `path` | string | Yes | Asset to measure, e.g. 'res\://kit/facade/wall\_single\_01.tscn'. It is loaded and instanced off-scene, never added to an open scene. Length 1 to 512. |
| `maxTriangles` | integer | No | Triangle budget (100-300000) for the face and open-loop analysis (AABBs and counts are always complete). summary.warnings says when the budget cut the analysis and which budget covers the whole mesh. Default `60000`. Range 100 to 300000. |
| `detail` | "summary" \| "full" | No | summary (default): open\_loops lists only port-like loops (radius over 2 cm with a partner loop facing another way, or the one opening of an end piece on its bounding-box face), or none. full: every open loop, including the outline of flat sheets. Every loop has a stable id ('+Y', '+Y#2') that summer\_connect\_ports accepts. Default `"summary"`. |

<Accordion title="Input JSON schema">
  ```json theme={null}
  {
    "type": "object",
    "properties": {
      "path": {
        "type": "string",
        "minLength": 1,
        "maxLength": 512,
        "description": "Asset to measure, e.g. 'res://kit/facade/wall_single_01.tscn'. It is loaded and instanced off-scene, never added to an open scene."
      },
      "maxTriangles": {
        "type": "integer",
        "minimum": 100,
        "maximum": 300000,
        "default": 60000,
        "description": "Triangle budget (100-300000) for the face and open-loop analysis (AABBs and counts are always complete). summary.warnings says when the budget cut the analysis and which budget covers the whole mesh."
      },
      "detail": {
        "type": "string",
        "enum": [
          "summary",
          "full"
        ],
        "default": "summary",
        "description": "summary (default): open_loops lists only port-like loops (radius over 2 cm with a partner loop facing another way, or the one opening of an end piece on its bounding-box face), or none. full: every open loop, including the outline of flat sheets. Every loop has a stable id ('+Y', '+Y#2') that summer_connect_ports accepts."
      }
    },
    "required": [
      "path"
    ],
    "additionalProperties": false
  }
  ```
</Accordion>

**Output:** MCP text content holding JSON; errors set `isError`. From the tool's own description: Returns (all in the asset root's own frame, the frame position/rotation apply in), the facing evidence first: - summary \{aabb, origin \{fraction, label e.g.

```json Example call theme={null}
{
  "name": "summer_inspect_asset",
  "arguments": {
    "path": "res://kit/facade/wall_single_01.tscn"
  }
}
```

***

### summer\_inspect\_node

On the local MCP (`summer-engine` npm).

Get all editable properties of a node with their current values, types, and resource info.

Call this before modifying a node to understand its current state. Returns every property the Godot inspector would show. Each prop carries the engine's raw Variant.Type integer as "type" plus its name as "type\_name" (e.g. type 5 = TYPE\_VECTOR2, 20 = TYPE\_COLOR, 24 = TYPE\_OBJECT); resource-valued props also carry resource\_type / resource\_path.

Reads the currently OPEN scene — "path" is relative to its root (there is no scenePath argument; open the scene first if needed).

Example: inspect a light to see its energy, color, shadow settings before changing them.

The full read is about 5 KB. To read only what you need, pass fields: property names or globs ('position', 'surface\_material\_override/\*'), plus derived fields: transform (local position / rotation\_degrees / scale, and a Transform3D literal for 3D nodes), global\_transform (world origin + Transform3D, composed from the world snapshot), scene\_file\_path (the scene this node instances), aabb (world bounds), warnings. Example: fields:\['transform','global\_transform','scene\_file\_path'] is a few hundred bytes. missing\_fields and unavailable say what could not be read.

| | |
| - | - |
| **Needs** | Summer Engine open with your project |
| **Effects** | read-only |
| **CLI** | `summer tool inspect-node --args '<json>'` |

**Use when:**

* before modifying a node, to understand its current state
* "what is the player's speed / position / collision layer?"
* "which material and mesh does this MeshInstance3D use?"
* "where is this piece, locally and in the world, and which scene is it?" — fields:\[transform, global\_transform, scene\_file\_path]

**Do not use when:**

* sub-properties of the material, mesh, or shape itself — [`summer_inspect_resource`](/mcp/tools/build#summer_inspect_resource)
* live values while the game runs — [`summer_inspect_runtime_node`](/mcp/tools/run-and-test#summer_inspect_runtime_node)

**Inputs:**

| Input | Type | Required | Description |
| - | - | - | - |
| `path` | string | Yes | Node path from scene tree, e.g. 'Player', 'World/Enemies/Boss', 'DirectionalLight3D' |
| `fields` | string\[] | No | Only these fields: property names or globs (e.g. 'position', 'surface\_material\_override/\*') and the derived fields transform, global\_transform, scene\_file\_path, aabb, warnings. Omit for every property. Items 0 to 48. |

<Accordion title="Input JSON schema">
  ```json theme={null}
  {
    "type": "object",
    "properties": {
      "path": {
        "type": "string",
        "description": "Node path from scene tree, e.g. 'Player', 'World/Enemies/Boss', 'DirectionalLight3D'"
      },
      "fields": {
        "type": "array",
        "items": {
          "type": "string"
        },
        "maxItems": 48,
        "description": "Only these fields: property names or globs (e.g. 'position', 'surface_material_override/*') and the derived fields transform, global_transform, scene_file_path, aabb, warnings. Omit for every property."
      }
    },
    "required": [
      "path"
    ],
    "additionalProperties": false
  }
  ```
</Accordion>

**Output:** MCP text content holding JSON; errors set `isError`. From the tool's own description: Returns every property the Godot inspector would show.

```json Example call theme={null}
{
  "name": "summer_inspect_node",
  "arguments": {
    "path": "Player"
  }
}
```

***

### summer\_inspect\_resource

On the local MCP (`summer-engine` npm).

Read a resource: a material, mesh, shape, texture, environment, or a scene/model file.

Two forms, pass exactly one:

* path: a resource FILE ('res\://materials/ground.tres', a mesh 'res\://kit/meshes/wall\_01.res', 'res\://models/player.glb'), loaded read-only in the editor. A Mesh returns its AABB, surface\_count and per surface the primitive, vertex and index counts, attributes, triangles and material (class, path or embedded, albedo for standard materials), plus the unique materials and blend shapes. A scene or model (.tscn/.glb/.gltf) returns its node count, the first 40 nodes with type, instanced scene and mesh, and its meshes; [`summer_inspect_asset`](/mcp/tools/build#summer_inspect_asset) measures it (AABB, planes, ports). Every other resource (and a mesh) returns its editor properties that differ from the class default (props), with props\_at\_default counting the rest.
* nodePath + property: a resource a node of the ACTIVE scene tab holds, e.g. nodePath 'Floor', property 'mesh'. For example, [`summer_inspect_node`](/mcp/tools/build#summer_inspect_node) tells you a MeshInstance3D has a "StandardMaterial3D" material\_override — this form returns its albedo\_color, metallic, roughness, etc.

| | |
| - | - |
| **Needs** | Summer Engine open with your project |
| **Effects** | read-only |
| **CLI** | `summer tool inspect-resource --args '<json>'` |

**Use when:**

* reading sub-properties that the node inspector only names
* "how many surfaces, triangles and which materials does this mesh .res have?"
* "what colour is this material?" / "how big is this collision shape?"
* "what settings does the WorldEnvironment resource have?"

**Do not use when:**

* top-level node properties — [`summer_inspect_node`](/mcp/tools/build#summer_inspect_node)

**Inputs:**

| Input | Type | Required | Description |
| - | - | - | - |
| `path` | string | No | A resource FILE: 'res\://materials/ground.tres', a mesh 'res\://kit/meshes/wall\_01.res', a texture, a shape, or a scene/model 'res\://models/player.glb'. Loaded read-only in the editor. Length 1 to 512. |
| `nodePath` | string | No | With property: a node of the ACTIVE scene tab whose resource to read, e.g. 'Floor'. Do not combine with path. Length 1 to 256. |
| `property` | string | No | With nodePath: the node property holding the resource, e.g. 'mesh', 'material\_override', 'shape', 'environment'. Length 1 to 128. |

<Accordion title="Input JSON schema">
  ```json theme={null}
  {
    "type": "object",
    "properties": {
      "path": {
        "type": "string",
        "minLength": 1,
        "maxLength": 512,
        "description": "A resource FILE: 'res://materials/ground.tres', a mesh 'res://kit/meshes/wall_01.res', a texture, a shape, or a scene/model 'res://models/player.glb'. Loaded read-only in the editor."
      },
      "nodePath": {
        "type": "string",
        "minLength": 1,
        "maxLength": 256,
        "description": "With property: a node of the ACTIVE scene tab whose resource to read, e.g. 'Floor'. Do not combine with path."
      },
      "property": {
        "type": "string",
        "minLength": 1,
        "maxLength": 128,
        "description": "With nodePath: the node property holding the resource, e.g. 'mesh', 'material_override', 'shape', 'environment'."
      }
    },
    "additionalProperties": false
  }
  ```
</Accordion>

**Output:** MCP text content holding JSON; errors set `isError`.

```json Example call theme={null}
{
  "name": "summer_inspect_resource",
  "arguments": {}
}
```

***

### summer\_instantiate\_scene

On the local MCP (`summer-engine` npm).

Add an existing scene or 3D model as a child node. Use this to:

* Add a .tscn prefab (reusable scene) as a child
* Add a .glb/.gltf 3D model into the scene
* Compose scenes from smaller scenes (e.g., add a "Player" scene into a "Level" scene)

The scene must already exist in the project. Use [`summer_import_from_url`](/mcp/tools/create-assets#summer_import_from_url) first if importing from external sources.

PASS target\_size FOR IMPORTED MODELS. Downloaded/generated .glb assets arrive at arbitrary scale (a "chair" can be 40 units tall). target\_size uniformly scales the instanced subtree so its largest world-AABB dimension equals that many units — commit to real-world size: chair 1.0, door 2.0, car 4.5, person 1.7, tree 6-10. The result then reports dimensions + scale\_applied; verify placement afterwards ([`summer_world_snapshot`](/mcp/tools/run-and-test#summer_world_snapshot) AABBs, [`summer_screenshot`](/mcp/tools/run-and-test#summer_screenshot)). Older engine builds ignore target\_size — when the result lacks scale\_applied, this tool appends a note and you must scale the node yourself ([`summer_set_prop`](/mcp/tools/build#summer_set_prop) scale) and re-check.

PLACE IT IN THE SAME CALL: position, rotation\_degrees and scale (\[x, y, z], parent-local, like [`summer_set_prop`](/mcp/tools/build#summer_set_prop)), or transform (a "Transform3D(...)" string). The instance is created, then those properties are set on the exact node path the receipt reports (a name collision rename is followed), then the scene is saved: one call per piece, no window at the origin. The result adds placement \{nodePath, applied, fields}. Do not combine transform with the others, or scale/transform with target\_size. Measure a kit piece first with [`summer_inspect_asset`](/mcp/tools/build#summer_inspect_asset).

| | |
| - | - |
| **Needs** | Summer Engine open with your project |
| **Effects** | writes files, changes the open project |
| **CLI** | `summer tool instantiate-scene --args '<json>'` |

**Use when:**

* placing a .tscn prefab or imported 3D model into a scene
* "put three copies of the enemy prefab in the level"
* "add the imported car.glb to the scene"
* placing a kit piece at an exact position and rotation in one call per piece

**Do not use when:**

* a bare built-in node type like Camera3D or Timer — [`summer_add_node`](/mcp/tools/build#summer_add_node)

**Inputs:**

| Input | Type | Required | Description |
| - | - | - | - |
| `scenePath` | string | Yes | Target scene to receive the instance, e.g. 'res\://main.tscn' |
| `parent` | string | Yes | Parent node path, e.g. './World' |
| `scene` | string | Yes | Scene/model path, e.g. 'res\://player.tscn' or 'res\://models/tree.glb' |
| `name` | string | No | Override the instance name |
| `target_size` | number | No | Normalize the instance's physical size: uniformly scale it so its largest world-AABB dimension equals this many units (chair 1.0, car 4.5, person 1.7). Strongly recommended for imported .glb/.gltf models. |
| `position` | any\[] | No | Parent-local position \[x, y, z] set right after the instance is created. Items 3 to 3. |
| `rotation_degrees` | any | No | Parent-local rotation in degrees \[x, y, z] (Godot rotation\_degrees). |
| `scale` | any | No | Local scale \[x, y, z]. Not with target\_size. |
| `transform` | string | No | Full local transform as "Transform3D(xx, xy, xz, yx, yy, yz, zx, zy, zz, ox, oy, oz)" (Godot row-major basis, then origin). Not with position/rotation\_degrees/scale/target\_size. |

<Accordion title="Input JSON schema">
  ```json theme={null}
  {
    "type": "object",
    "properties": {
      "scenePath": {
        "type": "string",
        "description": "Target scene to receive the instance, e.g. 'res://main.tscn'"
      },
      "parent": {
        "type": "string",
        "description": "Parent node path, e.g. './World'"
      },
      "scene": {
        "type": "string",
        "description": "Scene/model path, e.g. 'res://player.tscn' or 'res://models/tree.glb'"
      },
      "name": {
        "type": "string",
        "description": "Override the instance name"
      },
      "target_size": {
        "type": "number",
        "exclusiveMinimum": 0,
        "description": "Normalize the instance's physical size: uniformly scale it so its largest world-AABB dimension equals this many units (chair 1.0, car 4.5, person 1.7). Strongly recommended for imported .glb/.gltf models."
      },
      "position": {
        "type": "array",
        "minItems": 3,
        "maxItems": 3,
        "items": [
          {
            "type": "number"
          },
          {
            "$ref": "#/properties/position/items/0"
          },
          {
            "$ref": "#/properties/position/items/0"
          }
        ],
        "description": "Parent-local position [x, y, z] set right after the instance is created."
      },
      "rotation_degrees": {
        "$ref": "#/properties/position",
        "description": "Parent-local rotation in degrees [x, y, z] (Godot rotation_degrees)."
      },
      "scale": {
        "$ref": "#/properties/position",
        "description": "Local scale [x, y, z]. Not with target_size."
      },
      "transform": {
        "type": "string",
        "description": "Full local transform as \"Transform3D(xx, xy, xz, yx, yy, yz, zx, zy, zz, ox, oy, oz)\" (Godot row-major basis, then origin). Not with position/rotation_degrees/scale/target_size."
      }
    },
    "required": [
      "scenePath",
      "parent",
      "scene"
    ],
    "additionalProperties": false
  }
  ```
</Accordion>

**Output:** MCP text content holding JSON; errors set `isError`. From the tool's own description: The result then reports dimensions + scale\_applied; verify placement afterwards (summer\_world\_snapshot AABBs, summer\_screenshot). The result adds placement \{nodePath, applied, fields}.

```json Example call theme={null}
{
  "name": "summer_instantiate_scene",
  "arguments": {
    "scenePath": "res://main.tscn",
    "parent": "./World",
    "scene": "res://player.tscn"
  }
}
```

***

### summer\_library\_feedback

On the local MCP (`summer-engine` npm).

Report how library entries (skills, examples, templates, collections, references, tools) worked out, so Summer can fix and re-rank them — reports fix the entries this user's own future sessions load. Call once at a natural checkpoint with all entries used; fire-and-forget (1s cap, silent failure, never blocks). Only report outcome 'worked' after in-engine verification (playtest or screenshot passed). What is sent: the library entry ids you used (entry\_id), one outcome word per entry, your optional note and deviation (280 characters max each, about the entry itself), engine\_version, agent\_model (your self-reported model id), toolkit\_version (this CLI's version), client (the host app name/version from the MCP handshake), session\_id (a random id per MCP server process, never persisted), and — only when not logged in — install\_id (a random uuid stored in \~/.summer/; no hardware, user, or project identity). When logged in, the Summer account bearer token is sent instead of install\_id. The schema has no field for project files, chat content, or code. The very first call on a machine sends nothing and returns \{recorded:false, first\_run:true, notice} — call again to send. Otherwise recorded:true means the gateway accepted the batch; \{recorded:false, dropped:true, status, reason} means the 1s POST failed and the batch is gone (no retry) — reason is endpoint\_missing (404), rejected (other 4xx), server\_error (5xx) or network. The user can opt out entirely with SUMMER\_NO\_TELEMETRY=1 or DO\_NOT\_TRACK=1 — then nothing is sent and this tool returns \{recorded:false, disabled:true}.

| | |
| - | - |
| **Needs** | No open editor and no sign-in. Uses your `summer login` sign-in when you have one |
| **Effects** | writes files, uses the network |
| **CLI** | `summer tool library-feedback --args '<json>'` |

**Use when:**

* a natural checkpoint after using library entries, batching all outcomes in one call
* an entry was wrong, outdated, incomplete, or misrouted and Summer should know

**Do not use when:**

* reporting outcome worked without in-engine verification
* the note would describe the user's project, files, or code instead of the entry

**Inputs:**

| Input | Type | Required | Description |
| - | - | - | - |
| `reports` | object\[] | Yes | 1-10 outcome reports, batched at a natural checkpoint (one call, not one per entry). Items 1 to 10. |
| `reports[].entry_id` | string | Yes | The library entry ID exactly as the loader printed it (kind/slug, optionally @content-hash). Never guess or reconstruct it. |
| `reports[].outcome` | "worked" \| "worked\_with\_fixes" \| "wrong" \| "outdated" \| "incomplete" \| "did\_not\_apply" \| "misrouted" | Yes | worked = verified in-engine (playtest/screenshot passed). worked\_with\_fixes = worked after your changes (say what in deviation). wrong = incorrect content. outdated = no longer matches this engine version. incomplete = missing a needed case. did\_not\_apply = loaded but irrelevant to the task. misrouted = the description/metadata led you here wrongly. |
| `reports[].note` | string | No | Optional, max 280 chars. About the ENTRY only — never the user's project, files, or code. Length 0 to 280. |
| `reports[].deviation` | string | No | Optional, max 280 chars. What you did instead of / on top of the entry's instructions. Length 0 to 280. |
| `engine_version` | string | Yes | The Summer Engine version in use, e.g. "4.6.1". Length 1 to 32. |
| `agent_model` | string | Yes | The model you are, e.g. claude-fable-5, gpt-5.5-codex; use "unknown" if unsure. Length 1 to 64. |

<Accordion title="Input JSON schema">
  ```json theme={null}
  {
    "type": "object",
    "properties": {
      "reports": {
        "type": "array",
        "items": {
          "type": "object",
          "properties": {
            "entry_id": {
              "type": "string",
              "pattern": "^(tool|skill|example|template|collection|reference)\\/[a-z0-9-]+(@[a-f0-9]{8,64})?$",
              "description": "The library entry ID exactly as the loader printed it (kind/slug, optionally @content-hash). Never guess or reconstruct it."
            },
            "outcome": {
              "type": "string",
              "enum": [
                "worked",
                "worked_with_fixes",
                "wrong",
                "outdated",
                "incomplete",
                "did_not_apply",
                "misrouted"
              ],
              "description": "worked = verified in-engine (playtest/screenshot passed). worked_with_fixes = worked after your changes (say what in deviation). wrong = incorrect content. outdated = no longer matches this engine version. incomplete = missing a needed case. did_not_apply = loaded but irrelevant to the task. misrouted = the description/metadata led you here wrongly."
            },
            "note": {
              "type": "string",
              "maxLength": 280,
              "description": "Optional, max 280 chars. About the ENTRY only — never the user's project, files, or code."
            },
            "deviation": {
              "type": "string",
              "maxLength": 280,
              "description": "Optional, max 280 chars. What you did instead of / on top of the entry's instructions."
            }
          },
          "required": [
            "entry_id",
            "outcome"
          ],
          "additionalProperties": false
        },
        "minItems": 1,
        "maxItems": 10,
        "description": "1-10 outcome reports, batched at a natural checkpoint (one call, not one per entry)."
      },
      "engine_version": {
        "type": "string",
        "minLength": 1,
        "maxLength": 32,
        "description": "The Summer Engine version in use, e.g. \"4.6.1\"."
      },
      "agent_model": {
        "type": "string",
        "minLength": 1,
        "maxLength": 64,
        "description": "The model you are, e.g. claude-fable-5, gpt-5.5-codex; use \"unknown\" if unsure."
      }
    },
    "required": [
      "reports",
      "engine_version",
      "agent_model"
    ],
    "additionalProperties": false
  }
  ```
</Accordion>

**Output:** MCP text content holding JSON; errors set `isError`.

```json Example call theme={null}
{
  "name": "summer_library_feedback",
  "arguments": {
    "reports": [
      {
        "entry_id": "<entry_id>",
        "outcome": "worked"
      }
    ],
    "engine_version": "4.6.1",
    "agent_model": "<agent_model>"
  }
}
```

***

### summer\_measure

On the local MCP (`summer-engine` npm).

Measure placement between specific nodes from their visible-mesh bounds (evidence visual\_aabb). Read-only, never saves. Complements [`summer_starcast`](/mcp/tools/build#summer_starcast) (which reports clearance around ONE node in 26 directions).

mode pair (a, b): per axis \{gap (> 0 clearance, \< 0 overlap depth), relation gap|touching|overlap, a/b intervals, delta\_min/max/center (b minus a)} and boxes\_overlap. Catches facade gaps and modules that overlap.
mode plane (nodes, face): whether that face of every node lies on one plane: \{coplanar, plane (median), spread, nodes \[\{path, face, deviation, off\_plane: proud|recessed}]}. Catches modules standing proud of a facade line. face '+z' = the face pointing along +z.

space "local" measures along the axes of a (pair) or nodes\[0] (plane), for rotated facades. tolerance (default 5 mm) decides touching / coplanar.

| | |
| - | - |
| **Needs** | Summer Engine open with your project |
| **Effects** | read-only |
| **CLI** | `summer tool measure --args '<json>'` |

**Use when:**

* checking that two facade modules meet edge to edge, or how far apart or overlapping two pieces are on each axis
* checking that every module of a facade line has its front on one plane (plane mode) and which ones stand proud or sit recessed
* verifying a placement numerically before the screenshot

**Do not use when:**

* you want clearance around one node in every direction — [`summer_starcast`](/mcp/tools/build#summer_starcast)
* you want to test a pose before moving anything — [`summer_test_placement`](/mcp/tools/build#summer_test_placement)

**Inputs:**

| Input | Type | Required | Description |
| - | - | - | - |
| `scenePath` | string | Yes | Exact scene to read or change, e.g. 'res\://levels/street.tscn'. It must be open in the editor (any tab). Length 1 to 512. |
| `mode` | "pair" \| "plane" | No | pair: gap or overlap per axis between nodes a and b. plane: whether one face of every node in `nodes` lies on one plane. Default `"pair"`. |
| `a` | string | No | pair mode, first node: exact node path relative to the scene root, e.g. './Facade/Wall\_01'. Length 1 to 256. |
| `b` | string | No | pair mode, second node: exact node path relative to the scene root, e.g. './Facade/Wall\_01'. Length 1 to 256. |
| `axis` | "x" \| "y" \| "z" | No | pair mode: report only this axis (x, y or z of the chosen space). |
| `nodes` | string\[] | No | plane mode: 2-32 nodes whose face is checked, e.g. every module of one facade line. Items 2 to 32. |
| `face` | "+x" \| "-x" \| "+y" \| "-y" \| "+z" \| "-z" | No | plane mode: which face, e.g. '+z' for the face pointing along +z (a facade front that looks toward +z). |
| `space` | "world" \| "local" | No | world: world axes. local: the axes of a (pair) or nodes\[0] (plane), for rotated facades. Default `"world"`. |
| `tolerance` | number | No | Distance in scene units treated as touching (pair) or coplanar (plane). Default 5 mm. Default `0.005`. Range 0 to 1. |

<Accordion title="Input JSON schema">
  ```json theme={null}
  {
    "type": "object",
    "properties": {
      "scenePath": {
        "type": "string",
        "minLength": 1,
        "maxLength": 512,
        "description": "Exact scene to read or change, e.g. 'res://levels/street.tscn'. It must be open in the editor (any tab)."
      },
      "mode": {
        "type": "string",
        "enum": [
          "pair",
          "plane"
        ],
        "default": "pair",
        "description": "pair: gap or overlap per axis between nodes a and b. plane: whether one face of every node in `nodes` lies on one plane."
      },
      "a": {
        "type": "string",
        "minLength": 1,
        "maxLength": 256,
        "description": "pair mode, first node: exact node path relative to the scene root, e.g. './Facade/Wall_01'."
      },
      "b": {
        "type": "string",
        "minLength": 1,
        "maxLength": 256,
        "description": "pair mode, second node: exact node path relative to the scene root, e.g. './Facade/Wall_01'."
      },
      "axis": {
        "type": "string",
        "enum": [
          "x",
          "y",
          "z"
        ],
        "description": "pair mode: report only this axis (x, y or z of the chosen space)."
      },
      "nodes": {
        "type": "array",
        "items": {
          "type": "string",
          "minLength": 1,
          "maxLength": 256,
          "description": "plane mode node: exact node path relative to the scene root, e.g. './Facade/Wall_01'."
        },
        "minItems": 2,
        "maxItems": 32,
        "description": "plane mode: 2-32 nodes whose face is checked, e.g. every module of one facade line."
      },
      "face": {
        "type": "string",
        "enum": [
          "+x",
          "-x",
          "+y",
          "-y",
          "+z",
          "-z"
        ],
        "description": "plane mode: which face, e.g. '+z' for the face pointing along +z (a facade front that looks toward +z)."
      },
      "space": {
        "type": "string",
        "enum": [
          "world",
          "local"
        ],
        "default": "world",
        "description": "world: world axes. local: the axes of a (pair) or nodes[0] (plane), for rotated facades."
      },
      "tolerance": {
        "type": "number",
        "minimum": 0,
        "maximum": 1,
        "default": 0.005,
        "description": "Distance in scene units treated as touching (pair) or coplanar (plane). Default 5 mm."
      }
    },
    "required": [
      "scenePath"
    ],
    "additionalProperties": false
  }
  ```
</Accordion>

**Output:** MCP text content holding JSON; errors set `isError`.

```json Example call theme={null}
{
  "name": "summer_measure",
  "arguments": {
    "scenePath": "res://levels/street.tscn"
  }
}
```

***

### summer\_navigation\_probe

On the local MCP (`summer-engine` npm).

Inspect whether two explicit world-space points are connected by the targeted 3D scene's built-in Godot navigation map without changing or saving the scene.

Returns navigation readiness and its reason, map iteration and region counts, requested and layer-filtered snapped endpoints, snap distances, conservative reachability, full route length, and at most 16 deterministic route points. A path is reachable only when it terminates at both snapped endpoints within the reported tolerance.

ready:false means navigation evidence is unavailable, not that the route is unreachable. In particular, map iteration 0 precedes the first usable synchronization and can return silently empty paths; iteration 1 and later are usable. evidence is always navigation. Normal results are capped below 5 KB.

Always pass an exact scenePath and finite world-space start/end points. This read-only tool never uses editor selection, creates undo history, or calls SaveScene. On an engine build that predates NavigationProbe3D the result is a structured engine\_lacks\_op failure naming the fallback.

| | |
| - | - |
| **Needs** | Summer Engine open with your project |
| **Effects** | read-only |
| **CLI** | `summer tool navigation-probe --args '<json>'` |

**Use when:**

* placing an NPC, pickup, portal, or encounter anchor whose route from spawn matters
* checking that a moved prop did not cut the navigation mesh between two areas

**Do not use when:**

* the scene has no NavigationRegion3D (ready is false; there is nothing to probe)
* you need live agent behaviour — playtest with [`summer_play`](/mcp/tools/run-and-test#summer_play) and read [`summer_get_runtime_tree`](/mcp/tools/run-and-test#summer_get_runtime_tree)

**Inputs:**

| Input | Type | Required | Description |
| - | - | - | - |
| `scenePath` | string | Yes | Exact 3D scene whose World3D navigation map should be queried. Length 1 to 512. |
| `start` | any\[] | Yes | Requested world-space route start \[x,y,z]. Items 3 to 3. |
| `end` | any\[] | Yes | Requested world-space route destination \[x,y,z]. Items 3 to 3. |
| `navigationLayers` | integer | No | Godot navigation-layer bitmask; only enabled matching regions are used. Default `1`. Range 1 to 4294967295. |
| `optimize` | boolean | No | Use Godot's corridor-funnel path post-processing; false uses edge-centered points. Default `true`. |

<Accordion title="Input JSON schema">
  ```json theme={null}
  {
    "type": "object",
    "properties": {
      "scenePath": {
        "type": "string",
        "minLength": 1,
        "maxLength": 512,
        "description": "Exact 3D scene whose World3D navigation map should be queried."
      },
      "start": {
        "type": "array",
        "minItems": 3,
        "maxItems": 3,
        "items": [
          {
            "type": "number"
          },
          {
            "type": "number"
          },
          {
            "type": "number"
          }
        ],
        "description": "Requested world-space route start [x,y,z]."
      },
      "end": {
        "type": "array",
        "minItems": 3,
        "maxItems": 3,
        "items": [
          {
            "$ref": "#/properties/start/items/0"
          },
          {
            "$ref": "#/properties/start/items/1"
          },
          {
            "$ref": "#/properties/start/items/2"
          }
        ],
        "description": "Requested world-space route destination [x,y,z]."
      },
      "navigationLayers": {
        "type": "integer",
        "minimum": 1,
        "maximum": 4294967295,
        "default": 1,
        "description": "Godot navigation-layer bitmask; only enabled matching regions are used."
      },
      "optimize": {
        "type": "boolean",
        "default": true,
        "description": "Use Godot's corridor-funnel path post-processing; false uses edge-centered points."
      }
    },
    "required": [
      "scenePath",
      "start",
      "end"
    ],
    "additionalProperties": false
  }
  ```
</Accordion>

**Output:** MCP text content holding JSON; errors set `isError`. From the tool's own description: Returns navigation readiness and its reason, map iteration and region counts, requested and layer-filtered snapped endpoints, snap distances, conservative reachability, full route length, and at most 16 deterministic route points.

```json Example call theme={null}
{
  "name": "summer_navigation_probe",
  "arguments": {
    "scenePath": "<scenePath>",
    "start": [
      "<start>"
    ],
    "end": [
      "<end>"
    ]
  }
}
```

***

### summer\_open

On the local MCP (`summer-engine` npm).

Open the exact summerengine.com page or Summer Engine editor surface the user wants to LOOK at, by intent name — or, with open:false, return the URL / engine op without opening anything. The result ALWAYS carries the resolved url or op, also after opening, so you can tell the user where they landed.

WHEN: the user wants to see, check, or decide something: "open my billing page", "show me my published games", "take me to pricing", "open the MCP setup guide for Cursor", "show me the scene", "select the Player node", "open player.gd". NOT for getting a result (add a node, set a property, publish) — use the mutation tools; opening a UI is a user-visible action, do it because the user asked to look, and say what will open.

target: an id (billing, usage, account, settings, team, my-games, game, pricing, download, mcp-guide, templates, asset-store, docs, scene, main-scene, node, script, file, files, scene-tree, inspector, screen-3d, assistant, project-settings, output, debugger, editor-window, …), an intent phrase ("change my plan"), a res\:// path (routed by extension: .tscn -> scene, .gd -> script, else file), or a summerengine.com path ("/pricing"). Omit target to LIST every destination with surface/status/requires.
params: slot values — gameId + section (builds, releases, store-page, analytics, …) for game; guide (agent name: cursor, claude-code, codex, gemini, …) for mcp-guide; username; version; path / node / scene / line / col / tab for editor targets.
open: false resolves only and returns url (+ login\_url when the page needs login) or op; nothing opens, no engine needed.

Result: \{ ok, action: opened | printed | listed | ambiguous | unsupported | engine\_not\_running | engine\_error | not\_found | invalid\_params | open\_failed | blocked\_origin, target (with availability for editor ids), url, login\_url, logged\_in, opened\_url, op, engine, failure\_reason, matches, hint }.

* Web targets that require login open through /login?returnUrl=\<path> when this machine holds no Summer login token (logged\_in:false) — the destination loads after sign-in.
* Editor targets need Summer Engine running with the project open; otherwise action engine\_not\_running with the op that would have been sent and a 'summer run' hint. Nothing was opened.
* Editor destinations are forwarded to the engine's own navigation table (op Navigate; ids advertised in /api/health capabilities.navigation). On an engine that predates it, scene/node/script/file and the three docks still work through their original ops; anything else answers action unsupported with failure\_reason engine\_lacks\_op and an update hint. Never claim those opened. Listing (no target) shows each editor id's availability from the connected engine.
* ambiguous: several destinations match; call again with one of matches\[].id.
  Only summerengine.com (and subdomains) are ever opened — a gateway configured elsewhere is refused (blocked\_origin); res\:// paths with .. or other escapes are refused; a machine with no browser gets open\_failed with the url to hand over.

| | |
| - | - |
| **Needs** | Summer Engine open with your project |
| **Effects** | read-only |
| **CLI** | `summer open` |

**Use when:**

* the user wants to SEE or DECIDE something on the website — "open my billing page", "show me my published games", "take me to pricing", "open the MCP setup guide for Cursor"
* the user wants to LOOK at something in the running editor — "show me the scene", "select the Player node", "open player.gd", "reveal that texture in the file dock"
* "open the main scene in the editor" / "open the scene I am editing so I can look at it" — an editor surface the USER should see, navigated for them (the scene tools open a tab for the agent, not for the user)
* handing the user a link instead of opening a browser (open: false), or checking which destination an intent maps to
* resolving where a user intent lives ("where do I change my plan?") before acting

**Do not use when:**

* the user wants a result, not a view — add the node, set the property, publish; use the mutation tools ([`summer_add_node`](/mcp/tools/build#summer_add_node), [`summer_set_prop`](/mcp/tools/build#summer_set_prop), [`summer_publish_build`](/mcp/tools/publish#summer_publish_build))
* opening a project directory in the engine — that is the CLI's `summer open <path>` / `summer run <path>` project launcher, not a navigation target
* the destination is not on summerengine.com or docs.summerengine.com — the tool refuses other origins

**Inputs:**

| Input | Type | Required | Description |
| - | - | - | - |
| `target` | string | No | Where to go: a target id (billing, my-games, mcp-guide, scene, node, inspector, …), an intent phrase ("change my plan"), a res\:// path, or a summerengine.com path ("/pricing"). Omit to list every target. |
| `params` | object | No | Slot values for the target: gameId, section, username, version, guide (agent name or guide slug), path (res\://…), node, scene, line, col, tab. |
| `surface` | "auto" \| "web" \| "editor" | No | Restrict matching to the website or the editor. "auto" (default) considers both. |
| `open` | boolean | No | Default true: open it. false = resolve only — return the URL or engine op and open nothing (works without the engine and without a browser). The CLI's --print. |

<Accordion title="Input JSON schema">
  ```json theme={null}
  {
    "type": "object",
    "properties": {
      "target": {
        "type": "string",
        "description": "Where to go: a target id (billing, my-games, mcp-guide, scene, node, inspector, …), an intent phrase (\"change my plan\"), a res:// path, or a summerengine.com path (\"/pricing\"). Omit to list every target."
      },
      "params": {
        "type": "object",
        "additionalProperties": {
          "type": "string"
        },
        "description": "Slot values for the target: gameId, section, username, version, guide (agent name or guide slug), path (res://…), node, scene, line, col, tab."
      },
      "surface": {
        "type": "string",
        "enum": [
          "auto",
          "web",
          "editor"
        ],
        "description": "Restrict matching to the website or the editor. \"auto\" (default) considers both."
      },
      "open": {
        "type": "boolean",
        "description": "Default true: open it. false = resolve only — return the URL or engine op and open nothing (works without the engine and without a browser). The CLI's --print."
      }
    },
    "additionalProperties": false
  }
  ```
</Accordion>

**Output:** MCP text content holding JSON; errors set `isError`. From the tool's own description: The result ALWAYS carries the resolved url or op, also after opening, so you can tell the user where they landed. Result: \{ ok, action: opened | printed | listed | ambiguous | unsupported | engine\_not\_running | engine\_error | not\_found | invalid\_params | open\_failed | blocked\_origin, target (with availability for editor ids), url, login\_url, logged\_in, opened\_url, op, engine, failure\_reason, matches, hint }.

```json Example call theme={null}
{
  "name": "summer_open",
  "arguments": {}
}
```

***

### summer\_open\_main\_scene

On the local MCP (`summer-engine` npm).

Open the project's configured main scene from project settings.

Safer than guessing scene names like main.tscn/Main.tscn.
Call this when you get "no scene open".

| | |
| - | - |
| **Needs** | Summer Engine open with your project |
| **Effects** | changes the open project |
| **CLI** | `summer tool open-main-scene --args '<json>'` |

**Use when:**

* any tool reports that no scene is open
* "get me back to the game's main scene"
* a fresh session with no active scene tab

**Do not use when:**

* a specific non-main scene — [`summer_open_scene`](/mcp/tools/build#summer_open_scene) with its path

**Inputs:**

No inputs.

<Accordion title="Input JSON schema">
  ```json theme={null}
  {
    "type": "object",
    "properties": {}
  }
  ```
</Accordion>

**Output:** MCP text content holding JSON; errors set `isError`.

```json Example call theme={null}
{
  "name": "summer_open_main_scene",
  "arguments": {}
}
```

***

### summer\_open\_scene

On the local MCP (`summer-engine` npm).

Open a scene file in the editor. Use this to switch between scenes.

Do not guess paths. Prefer:

1. [`summer_get_project_context`](/mcp/tools/build#summer_get_project_context) (read mainScene)
2. [`summer_open_main_scene`](/mcp/tools/build#summer_open_main_scene) (open known main scene)
3. [`summer_open_scene`](/mcp/tools/build#summer_open_scene) only when user gave an explicit path.

| | |
| - | - |
| **Needs** | Summer Engine open with your project |
| **Effects** | changes the open project |
| **CLI** | `summer tool open-scene --args '<json>'` |

**Use when:**

* switching the editor to an explicitly known scene path
* "switch to level2.tscn" / "open the player prefab in the editor"
* a tool needs a different scene to be the active tab

**Do not use when:**

* guessing scene filenames (resolve them from project context first)
* the project's main scene — [`summer_open_main_scene`](/mcp/tools/build#summer_open_main_scene)

**Inputs:**

| Input | Type | Required | Description |
| - | - | - | - |
| `path` | string | Yes | Scene path, e.g. 'res\://main.tscn' or 'res\://levels/level1.tscn' |

<Accordion title="Input JSON schema">
  ```json theme={null}
  {
    "type": "object",
    "properties": {
      "path": {
        "type": "string",
        "description": "Scene path, e.g. 'res://main.tscn' or 'res://levels/level1.tscn'"
      }
    },
    "required": [
      "path"
    ],
    "additionalProperties": false
  }
  ```
</Accordion>

**Output:** MCP text content holding JSON; errors set `isError`.

```json Example call theme={null}
{
  "name": "summer_open_scene",
  "arguments": {
    "path": "res://main.tscn"
  }
}
```

***

### summer\_place\_adjacent

On the local MCP (`summer-engine` npm).

Move one node so its bounds face sits against another node's bounds face along one axis: facade modules edge to edge, a storey stacked on the one below, a cornice on a wall. Optionally line up the other two axes (min, center or max), per axis.

Example: next module to the right, same base height, same front plane: \{axis:"x", side:"max", gap:0, alignOtherAxes:\{y:"min", z:"max"}}.

Bounds are the visible GeometryInstance3D AABBs (the definition [`summer_align_distribute_3d`](/mcp/tools/build#summer_align_distribute_3d) uses; evidence visual\_aabb). space "local" uses the reference's own axes for rotated facades. When the subject is inside the reference, its geometry is left out of the reference's bounds. One SetProp on position, one undo step, then the scene is saved; a fresh read verifies the achieved gap and residuals (verify). Returns \{moved\_by, position, verify:\{gap, residuals}}. The scene must be open in the editor (any tab).

| | |
| - | - |
| **Needs** | Summer Engine open with your project |
| **Effects** | writes files, changes the open project |
| **CLI** | `summer tool place-adjacent --args '<json>'` |

**Use when:**

* laying facade or wall modules edge to edge along a street line
* stacking a storey, cornice or crown on the piece below
* putting a piece flush beside another with the same base height and front plane

**Do not use when:**

* aligning or spacing a whole group along one axis — [`summer_align_distribute_3d`](/mcp/tools/build#summer_align_distribute_3d)
* seating a piece on a floor or a wall surface — [`summer_snap_to_surface`](/mcp/tools/build#summer_snap_to_surface) or [`summer_attach_to_surface`](/mcp/tools/build#summer_attach_to_surface)

**Inputs:**

| Input | Type | Required | Description |
| - | - | - | - |
| `scenePath` | string | Yes | Exact scene to read or change, e.g. 'res\://levels/street.tscn'. It must be open in the editor (any tab). Length 1 to 512. |
| `subject` | string | Yes | Node to move: exact node path relative to the scene root, e.g. './Facade/Wall\_01'. Length 1 to 256. |
| `reference` | string | Yes | Node that stays put: exact node path relative to the scene root, e.g. './Facade/Wall\_01'. Length 1 to 256. |
| `axis` | "x" \| "y" \| "z" | Yes | Axis along which the two pieces meet (x, y or z of the chosen space). |
| `side` | "min" \| "max" | Yes | max: subject goes on the reference's +axis side (its min face against the reference's max face). min: the -axis side. |
| `gap` | number | No | Distance between the two faces along axis. 0 = flush; negative = overlap (inset). Default `0`. Range -100 to 1000. |
| `alignOtherAxes` | "min" \| "center" \| "max" \| "none" \| object | No | How to line up the other two axes: min, center, max or none (keep). One mode for both, or per axis, e.g. \{y: 'min', z: 'max'} for same base height and one front plane. Default `"none"`. |
| `space` | "world" \| "local" | No | world: world axes. local: the reference's own axes, for a rotated facade. Default `"world"`. |

<Accordion title="Input JSON schema">
  ```json theme={null}
  {
    "type": "object",
    "properties": {
      "scenePath": {
        "type": "string",
        "minLength": 1,
        "maxLength": 512,
        "description": "Exact scene to read or change, e.g. 'res://levels/street.tscn'. It must be open in the editor (any tab)."
      },
      "subject": {
        "type": "string",
        "minLength": 1,
        "maxLength": 256,
        "description": "Node to move: exact node path relative to the scene root, e.g. './Facade/Wall_01'."
      },
      "reference": {
        "type": "string",
        "minLength": 1,
        "maxLength": 256,
        "description": "Node that stays put: exact node path relative to the scene root, e.g. './Facade/Wall_01'."
      },
      "axis": {
        "type": "string",
        "enum": [
          "x",
          "y",
          "z"
        ],
        "description": "Axis along which the two pieces meet (x, y or z of the chosen space)."
      },
      "side": {
        "type": "string",
        "enum": [
          "min",
          "max"
        ],
        "description": "max: subject goes on the reference's +axis side (its min face against the reference's max face). min: the -axis side."
      },
      "gap": {
        "type": "number",
        "minimum": -100,
        "maximum": 1000,
        "default": 0,
        "description": "Distance between the two faces along axis. 0 = flush; negative = overlap (inset)."
      },
      "alignOtherAxes": {
        "anyOf": [
          {
            "type": "string",
            "enum": [
              "min",
              "center",
              "max",
              "none"
            ]
          },
          {
            "type": "object",
            "properties": {
              "x": {
                "$ref": "#/properties/alignOtherAxes/anyOf/0"
              },
              "y": {
                "$ref": "#/properties/alignOtherAxes/anyOf/0"
              },
              "z": {
                "$ref": "#/properties/alignOtherAxes/anyOf/0"
              }
            },
            "additionalProperties": false
          }
        ],
        "default": "none",
        "description": "How to line up the other two axes: min, center, max or none (keep). One mode for both, or per axis, e.g. {y: 'min', z: 'max'} for same base height and one front plane."
      },
      "space": {
        "type": "string",
        "enum": [
          "world",
          "local"
        ],
        "default": "world",
        "description": "world: world axes. local: the reference's own axes, for a rotated facade."
      }
    },
    "required": [
      "scenePath",
      "subject",
      "reference",
      "axis",
      "side"
    ],
    "additionalProperties": false
  }
  ```
</Accordion>

**Output:** MCP text content holding JSON; errors set `isError`. From the tool's own description: Returns \{moved\_by, position, verify:\{gap, residuals}}.

```json Example call theme={null}
{
  "name": "summer_place_adjacent",
  "arguments": {
    "scenePath": "res://levels/street.tscn",
    "subject": "./Facade/Wall_01",
    "reference": "./Facade/Wall_01",
    "axis": "x",
    "side": "min"
  }
}
```

***

### summer\_project\_setting

On the local MCP (`summer-engine` npm).

Set a project setting in project.godot. Common settings:

* "application/config/name" — project name
* "application/run/main\_scene" — main scene path
* "rendering/renderer/rendering\_method" — "forward\_plus", "mobile", or "gl\_compatibility"
* "display/window/size/viewport\_width" — window width
* "display/window/size/viewport\_height" — window height
* "physics/3d/default\_gravity" — gravity value (float)

| | |
| - | - |
| **Needs** | Summer Engine open with your project |
| **Effects** | writes files, changes the open project |
| **CLI** | `summer tool project-setting --args '<json>'` |

**Use when:**

* configuring project-level behavior
* "make the game start on Level1" — changing the main scene
* "set the resolution / fullscreen / gravity / physics tick rate"

**Do not use when:**

* per-node properties — [`summer_set_prop`](/mcp/tools/build#summer_set_prop)
* key bindings — [`summer_input_map_bind`](/mcp/tools/build#summer_input_map_bind)

**Inputs:**

| Input | Type | Required | Description |
| - | - | - | - |
| `key` | string | Yes | Setting key path, e.g. 'application/config/name' |
| `value` | string \| number \| boolean | Yes | Setting value |

<Accordion title="Input JSON schema">
  ```json theme={null}
  {
    "type": "object",
    "properties": {
      "key": {
        "type": "string",
        "description": "Setting key path, e.g. 'application/config/name'"
      },
      "value": {
        "type": [
          "string",
          "number",
          "boolean"
        ],
        "description": "Setting value"
      }
    },
    "required": [
      "key",
      "value"
    ],
    "additionalProperties": false
  }
  ```
</Accordion>

**Output:** MCP text content holding JSON; errors set `isError`.

```json Example call theme={null}
{
  "name": "summer_project_setting",
  "arguments": {
    "key": "application/config/name",
    "value": "<value>"
  }
}
```

***

### summer\_raycast

On the local MCP (`summer-engine` npm).

Cast one ray from any point in an open scene, before anything is placed there: find the wall, floor or ceiling in front of a point and its normal. ([`summer_starcast`](/mcp/tools/build#summer_starcast) casts from an existing node's bounds; this casts from an arbitrary origin.)

evidence auto (default): physics first (collider hit: exact point and normal); if physics hits nothing, the nearest visible-mesh AABB hit, declared with fallback:true and fallback\_reason. Physics needs the scene to be the active editor tab (only that scene's bodies are in the editor's physics space); otherwise auto falls back to visual AABBs. When physics hits but a mesh-only object is nearer, nearer\_visual\_only names it.

Returns \{hit, evidence, path, point, normal, distance, origin, direction, physics\_available, warnings}. Read-only (RunSceneScript probe, undo "none"); never saves.

| | |
| - | - |
| **Needs** | Summer Engine open with your project |
| **Effects** | read-only |
| **CLI** | `summer tool raycast --args '<json>'` |

**Use when:**

* finding the wall, floor or ceiling in front of a point and its normal before anything is placed there
* choosing where a lamp, pipe or sign mounts on a facade
* checking what a line of sight or a drop line hits

**Do not use when:**

* you want clearance around an existing node in every direction — [`summer_starcast`](/mcp/tools/build#summer_starcast)
* you want to mount the piece in the same call — [`summer_attach_to_surface`](/mcp/tools/build#summer_attach_to_surface) casts its own ray

**Inputs:**

| Input | Type | Required | Description |
| - | - | - | - |
| `scenePath` | string | Yes | Exact scene to read or change, e.g. 'res\://levels/street.tscn'. It must be open in the editor (any tab). Length 1 to 512. |
| `origin` | any\[] | Yes | Ray start in scene (world) space \[x, y, z]. Nothing needs to be placed there. Items 3 to 3. |
| `direction` | any\[] | Yes | Ray direction \[x, y, z]; normalized for you. Items 3 to 3. |
| `maxDistance` | number | No | Maximum ray length in scene units. Default `100`. Range … to 10000. |
| `collisionMask` | integer | No | Godot 3D physics layer mask for physics queries. Default `4294967295`. Range 0 to 4294967295. |
| `collideWithAreas` | boolean | No | Also hit Area3D volumes (physics only). Default `false`. |
| `evidence` | "auto" \| "physics" \| "visual\_aabb" | No | auto: physics first, visual AABB fallback when physics finds nothing (declared). physics or visual\_aabb: that channel only. Default `"auto"`. |
| `exclude` | string\[] | No | Nodes (with their descendants) the ray ignores, e.g. the piece you are about to move. Items 0 to 16. |

<Accordion title="Input JSON schema">
  ```json theme={null}
  {
    "type": "object",
    "properties": {
      "scenePath": {
        "type": "string",
        "minLength": 1,
        "maxLength": 512,
        "description": "Exact scene to read or change, e.g. 'res://levels/street.tscn'. It must be open in the editor (any tab)."
      },
      "origin": {
        "type": "array",
        "minItems": 3,
        "maxItems": 3,
        "items": [
          {
            "type": "number"
          },
          {
            "$ref": "#/properties/origin/items/0"
          },
          {
            "$ref": "#/properties/origin/items/0"
          }
        ],
        "description": "Ray start in scene (world) space [x, y, z]. Nothing needs to be placed there."
      },
      "direction": {
        "type": "array",
        "minItems": 3,
        "maxItems": 3,
        "items": [
          {
            "$ref": "#/properties/origin/items/0"
          },
          {
            "$ref": "#/properties/origin/items/0"
          },
          {
            "$ref": "#/properties/origin/items/0"
          }
        ],
        "description": "Ray direction [x, y, z]; normalized for you."
      },
      "maxDistance": {
        "type": "number",
        "exclusiveMinimum": 0,
        "maximum": 10000,
        "default": 100,
        "description": "Maximum ray length in scene units."
      },
      "collisionMask": {
        "type": "integer",
        "minimum": 0,
        "maximum": 4294967295,
        "default": 4294967295,
        "description": "Godot 3D physics layer mask for physics queries."
      },
      "collideWithAreas": {
        "type": "boolean",
        "default": false,
        "description": "Also hit Area3D volumes (physics only)."
      },
      "evidence": {
        "type": "string",
        "enum": [
          "auto",
          "physics",
          "visual_aabb"
        ],
        "default": "auto",
        "description": "auto: physics first, visual AABB fallback when physics finds nothing (declared). physics or visual_aabb: that channel only."
      },
      "exclude": {
        "type": "array",
        "items": {
          "type": "string",
          "minLength": 1,
          "maxLength": 256,
          "description": "node to ignore: exact node path relative to the scene root, e.g. './Facade/Wall_01'."
        },
        "maxItems": 16,
        "description": "Nodes (with their descendants) the ray ignores, e.g. the piece you are about to move."
      }
    },
    "required": [
      "scenePath",
      "origin",
      "direction"
    ],
    "additionalProperties": false
  }
  ```
</Accordion>

**Output:** MCP text content holding JSON; errors set `isError`. From the tool's own description: Returns \{hit, evidence, path, point, normal, distance, origin, direction, physics\_available, warnings}.

```json Example call theme={null}
{
  "name": "summer_raycast",
  "arguments": {
    "scenePath": "res://levels/street.tscn",
    "origin": [
      "<origin>"
    ],
    "direction": [
      "<direction>"
    ]
  }
}
```

***

### summer\_read\_file

On the local MCP (`summer-engine` npm).

Read a text file from the engine-bound project and return its full-file sha256 receipt.

Use the returned sha256 as expected\_sha256 when overwriting an existing file. Paths must begin with res\://.

READ BIG FILES IN PARTS instead of all at once:

* offset + limit page the file: lines by default (unit:'bytes' for a byte range on UTF-8 boundaries). The result's data.window gives start\_line/end\_line, total\_lines, next\_offset (null at the end) and eof.
* For JSON: json\_path picks one value ('pieces.wall\_a', 'items\[3]'); keys keeps matching object keys (\['wall\_\*']); keys\_only lists key names only. data.json says what matched. offset/limit then page the selection.
  The sha256 always covers the WHOLE file, so a windowed read still guards a later overwrite. Files over 1 MB can be paged only within their first 1 MB.

| | |
| - | - |
| **Needs** | Summer Engine open with your project |
| **Effects** | read-only |
| **CLI** | `summer tool read-file --args '<json>'` |

**Use when:**

* reading project files through the engine
* getting the sha256 required before overwriting a file
* reading a file too big for one result in pages (offset/limit)
* "read the wall\_door\_b entry of a kit manifest" — json\_path / keys instead of the whole file

**Inputs:**

| Input | Type | Required | Description |
| - | - | - | - |
| `path` | string | Yes | Project path, e.g. res\://scripts/player.gd |
| `max_bytes` | integer | No | Most bytes of content to return (UTF-8). Default 200000. A window or JSON selection is cut at this size too. Default `200000`. Range … to 1000000. |
| `offset` | integer | No | Skip this many units (lines by default, see unit) before returning content. 0 = from the start. Range 0 to …. |
| `limit` | integer | No | Return at most this many units (lines by default). The result's window\.next\_offset continues the read. |
| `unit` | "lines" \| "bytes" | No | What offset/limit count: 'lines' (default) or 'bytes' (cut on UTF-8 character boundaries). |
| `json_path` | string | No | For a JSON file: return only this value, e.g. 'pieces.wall\_a', 'pieces\["a b"]', 'items\[3].size\_m'. |
| `keys` | string\[] | No | For a JSON object (the file root or the json\_path value): keep only these keys; \* and ? wildcards, e.g. \['wall\_\*']. Items 0 to 64. |
| `keys_only` | boolean | No | For a JSON object: return only its key names (after the keys filter), not the values — a cheap table of contents. |

<Accordion title="Input JSON schema">
  ```json theme={null}
  {
    "type": "object",
    "properties": {
      "path": {
        "type": "string",
        "description": "Project path, e.g. res://scripts/player.gd"
      },
      "max_bytes": {
        "type": "integer",
        "exclusiveMinimum": 0,
        "maximum": 1000000,
        "default": 200000,
        "description": "Most bytes of content to return (UTF-8). Default 200000. A window or JSON selection is cut at this size too."
      },
      "offset": {
        "type": "integer",
        "minimum": 0,
        "description": "Skip this many units (lines by default, see unit) before returning content. 0 = from the start."
      },
      "limit": {
        "type": "integer",
        "exclusiveMinimum": 0,
        "description": "Return at most this many units (lines by default). The result's window.next_offset continues the read."
      },
      "unit": {
        "type": "string",
        "enum": [
          "lines",
          "bytes"
        ],
        "description": "What offset/limit count: 'lines' (default) or 'bytes' (cut on UTF-8 character boundaries)."
      },
      "json_path": {
        "type": "string",
        "description": "For a JSON file: return only this value, e.g. 'pieces.wall_a', 'pieces[\"a b\"]', 'items[3].size_m'."
      },
      "keys": {
        "type": "array",
        "items": {
          "type": "string"
        },
        "maxItems": 64,
        "description": "For a JSON object (the file root or the json_path value): keep only these keys; * and ? wildcards, e.g. ['wall_*']."
      },
      "keys_only": {
        "type": "boolean",
        "description": "For a JSON object: return only its key names (after the keys filter), not the values — a cheap table of contents."
      }
    },
    "required": [
      "path"
    ],
    "additionalProperties": false
  }
  ```
</Accordion>

**Output:** MCP text content holding JSON; errors set `isError`. From the tool's own description: The result's data.window gives start\_line/end\_line, total\_lines, next\_offset (null at the end) and eof.

```json Example call theme={null}
{
  "name": "summer_read_file",
  "arguments": {
    "path": "<path>"
  }
}
```

***

### summer\_read\_library

On the local MCP (`summer-engine` npm).

Load one library entry by id (\<kind>/\<slug>, as returned by [`summer_search_library`](/mcp/tools/build#summer_search_library)). Skills: the SKILL.md body plus metadata (status, use\_when, related) and how to invoke the skill in your host (bare slug). Tools: how to call it (MCP name, `summer tool <slug> --args`, engine requirement, authority) plus the descriptor. Templates: the pinned repo @ commit and tree digest (or built-in) and the `summer create <slug>` command. References: the markdown body. Linked files: a body ends with its relative links and the id that loads each; a file an entry links loads by \<entry id>/\<link as written> (e.g. skill/spatial-placement/references/kit-placement-tools.md), by the relative path alone when one entry ships it, inside library/ only. part: 'skill' = body only, 'resource' = the resource.yaml descriptor only, 'all' (default) = both. The LAST line of every load is the feedback footer `— entry_id: <id>@<content-hash>. If this entry is wrong, stale, or you deviate from it, report via summer_library_feedback.` — copy that entry\_id verbatim into [`summer_library_feedback`](/mcp/tools/build#summer_library_feedback) once you have verified the outcome in-engine. Unknown id -> \{ok:false, error:'not\_found', nearest:\[up to 3 ids]}. No engine needed; reads the library shipped with this package.

| | |
| - | - |
| **Needs** | No open editor and no sign-in. Uses your `summer login` sign-in when you have one |
| **Effects** | read-only |
| **CLI** | `summer tool read-library --args '<json>'` |

**Use when:**

* [`summer_search_library`](/mcp/tools/build#summer_search_library) returned an id and you need the entry itself before acting
* re-reading a skill or reference the current version of (entries evolve — never rely on memory of one)
* checking how to call a tool or how a template is pinned without walking the library folders

**Do not use when:**

* you do not know the id yet — [`summer_search_library`](/mcp/tools/build#summer_search_library) first
* the skill is installed in your host — invoking it there (Claude Code /\<slug>) loads the same body

**Inputs:**

| Input | Type | Required | Description |
| - | - | - | - |
| `id` | string | Yes | The entry id as returned by summer\_search\_library: \<kind>/\<slug>, e.g. skill/vfx-water-ripple or tool/screenshot. A file an entry links loads by \<entry id>/\<link as written>, e.g. skill/spatial-placement/references/kit-placement-tools.md; the 'linked files' list at the end of a body gives each id. Length 1 to 200. |
| `part` | "skill" \| "resource" \| "all" | No | 'skill' = the body only (SKILL.md for skills; the markdown body for references; how-to-call for tools; the pin for templates). 'resource' = the resource.yaml descriptor only. 'all' (default) = both. |

<Accordion title="Input JSON schema">
  ```json theme={null}
  {
    "type": "object",
    "properties": {
      "id": {
        "type": "string",
        "minLength": 1,
        "maxLength": 200,
        "description": "The entry id as returned by summer_search_library: <kind>/<slug>, e.g. skill/vfx-water-ripple or tool/screenshot. A file an entry links loads by <entry id>/<link as written>, e.g. skill/spatial-placement/references/kit-placement-tools.md; the 'linked files' list at the end of a body gives each id."
      },
      "part": {
        "type": "string",
        "enum": [
          "skill",
          "resource",
          "all"
        ],
        "description": "'skill' = the body only (SKILL.md for skills; the markdown body for references; how-to-call for tools; the pin for templates). 'resource' = the resource.yaml descriptor only. 'all' (default) = both."
      }
    },
    "required": [
      "id"
    ],
    "additionalProperties": false
  }
  ```
</Accordion>

**Output:** MCP text content holding JSON; errors set `isError`.

```json Example call theme={null}
{
  "name": "summer_read_library",
  "arguments": {
    "id": "<id>"
  }
}
```

***

### summer\_remove\_node

On the local MCP (`summer-engine` npm).

Remove a node from the scene tree. All children are removed too. Cannot remove the root node. Supports undo. Destructive operation: do not delete multiple top-level nodes unless the user explicitly requests destructive changes.

| | |
| - | - |
| **Needs** | Summer Engine open with your project |
| **Effects** | writes files, changes the open project |
| **CLI** | `summer tool remove-node --args '<json>'` |

**Use when:**

* deleting scene content the user asked to remove
* "delete the old camera" / "get rid of the debug label"
* removing the placeholder cube now that the real model is in

**Do not use when:**

* bulk-deleting top-level nodes without an explicit user request

**Inputs:**

| Input | Type | Required | Description |
| - | - | - | - |
| `scenePath` | string | Yes | Target scene path, e.g. 'res\://main.tscn' |
| `path` | string | Yes | Node path to remove, e.g. './World/OldEnemy' |

<Accordion title="Input JSON schema">
  ```json theme={null}
  {
    "type": "object",
    "properties": {
      "scenePath": {
        "type": "string",
        "description": "Target scene path, e.g. 'res://main.tscn'"
      },
      "path": {
        "type": "string",
        "description": "Node path to remove, e.g. './World/OldEnemy'"
      }
    },
    "required": [
      "scenePath",
      "path"
    ],
    "additionalProperties": false
  }
  ```
</Accordion>

**Output:** MCP text content holding JSON; errors set `isError`.

```json Example call theme={null}
{
  "name": "summer_remove_node",
  "arguments": {
    "scenePath": "res://main.tscn",
    "path": "./World/OldEnemy"
  }
}
```

***

### summer\_repeat\_along

On the local MCP (`summer-engine` npm).

Instance copies of one scene along a straight line in one call: wall clamps every 0.45 m, braces every 0.8 m, fence posts, a row of window modules. Give start plus end (with spacing or count) or start plus direction (with count and spacing); positions are in the parent's local space. align (start|center|end) places the leftover length when spacing does not divide the line. Each copy is an InstantiateScene (the engine runs each alone), named \<namePrefix>\_\<n>; the copies' transforms (position, rotationDegrees, scale) are then set in one request and the scene is saved once: N copies cost N + 2 engine requests. At most 64 copies per call.

Returns a compact receipt: \{count, spacing, first, last, created \[node paths], renamed, failures \[\{index, error}], saved}. Lists are cut to stay under 5 KB and the cut is declared.

| | |
| - | - |
| **Needs** | Summer Engine open with your project |
| **Effects** | writes files, changes the open project |
| **CLI** | `summer tool repeat-along --args '<json>'` |

**Use when:**

* placing wall clamps, gutter braces or duct braces at a fixed spacing along a run
* a row of fence posts, bollards, lamps or window modules
* filling a line with as many copies as fit at a spacing

**Do not use when:**

* scattering copies over an area or a grid — [`summer_run_script`](/mcp/tools/build#summer_run_script) with ctx.scatter / ctx.grid
* spacing nodes that already exist — [`summer_align_distribute_3d`](/mcp/tools/build#summer_align_distribute_3d)

**Inputs:**

| Input | Type | Required | Description |
| - | - | - | - |
| `scenePath` | string | Yes | Exact scene to read or change, e.g. 'res\://levels/street.tscn'. It must be open in the editor (any tab). Length 1 to 512. |
| `template` | string | Yes | Scene to instance for every copy, e.g. 'res\://kit/pipes/wall\_clamp\_a.tscn'. Length 1 to 512. |
| `parent` | string | Yes | Parent for the copies; start/end/direction are in this parent's local space (same as position). Length 1 to 256. |
| `start` | any\[] | Yes | First copy's position \[x, y, z] in the parent's space. Items 3 to 3. |
| `end` | any\[] | No | Line end. With spacing: as many copies as fit; with count: count copies spread from start to end. Items 3 to 3. |
| `direction` | any | No | Instead of end: direction of the row; needs count and spacing. |
| `count` | integer | No | Number of copies (1-64). Range 1 to 64. |
| `spacing` | number | No | Distance between neighbouring copies' origins. Range … to 1000. |
| `align` | "start" \| "center" \| "end" | No | With end + spacing: where the leftover length goes. start = first copy at start; center = leftover split; end = last copy at end. Default `"start"`. |
| `rotationDegrees` | any | No | rotation\_degrees for every copy \[x, y, z]. |
| `scale` | any | No | scale for every copy \[x, y, z]. |
| `namePrefix` | string | No | Copies are named \<namePrefix>\_\<n> (default: the template file name). Length 1 to 64. |

<Accordion title="Input JSON schema">
  ```json theme={null}
  {
    "type": "object",
    "properties": {
      "scenePath": {
        "type": "string",
        "minLength": 1,
        "maxLength": 512,
        "description": "Exact scene to read or change, e.g. 'res://levels/street.tscn'. It must be open in the editor (any tab)."
      },
      "template": {
        "type": "string",
        "minLength": 1,
        "maxLength": 512,
        "description": "Scene to instance for every copy, e.g. 'res://kit/pipes/wall_clamp_a.tscn'."
      },
      "parent": {
        "type": "string",
        "minLength": 1,
        "maxLength": 256,
        "description": "Parent for the copies; start/end/direction are in this parent's local space (same as position)."
      },
      "start": {
        "type": "array",
        "minItems": 3,
        "maxItems": 3,
        "items": [
          {
            "type": "number"
          },
          {
            "$ref": "#/properties/start/items/0"
          },
          {
            "$ref": "#/properties/start/items/0"
          }
        ],
        "description": "First copy's position [x, y, z] in the parent's space."
      },
      "end": {
        "type": "array",
        "minItems": 3,
        "maxItems": 3,
        "items": [
          {
            "$ref": "#/properties/start/items/0"
          },
          {
            "$ref": "#/properties/start/items/0"
          },
          {
            "$ref": "#/properties/start/items/0"
          }
        ],
        "description": "Line end. With spacing: as many copies as fit; with count: count copies spread from start to end."
      },
      "direction": {
        "$ref": "#/properties/end",
        "description": "Instead of end: direction of the row; needs count and spacing."
      },
      "count": {
        "type": "integer",
        "minimum": 1,
        "maximum": 64,
        "description": "Number of copies (1-64)."
      },
      "spacing": {
        "type": "number",
        "exclusiveMinimum": 0,
        "maximum": 1000,
        "description": "Distance between neighbouring copies' origins."
      },
      "align": {
        "type": "string",
        "enum": [
          "start",
          "center",
          "end"
        ],
        "default": "start",
        "description": "With end + spacing: where the leftover length goes. start = first copy at start; center = leftover split; end = last copy at end."
      },
      "rotationDegrees": {
        "$ref": "#/properties/end",
        "description": "rotation_degrees for every copy [x, y, z]."
      },
      "scale": {
        "$ref": "#/properties/end",
        "description": "scale for every copy [x, y, z]."
      },
      "namePrefix": {
        "type": "string",
        "minLength": 1,
        "maxLength": 64,
        "description": "Copies are named <namePrefix>_<n> (default: the template file name)."
      }
    },
    "required": [
      "scenePath",
      "template",
      "parent",
      "start"
    ],
    "additionalProperties": false
  }
  ```
</Accordion>

**Output:** MCP text content holding JSON; errors set `isError`. From the tool's own description: Returns a compact receipt: \{count, spacing, first, last, created \[node paths], renamed, failures \[\{index, error}], saved}.

```json Example call theme={null}
{
  "name": "summer_repeat_along",
  "arguments": {
    "scenePath": "res://levels/street.tscn",
    "template": "res://kit/pipes/wall_clamp_a.tscn",
    "parent": "<parent>",
    "start": [
      "<start>"
    ]
  }
}
```

***

### summer\_replace\_node

On the local MCP (`summer-engine` npm).

Replace a node with a different scene/model or node type, keeping its parent, sibling index, name, transform and property overrides, and the children the scene added under it. Use it to swap a kit piece for another (a wall host for a door host), a placeholder for a prefab, or a StaticBody3D for a RigidBody3D.

Give exactly one of scene or type. The scenePath must be a .tscn.

PERSISTENCE IS VERIFIED: the tool saves, reads the saved .tscn back and checks that the node at path now instances the new scene (or has the new type), under the same parent, with every child present. persisted:true is proven from the file; a mismatch is an error with failure\_reason not\_persisted — never report that as done.

How: a scene swap runs as InstantiateScene (temporary name) -> SetProp each property override -> ReparentNode the children -> MoveNode to the old index -> RemoveNode the old node -> rename -> SaveScene, because the engine's own ReplaceNode keeps the OLD scene reference in the saved file. A type change of a plain node uses the engine's ReplaceNode. State that cannot travel (groups, signal connections, scene-local sub\_resource values, overrides of nodes inside the old scene) is listed in not\_carried\_over. Undo takes one Ctrl+Z per step.

| | |
| - | - |
| **Needs** | Summer Engine open with your project |
| **Effects** | writes files, changes the open project |
| **CLI** | `summer tool replace-node --args '<json>'` |

**Use when:**

* swapping a placeholder for a prefab or changing a body type
* "turn this StaticBody3D into a RigidBody3D but keep its children"
* swapping the placeholder cube for the real prefab in place
* swapping one kit piece for another (a wall host for a door host) without hand-copying its transform

**Do not use when:**

* adding alongside instead of replacing — [`summer_add_node`](/mcp/tools/build#summer_add_node) / [`summer_instantiate_scene`](/mcp/tools/build#summer_instantiate_scene)

**Inputs:**

| Input | Type | Required | Description |
| - | - | - | - |
| `scenePath` | string | Yes | Target scene path, e.g. 'res\://main.tscn' |
| `path` | string | Yes | Node path to replace, e.g. './House3/Front/G\_f2\_door' |
| `type` | string | No | New node type, e.g. 'RigidBody3D'. Give exactly one of type or scene. |
| `scene` | string | No | Scene or model to replace with, e.g. 'res\://kit/wall\_door\_02.tscn'. Give exactly one of type or scene. |

<Accordion title="Input JSON schema">
  ```json theme={null}
  {
    "type": "object",
    "properties": {
      "scenePath": {
        "type": "string",
        "description": "Target scene path, e.g. 'res://main.tscn'"
      },
      "path": {
        "type": "string",
        "description": "Node path to replace, e.g. './House3/Front/G_f2_door'"
      },
      "type": {
        "type": "string",
        "description": "New node type, e.g. 'RigidBody3D'. Give exactly one of type or scene."
      },
      "scene": {
        "type": "string",
        "description": "Scene or model to replace with, e.g. 'res://kit/wall_door_02.tscn'. Give exactly one of type or scene."
      }
    },
    "required": [
      "scenePath",
      "path"
    ],
    "additionalProperties": false
  }
  ```
</Accordion>

**Output:** MCP text content holding JSON; errors set `isError`.

```json Example call theme={null}
{
  "name": "summer_replace_node",
  "arguments": {
    "scenePath": "res://main.tscn",
    "path": "./House3/Front/G_f2_door"
  }
}
```

***

### summer\_replace\_text

On the local MCP (`summer-engine` npm).

Safely replace text in an existing project file through the identity-bound engine.

The MCP server reads the complete file, requires a unique match by default, computes the new content, and submits a sha256-guarded WriteFile. Set replace\_all:true only when every exact occurrence should change.

| | |
| - | - |
| **Needs** | Summer Engine open with your project |
| **Effects** | writes files |
| **CLI** | `summer tool replace-text --args '<json>'` |

**Use when:**

* targeted edits to scripts, scenes, or config without resending the whole file
* "change speed = 5 to speed = 8 in player.gd"
* renaming one function call in a script without rewriting the file

**Do not use when:**

* writing a new file or rewriting most of it — [`summer_write_file`](/mcp/tools/build#summer_write_file)
* the same text appears more than once and you have not narrowed the match

**Inputs:**

| Input | Type | Required | Description |
| - | - | - | - |
| `path` | string | Yes | Project path, e.g. res\://scripts/player.gd |
| `old_text` | string | Yes | Exact text to replace. Length 1 to …. |
| `new_text` | string | Yes | Replacement text; may be empty. |
| `replace_all` | boolean | No | Replace every exact occurrence instead of requiring one unique match. Default `false`. |

<Accordion title="Input JSON schema">
  ```json theme={null}
  {
    "type": "object",
    "properties": {
      "path": {
        "type": "string",
        "description": "Project path, e.g. res://scripts/player.gd"
      },
      "old_text": {
        "type": "string",
        "minLength": 1,
        "description": "Exact text to replace."
      },
      "new_text": {
        "type": "string",
        "description": "Replacement text; may be empty."
      },
      "replace_all": {
        "type": "boolean",
        "default": false,
        "description": "Replace every exact occurrence instead of requiring one unique match."
      }
    },
    "required": [
      "path",
      "old_text",
      "new_text"
    ],
    "additionalProperties": false
  }
  ```
</Accordion>

**Output:** MCP text content holding JSON; errors set `isError`.

```json Example call theme={null}
{
  "name": "summer_replace_text",
  "arguments": {
    "path": "<path>",
    "old_text": "<old_text>",
    "new_text": "<new_text>"
  }
}
```

***

### summer\_run\_editor\_script

On the local MCP (`summer-engine` npm).

Run a GDScript EditorScript in a FRESH HEADLESS editor spawned against the ON-DISK project. Cold path: a whole child editor boots, runs your script once, and exits — seconds to tens of seconds depending on the project and the script (about 2 s end to end on a small template project; large projects can spend 30 s+ just booting).

USE FOR batch/project-wide jobs that should not block the live editor: re-saving many scenes, sweeping resources, mass import fixes, generating .tres assets, long bakes. It sees ONLY what is saved on disk — unsaved live edits in the open editor are INVISIBLE to it, and the live editor won't show its output until files reload. For work on the OPEN scene, use [`summer_run_script`](/mcp/tools/build#summer_run_script) instead.

SCRIPT CONTRACT — write a plain EditorScript body:

func \_run():
var scene = load("res\://main.tscn").instantiate()
\# ... work ...
print("done")  # captured into output\[]

You may omit the '@tool' and 'extends EditorScript' lines — the engine prepends any that are missing and reports each fix in 'normalizations' (with 'line\_offset' so error line numbers map back to your source). Including 'extends EditorScript' yourself is also fine.

Returns \{ok, ran, exit\_code, output, errors, boot\_errors, result, out\_dir, checkpoint, normalizations} plus a failure\_reason taxonomy on failure (script\_parse\_failed, timeout, spawn\_failed, ...). A top-level no\_rewind\_point:true means no pre-run checkpoint exists — the run is NOT rewindable; tell the user before doing more destructive work. This headless child has NO renderer: screenshots/pixels are impossible here (see the headless-scripting skill).

| | |
| - | - |
| **Needs** | Summer Engine open with your project |
| **Effects** | writes files, changes the open project |
| **CLI** | `summer tool run-editor-script --args '<json>'` |

**Use when:**

* re-saving many scenes, sweeping resources, mass import fixes, generating .tres assets, long bakes that should not block the live editor
* "re-save every scene after the engine upgrade"
* "fix the import settings on all 200 textures"

**Do not use when:**

* work on the currently OPEN scene or anything relying on unsaved live edits — [`summer_run_script`](/mcp/tools/build#summer_run_script)
* anything needing pixels — the headless child has no renderer
* you need checkpoint/rollback or the scene-scripting ctx helpers — that is [`summer_run_script`](/mcp/tools/build#summer_run_script) (RunSceneScript, Summer Engine 0.5.66 or newer, preview); RunEditorScript itself ships in current engines

**Inputs:**

| Input | Type | Required | Description |
| - | - | - | - |
| `source` | string | Yes | EditorScript GDScript source with `func _run():`. '@tool' / 'extends EditorScript' are optional — missing lines are prepended and reported in normalizations. |
| `max_seconds` | number | No | Time budget in seconds for the child editor (default 120, clamped 15-600). Include boot time — large projects can take 30s+ just to start. |
| `checkpoint` | boolean | No | Take a SummerGit checkpoint before the child editor runs. The result confesses (no\_rewind\_point) when none could be taken. |

<Accordion title="Input JSON schema">
  ```json theme={null}
  {
    "type": "object",
    "properties": {
      "source": {
        "type": "string",
        "description": "EditorScript GDScript source with `func _run():`. '@tool' / 'extends EditorScript' are optional — missing lines are prepended and reported in normalizations."
      },
      "max_seconds": {
        "type": "number",
        "description": "Time budget in seconds for the child editor (default 120, clamped 15-600). Include boot time — large projects can take 30s+ just to start."
      },
      "checkpoint": {
        "type": "boolean",
        "description": "Take a SummerGit checkpoint before the child editor runs. The result confesses (no_rewind_point) when none could be taken."
      }
    },
    "required": [
      "source"
    ],
    "additionalProperties": false
  }
  ```
</Accordion>

**Output:** MCP text content holding JSON; errors set `isError`. From the tool's own description: Returns \{ok, ran, exit\_code, output, errors, boot\_errors, result, out\_dir, checkpoint, normalizations} plus a failure\_reason taxonomy on failure (script\_parse\_failed, timeout, spawn\_failed, ...).

```json Example call theme={null}
{
  "name": "summer_run_editor_script",
  "arguments": {
    "source": "<source>"
  }
}
```

***

### summer\_run\_script

On the local MCP (`summer-engine` npm).

Run a GDScript snippet INSIDE the live editor, against the currently OPEN scene. This is the scene-scripting workhorse: one script replaces long chains of add-node/set-prop calls, and it can compute (loops, randomness, math, procedural meshes) what individual CRUD ops cannot.

SCRIPT CONTRACT — write ONLY the body below; do not add extends/@tool lines (missing ones are prepended and reported in 'normalizations'):

func run(ctx):
var root = ctx.get\_scene\_root()    # root node of the open scene
for i in range(10):
var m := MeshInstance3D.new()
m.mesh = BoxMesh.new()
m.position = Vector3(i \* 2, 0, 0)
root.add\_child(m)
ctx.set\_owner\_recursive(m)     # REQUIRED or the node is NOT saved
ctx.report("count", 10)            # structured value back to you

* ctx.get\_scene\_root() — the open scene's root node. Full editor API access.
* ctx.set\_owner\_recursive(node) — stamps node AND its descendants with the scene-root owner (equivalent to node.owner = root on each). Call it after add\_child on every created subtree.
* ctx.report(key, value) — return structured results (comes back in 'reports').
* print(...) — captured and returned in 'output'.
* OWNERSHIP: a created node whose owner is never set silently vanishes when the scene saves — descendants too. ctx.set\_owner\_recursive covers both.
* Values here are real GDScript — Vector3(0,10,0), Color(1,0,0,1) — NOT the quoted variant strings used by [`summer_set_prop`](/mcp/tools/build#summer_set_prop).

Newer ctx builds also carry creation helpers that set the owner FOR you and return the node — prefer them: ctx.add\_node(type, name, parent, props), ctx.find(name), ctx.get\_or\_create(type, name, parent), ctx.instance\_scene(res\_path, parent, name), ctx.add\_mesh(shape, name, parent, props) / ctx.add\_mesh\_with\_collision(...), ctx.mesh\_from\_arrays(...), ctx.make\_material(props) / ctx.apply\_material(node, material), ctx.grid(count\_x, count\_z, spacing, maker) / ctx.scatter(area, count, maker, seed), ctx.add\_light\_rig(target), ctx.ensure\_environment(props), ctx.add\_camera(position, look\_at, make\_current), ctx.summary(), ctx.save\_scene(path). Unknown props keys are reported in 'prop\_warnings', never silently dropped. On an older engine a missing helper is a plain GDScript error — fall back to the manual form above.

WHEN TO USE: 3+ related ops, anything with computed placement (scatter, grids, rings), procedural geometry (SurfaceTool/ArrayMesh), bulk renames/retunes. For a single property tweak, [`summer_set_prop`](/mcp/tools/build#summer_set_prop) is cheaper. Use [`summer_api_docs`](/mcp/tools/build#summer_api_docs) to verify property/method names instead of guessing.

THE LOOP: [`summer_world_snapshot`](/mcp/tools/run-and-test#summer_world_snapshot) (keep snapshot\_id) -> [`summer_run_script`](/mcp/tools/build#summer_run_script) -> [`summer_snapshot_diff`](/mcp/tools/run-and-test#summer_snapshot_diff) + [`summer_screenshot`](/mcp/tools/run-and-test#summer_screenshot) -> inspect -> iterate. Never claim visual success without the screenshot.

Returns \{ok, ran, result, reports, output, errors, duration\_ms, checkpoint} — newer engines add rolled\_back (a runtime error rolled the whole undo action back; the scene is untouched) and budget\_enforced (max\_seconds was a HARD deadline; when the budget hits, the script errors with "Summer script budget exceeded" — split the work into smaller scripts, never resubmit the same oversized one). Read 'errors' even when ok — with undo:'none', a partially-failed script may have mutated the scene. If this engine build predates RunSceneScript, the result is a structured engine\_lacks\_op failure (nothing is sent): use [`summer_run_editor_script`](/mcp/tools/build#summer_run_editor_script) or update Summer Engine.

| | |
| - | - |
| **Needs** | Summer Engine open with your project |
| **Effects** | writes files, changes the open project |
| **CLI** | `summer tool run-script --args '<json>'` |

**Use when:**

* a change needs 3+ related ops or any computed placement (scatter, grids, procedural meshes, bulk edits)
* the ctx helpers (add\_node, add\_mesh, grid, scatter, light rig, environment) fit the job

**Do not use when:**

* a single property tweak — [`summer_set_prop`](/mcp/tools/build#summer_set_prop) is cheaper
* a cold project-wide batch job that should not block the live editor — [`summer_run_editor_script`](/mcp/tools/build#summer_run_editor_script)
* requires an engine build with RunSceneScript (Summer Engine 0.5.66 or newer); older engines return engine\_lacks\_op

**Inputs:**

| Input | Type | Required | Description |
| - | - | - | - |
| `source` | string | Yes | GDScript source containing `func run(ctx):`. No extends/@tool line — just the function (plus any helpers). |
| `max_seconds` | number | No | Time budget in seconds (default 20, clamped 5-120). The script blocks the editor while it runs — keep it short. |
| `checkpoint` | boolean | No | Take a SummerGit checkpoint before running (default true). The result confesses (no\_rewind\_point) when no checkpoint could be taken. |
| `undo` | "action" \| "none" | No | Transaction mode (newer engines). 'action' (engine default): the whole run is ONE named undo action, and a mid-script runtime error rolls it back before returning (result rolled\_back:true) — no half-mutated scene. 'none': v1 behavior, checkpoint only. Older engines ignore this. |

<Accordion title="Input JSON schema">
  ```json theme={null}
  {
    "type": "object",
    "properties": {
      "source": {
        "type": "string",
        "description": "GDScript source containing `func run(ctx):`. No extends/@tool line — just the function (plus any helpers)."
      },
      "max_seconds": {
        "type": "number",
        "description": "Time budget in seconds (default 20, clamped 5-120). The script blocks the editor while it runs — keep it short."
      },
      "checkpoint": {
        "type": "boolean",
        "description": "Take a SummerGit checkpoint before running (default true). The result confesses (no_rewind_point) when no checkpoint could be taken."
      },
      "undo": {
        "type": "string",
        "enum": [
          "action",
          "none"
        ],
        "description": "Transaction mode (newer engines). 'action' (engine default): the whole run is ONE named undo action, and a mid-script runtime error rolls it back before returning (result rolled_back:true) — no half-mutated scene. 'none': v1 behavior, checkpoint only. Older engines ignore this."
      }
    },
    "required": [
      "source"
    ],
    "additionalProperties": false
  }
  ```
</Accordion>

**Output:** MCP text content holding JSON; errors set `isError`. From the tool's own description: Returns \{ok, ran, result, reports, output, errors, duration\_ms, checkpoint} — newer engines add rolled\_back (a runtime error rolled the whole undo action back; the scene is untouched) and budget\_enforced (max\_seconds was a HARD deadline; when the budget hits, the script errors with "Summer script budget exceeded" — split the work into smaller scripts, never resubmit the same oversized one).

```json Example call theme={null}
{
  "name": "summer_run_script",
  "arguments": {
    "source": "<source>"
  }
}
```

***

### summer\_save\_scene

On the local MCP (`summer-engine` npm).

Save an explicit scene to disk. Mutation tools already append one save; use this for a standalone save or save-as.

| | |
| - | - |
| **Needs** | Summer Engine open with your project |
| **Effects** | writes files, changes the open project |
| **CLI** | `summer tool save-scene --args '<json>'` |

**Use when:**

* a standalone save or save-as is needed
* "save a copy of this scene as level1\_backup.tscn"
* the user explicitly asks to save

**Do not use when:**

* after ordinary mutation tools, which already append one save

**Inputs:**

| Input | Type | Required | Description |
| - | - | - | - |
| `scenePath` | string | Yes | Scene to save, e.g. 'res\://main.tscn' |
| `path` | string | No | Optional save-as path, e.g. 'res\://levels/level2.tscn' |

<Accordion title="Input JSON schema">
  ```json theme={null}
  {
    "type": "object",
    "properties": {
      "scenePath": {
        "type": "string",
        "description": "Scene to save, e.g. 'res://main.tscn'"
      },
      "path": {
        "type": "string",
        "description": "Optional save-as path, e.g. 'res://levels/level2.tscn'"
      }
    },
    "required": [
      "scenePath"
    ],
    "additionalProperties": false
  }
  ```
</Accordion>

**Output:** MCP text content holding JSON; errors set `isError`.

```json Example call theme={null}
{
  "name": "summer_save_scene",
  "arguments": {
    "scenePath": "res://main.tscn"
  }
}
```

***

### summer\_search\_library

On the local MCP (`summer-engine` npm).

Search the Summer library — skills, tools, templates, references, examples, collections — by describing the task in plain words ('make stylized water', 'the player falls through the floor', 'which tool reads script errors'). This is the FIRST MOVE for any task: even a 1% chance the library covers it means you search, then read the entry you pick with [`summer_read_library`](/mcp/tools/build#summer_read_library) before acting — never act on a summary alone. Ranking: BM25 over ids, summaries, use\_when lines and facets with kind-aware priors and related-entry boosts (the same ranker the routing eval gates). When this install ships registry/generated/embeddings.json and the embedding endpoint answers within 1.5s, lexical and semantic rankings are fused (reciprocal rank fusion) and each hit's matched\_by says which side found it; offline or without embeddings it is lexical only and never fails for that reason. Returns \{query, semantic, count, results: \[\{id, kind, status, summary, use\_when, score, matched\_by, mcp\_tool\_name?}], hint}. Scores compare only within one response. kinds narrows to some of the six kinds; include\_preview:false hides preview entries; deprecated entries never surface. No engine needed. Privacy: only when semantic search is active is the query text sent to the Summer gateway to be embedded; nothing else leaves the machine.

| | |
| - | - |
| **Needs** | No open editor and no sign-in. Uses your `summer login` sign-in when you have one |
| **Effects** | uses the network |
| **CLI** | `summer tool search-library --args '<json>'` |

**Use when:**

* the first move for any task, before building anything — find the entry that covers what the user asked
* not sure which entry (skill, tool, template, reference) applies to the task at hand
* narrowing the library to one kind with the kinds filter, or hiding preview entries

**Do not use when:**

* you already hold an exact id — load it with [`summer_read_library`](/mcp/tools/build#summer_read_library)
* looking for assets (models, textures, sounds) — [`summer_search_assets`](/mcp/tools/create-assets#summer_search_assets) searches the asset library, not the knowledge library
* looking up an engine class, property, or method name — [`summer_api_docs`](/mcp/tools/build#summer_api_docs)

**Inputs:**

| Input | Type | Required | Description |
| - | - | - | - |
| `query` | string | Yes | The task in plain words — what you are building, fixing, or looking for (e.g. 'make stylized water', 'the player falls through the floor', 'which tool reads script errors'). Length 1 to 300. |
| `kinds` | "tool" \| "skill" \| "example" \| "template" \| "collection" \| "reference"\[] | No | Restrict to these kinds (tool, skill, example, template, collection, reference). Omit for all kinds. |
| `limit` | integer | No | Maximum results, 1-20 (default 8). Range 1 to 20. |
| `include_preview` | boolean | No | Include status: preview entries — not yet exercised in-engine by the Summer team (default true). false = stable only. |

<Accordion title="Input JSON schema">
  ```json theme={null}
  {
    "type": "object",
    "properties": {
      "query": {
        "type": "string",
        "minLength": 1,
        "maxLength": 300,
        "description": "The task in plain words — what you are building, fixing, or looking for (e.g. 'make stylized water', 'the player falls through the floor', 'which tool reads script errors')."
      },
      "kinds": {
        "type": "array",
        "items": {
          "type": "string",
          "enum": [
            "tool",
            "skill",
            "example",
            "template",
            "collection",
            "reference"
          ]
        },
        "description": "Restrict to these kinds (tool, skill, example, template, collection, reference). Omit for all kinds."
      },
      "limit": {
        "type": "integer",
        "minimum": 1,
        "maximum": 20,
        "description": "Maximum results, 1-20 (default 8)."
      },
      "include_preview": {
        "type": "boolean",
        "description": "Include status: preview entries — not yet exercised in-engine by the Summer team (default true). false = stable only."
      }
    },
    "required": [
      "query"
    ],
    "additionalProperties": false
  }
  ```
</Accordion>

**Output:** MCP text content holding JSON; errors set `isError`. From the tool's own description: Returns \{query, semantic, count, results: \[\{id, kind, status, summary, use\_when, score, matched\_by, mcp\_tool\_name?}], hint}.

```json Example call theme={null}
{
  "name": "summer_search_library",
  "arguments": {
    "query": "make stylized water"
  }
}
```

***

### summer\_select\_node

On the local MCP (`summer-engine` npm).

Select a node in the editor's scene tree and show it in the inspector panel. Useful for focusing the editor on a specific node.

| | |
| - | - |
| **Needs** | Summer Engine open with your project |
| **Effects** | changes the open project |
| **CLI** | `summer tool select-node --args '<json>'` |

**Use when:**

* focusing the user's editor on a specific node
* highlighting the player in the scene tree so the user can see it
* showing the user the node whose properties are about to change

**Do not use when:**

* reading properties — [`summer_inspect_node`](/mcp/tools/build#summer_inspect_node); selection changes nothing

**Inputs:**

| Input | Type | Required | Description |
| - | - | - | - |
| `nodePath` | string | Yes | Node path to select |
| `scenePath` | string | No | Open this scene first, then select the node |

<Accordion title="Input JSON schema">
  ```json theme={null}
  {
    "type": "object",
    "properties": {
      "nodePath": {
        "type": "string",
        "description": "Node path to select"
      },
      "scenePath": {
        "type": "string",
        "description": "Open this scene first, then select the node"
      }
    },
    "required": [
      "nodePath"
    ],
    "additionalProperties": false
  }
  ```
</Accordion>

**Output:** MCP text content holding JSON; errors set `isError`.

```json Example call theme={null}
{
  "name": "summer_select_node",
  "arguments": {
    "nodePath": "<nodePath>"
  }
}
```

***

### summer\_set\_prop

On the local MCP (`summer-engine` npm).

Set a property on a node. This is the primary way to configure nodes after adding them.

VALUE FORMAT — Godot string syntax for complex types:

* Vector3: "Vector3(0, 10, 0)" — position, scale, rotation\_degrees
* Vector2: "Vector2(100, 200)" — 2D position, size
* Color: "Color(1, 0.5, 0, 1)" — RGBA, always 4 components, values 0.0-1.0
* Transform3D: "Transform3D(1,0,0, 0,1,0, 0,0,1, 0,5,0)" — basis + origin
* Resource class name: "BoxMesh", "SphereMesh", "StandardMaterial3D" — auto-instantiated
* Numbers: 1.5, 42 — native JSON
* Booleans: true, false — native JSON
* Strings: "hello" — native JSON

COMMON PROPERTIES:

* position: "Vector3(x, y, z)" — world position
* rotation\_degrees: "Vector3(rx, ry, rz)" — rotation in degrees
* scale: "Vector3(sx, sy, sz)" — scale factor
* visible: true/false — visibility
* mesh: "BoxMesh", "SphereMesh", "CapsuleMesh", "CylinderMesh", "PlaneMesh"
* shadow\_enabled: true — for lights
* light\_energy: 1.5 — light intensity
* fov: 75.0 — camera field of view

| | |
| - | - |
| **Needs** | Summer Engine open with your project |
| **Effects** | writes files, changes the open project |
| **CLI** | `summer tool set-prop --args '<json>'` |

**Use when:**

* configuring nodes after adding them
* "move the light up" / "put the player at the spawn point" / "make the sprite red" / "rotate the camera 45 degrees"
* setting one node's position, rotation, scale, colour, speed, collision layer, or visible flag

**Do not use when:**

* a property that lives on a mesh, material, or shape resource — [`summer_set_resource_property`](/mcp/tools/build#summer_set_resource_property)
* project-wide settings — [`summer_project_setting`](/mcp/tools/build#summer_project_setting)
* many nodes or computed values — [`summer_run_script`](/mcp/tools/build#summer_run_script)

**Inputs:**

| Input | Type | Required | Description |
| - | - | - | - |
| `scenePath` | string | Yes | Target scene path, e.g. 'res\://main.tscn' |
| `path` | string | Yes | Node path, e.g. './World/Player' |
| `key` | string | Yes | Property name, e.g. 'position', 'mesh', 'visible' |
| `value` | string \| number \| boolean | Yes | Value in Summer Engine variant-string format for complex types, native JSON for primitives |

<Accordion title="Input JSON schema">
  ```json theme={null}
  {
    "type": "object",
    "properties": {
      "scenePath": {
        "type": "string",
        "description": "Target scene path, e.g. 'res://main.tscn'"
      },
      "path": {
        "type": "string",
        "description": "Node path, e.g. './World/Player'"
      },
      "key": {
        "type": "string",
        "description": "Property name, e.g. 'position', 'mesh', 'visible'"
      },
      "value": {
        "type": [
          "string",
          "number",
          "boolean"
        ],
        "description": "Value in Summer Engine variant-string format for complex types, native JSON for primitives"
      }
    },
    "required": [
      "scenePath",
      "path",
      "key",
      "value"
    ],
    "additionalProperties": false
  }
  ```
</Accordion>

**Output:** MCP text content holding JSON; errors set `isError`.

```json Example call theme={null}
{
  "name": "summer_set_prop",
  "arguments": {
    "scenePath": "res://main.tscn",
    "path": "./World/Player",
    "key": "position",
    "value": "<value>"
  }
}
```

***

### summer\_set\_resource\_property

On the local MCP (`summer-engine` npm).

Set a nested property on a resource attached to a node.

Use when you need to modify a sub-property of a resource, like:

* CollisionShape3D shape size: nodePath="./Player/CollisionShape3D", resourceProperty="shape", subProperty="size", value="Vector3(1, 2, 1)"
* Material albedo color: nodePath="./Floor", resourceProperty="material\_override", subProperty="albedo\_color", value="Color(0.2, 0.5, 0.2, 1)"
* Mesh size: nodePath="./Box", resourceProperty="mesh", subProperty="size", value="Vector3(2, 2, 2)"

| | |
| - | - |
| **Needs** | Summer Engine open with your project |
| **Effects** | writes files, changes the open project |
| **CLI** | `summer tool set-resource-property --args '<json>'` |

**Use when:**

* modifying sub-properties of meshes, materials, or shapes
* "make the box mesh 2 metres wide" / "change the capsule radius"
* setting the material albedo colour or roughness on a mesh

**Do not use when:**

* the property is on the node itself (position, visible, scale) — [`summer_set_prop`](/mcp/tools/build#summer_set_prop)

**Inputs:**

| Input | Type | Required | Description |
| - | - | - | - |
| `scenePath` | string | Yes | Target scene path, e.g. 'res\://main.tscn' |
| `nodePath` | string | Yes | Node path, e.g. './Player/CollisionShape3D' |
| `resourceProperty` | string | Yes | Resource property on the node, e.g. 'shape', 'mesh', 'material\_override' |
| `subProperty` | string | Yes | Property on the resource, e.g. 'size', 'radius', 'albedo\_color' |
| `value` | string \| number \| boolean | Yes | Value in Summer Engine variant-string format |

<Accordion title="Input JSON schema">
  ```json theme={null}
  {
    "type": "object",
    "properties": {
      "scenePath": {
        "type": "string",
        "description": "Target scene path, e.g. 'res://main.tscn'"
      },
      "nodePath": {
        "type": "string",
        "description": "Node path, e.g. './Player/CollisionShape3D'"
      },
      "resourceProperty": {
        "type": "string",
        "description": "Resource property on the node, e.g. 'shape', 'mesh', 'material_override'"
      },
      "subProperty": {
        "type": "string",
        "description": "Property on the resource, e.g. 'size', 'radius', 'albedo_color'"
      },
      "value": {
        "type": [
          "string",
          "number",
          "boolean"
        ],
        "description": "Value in Summer Engine variant-string format"
      }
    },
    "required": [
      "scenePath",
      "nodePath",
      "resourceProperty",
      "subProperty",
      "value"
    ],
    "additionalProperties": false
  }
  ```
</Accordion>

**Output:** MCP text content holding JSON; errors set `isError`.

```json Example call theme={null}
{
  "name": "summer_set_resource_property",
  "arguments": {
    "scenePath": "res://main.tscn",
    "nodePath": "./Player/CollisionShape3D",
    "resourceProperty": "shape",
    "subProperty": "size",
    "value": "<value>"
  }
}
```

***

### summer\_snap\_to\_surface

On the local MCP (`summer-engine` npm).

Move one exact 3D subject along a world-space ray until its support face sits at the requested gap from the first surface. This changes only the subject's global transform, saves the scene, and is one reversible editor undo.

Use the default downward direction to seat props on floors, ramps, tables, or shelves. Set alignUp only when the prop should tilt to match the support normal.

EVIDENCE BOUNDARY:

* physics means Godot swept the subject's enabled collider shapes against body colliders and refined the first-contact bracket.
* visual\_aabb is the engine's broad-phase fallback for mesh-only geometry (no collider on the subject or the support): AABBs swept against AABBs. It does not prove triangle contact, and alignUp is not applied from that approximate normal.
* visual\_mesh: whenever the engine answers with visual\_aabb (overlap\_recovery\_exceeded, gap\_exceeds\_hit\_travel, surface\_not\_found, or a seat), a read-only probe measures the move from visible triangles instead: the subject's vertices cast along the direction onto the triangles of the meshes below (a surface cutting through the subject counts as sunk), plus the support's vertices under it cast back. One SetProp places the subject, a second read verifies the gap (the move is undone if it disagrees by more than 5 mm), and the scene is saved. The receipt says evidence visual\_mesh, the engine's own answer under engine, verify \{final\_gap, ok}, and evidenceDetails (samples, triangles, whether the subject and the support have colliders). Meshes whose shader writes POSITION (screen-space quads) are not surfaces. When the triangles find no support either, the engine's failure is returned with mesh\_fallback saying why.
* initiallyOverlapping and backoffDistance expose bounded pre-sweep recovery. The tool fails instead of teleporting when the subject cannot be cleared within maxDistance.

SUNK PROPS: when the subject starts inside its support (gap\_exceeds\_hit\_travel with a start overlap), the tool lifts it against the cast direction by the overlap depth plus 0.02 m (at most 0.5 m and the subject's own extent), snaps again from there, and keeps that only if it settles on a node it was sunk into; the receipt then carries recovery (lifted\_by, original\_local\_position) and 'before' is the lifted pose. Otherwise the original position is restored.

FAILURES EXPLAIN THEMSELVES: after gap\_exceeds\_hit\_travel or overlap\_recovery\_exceeded a read-only starcast at the current pose adds start\_overlap, blocking (the nodes it touches or sits inside), below, and a concrete next\_step.

The normal result is bounded below 5 KB and returns before/after transforms, supportPath, finalGap with an error bound, slopeDeg, evidence, and warnings. scenePath and subjectPath are always required; there is no editor-selection fallback. On an engine build that predates SnapToSurface the result is a structured engine\_lacks\_op failure naming the fallback.

| | |
| - | - |
| **Needs** | Summer Engine open with your project |
| **Effects** | writes files, changes the open project |
| **CLI** | `summer tool snap-to-surface --args '<json>'` |

**Use when:**

* seating a prop on a floor, ramp, table, or shelf instead of hand-tuning its Y position
* grounding an imported or instantiated model that floats or sinks into its support
* lifting a prop that is sunk a few centimetres into the ground back onto it
* seating a prop without a collider (a fern, a bottle) on a PlaneMesh or other mesh-only ground

**Do not use when:**

* you only want to know whether a pose fits — [`summer_test_placement`](/mcp/tools/build#summer_test_placement) is read-only
* arranging several objects relative to each other — [`summer_align_distribute_3d`](/mcp/tools/build#summer_align_distribute_3d)

**Inputs:**

| Input | Type | Required | Description |
| - | - | - | - |
| `scenePath` | string | Yes | Exact scene containing the subject, e.g. 'res\://levels/market.tscn' Length 1 to 512. |
| `subjectPath` | string | Yes | Exact Node3D path relative to the scene root, e.g. './Props/Crate' Length 1 to 256. |
| `direction` | any\[] | No | Finite world-space cast direction \[x,y,z] whose squared length exceeds 0.00001. Defaults downward. Default `[0,-1,0]`. Items 3 to 3. |
| `maxDistance` | number | No | Maximum cast and overlap-recovery distance in scene units. Default `20`. Range … to 10000. |
| `gap` | number | No | Requested separation from the support surface; must not exceed maxDistance. Default `0`. Range 0 to 10000. |
| `alignUp` | boolean | No | Rotate the subject's current world up toward an exact physics contact normal before seating it. Default `false`. |

<Accordion title="Input JSON schema">
  ```json theme={null}
  {
    "type": "object",
    "properties": {
      "scenePath": {
        "type": "string",
        "minLength": 1,
        "maxLength": 512,
        "description": "Exact scene containing the subject, e.g. 'res://levels/market.tscn'"
      },
      "subjectPath": {
        "type": "string",
        "minLength": 1,
        "maxLength": 256,
        "description": "Exact Node3D path relative to the scene root, e.g. './Props/Crate'"
      },
      "direction": {
        "type": "array",
        "minItems": 3,
        "maxItems": 3,
        "items": [
          {
            "type": "number"
          },
          {
            "type": "number"
          },
          {
            "type": "number"
          }
        ],
        "default": [
          0,
          -1,
          0
        ],
        "description": "Finite world-space cast direction [x,y,z] whose squared length exceeds 0.00001. Defaults downward."
      },
      "maxDistance": {
        "type": "number",
        "exclusiveMinimum": 0,
        "maximum": 10000,
        "default": 20,
        "description": "Maximum cast and overlap-recovery distance in scene units."
      },
      "gap": {
        "type": "number",
        "minimum": 0,
        "maximum": 10000,
        "default": 0,
        "description": "Requested separation from the support surface; must not exceed maxDistance."
      },
      "alignUp": {
        "type": "boolean",
        "default": false,
        "description": "Rotate the subject's current world up toward an exact physics contact normal before seating it."
      }
    },
    "required": [
      "scenePath",
      "subjectPath"
    ],
    "additionalProperties": false
  }
  ```
</Accordion>

**Output:** MCP text content holding JSON; errors set `isError`.

```json Example call theme={null}
{
  "name": "summer_snap_to_surface",
  "arguments": {
    "scenePath": "res://levels/market.tscn",
    "subjectPath": "./Props/Crate"
  }
}
```

***

### summer\_starcast

On the local MCP (`summer-engine` npm).

Read a 3D spatial rundown for one exact node in an exact scene without moving it or saving the scene: 26 directional clearance casts (6 axes, 12 edges, 8 corners) from the subject's bounds, contact-or-overlap evidence, grounded state, and, in full detail, bounded nearby-object lists. Use it before and after placing an object to learn which side is blocked, by what, and at what distance.

detail 'summary' (default) is a placement report of at most 5 KB: subject position and size, grounded and contactStatus, deduplicated contact paths, one compact record per direction (status open|blocked, nearest distance, object, evidence, relationship), coverage, and warnings. detail 'full' adds per-direction hit geometry, an objects table, nearby lists, and the query echo, at most 12 KB; the engine downgrades to summary rather than exceed that (warning full\_result\_exceeded\_12kb\_returned\_summary) and always reports requestedDetail vs returnedDetail.

EVIDENCE BOUNDARY:

* evidence 'physics' uses Godot's PhysicsDirectSpaceState3D against exact collider geometry on collisionMask. Shape intersections say contact\_or\_overlap because the query does not establish penetration depth; touching and anything within margin are included.
* evidence 'visual\_aabb' uses visible world-axis-aligned bounding boxes: it catches meshes without colliders but is broad-phase only, never triangle-level contact.
* Lights, cameras, audio, navigation, scripts, and plain Nodes are not obstacles unless they own visual or collision geometry. One representative ray per direction can miss off-center geometry.

scenePath and path are exact; editor selection is never consulted. This tool is read-only: it never moves the node or saves the scene. On an engine build that predates Starcast3D the result is a structured engine\_lacks\_op failure naming the fallback.

| | |
| - | - |
| **Needs** | Summer Engine open with your project |
| **Effects** | read-only |
| **CLI** | `summer tool starcast --args '<json>'` |

**Use when:**

* learning what surrounds a placed prop before and after a correction — which direction is blocked, by what, and at what distance
* diagnosing an overlap or a floating object when [`summer_test_placement`](/mcp/tools/build#summer_test_placement) reports fits false or grounded false and you need to know which side to move
* checking wall gaps, shelf support, or alcove clearance for a rotated subject (directionSpace local)

**Do not use when:**

* you want the engine to move the prop for you — [`summer_snap_to_surface`](/mcp/tools/build#summer_snap_to_surface) or [`summer_align_distribute_3d`](/mcp/tools/build#summer_align_distribute_3d)
* you only need a yes/no on one candidate pose — [`summer_test_placement`](/mcp/tools/build#summer_test_placement) is cheaper
* the subject is 2D or has neither visual nor collision geometry
* requires an engine build with Starcast3D (Summer Engine 0.5.66 or newer); older engines return engine\_lacks\_op

**Inputs:**

| Input | Type | Required | Description |
| - | - | - | - |
| `scenePath` | string | Yes | Exact scene containing the subject, e.g. 'res\://levels/level1.tscn'. Length 1 to 512. |
| `path` | string | Yes | Exact Node3D path relative to the scene root, e.g. './World/Crate'. Length 1 to 256. |
| `detail` | "summary" \| "full" | No | summary: compact placement report (at most 5 KB). full: adds bounded hit geometry, an objects table, and nearby lists (at most 12 KB; the engine downgrades to summary rather than exceed it). Default `"summary"`. |
| `maxDistance` | number | No | Maximum outward cast distance in scene units. Default `20`. Range … to 10000. |
| `nearbyRadius` | number | No | Maximum gap from the subject bounds for the nearby-object lists (full detail). Default `10`. Range 0 to 10000. |
| `directionSpace` | "world" \| "local" | No | Cast along world axes, or along the subject's orthonormalized local axes when 'front', 'side', or 'up' mean the rotated subject's own orientation. Default `"world"`. |
| `collisionMask` | integer | No | Godot 3D physics layer mask queried by rays, shape contacts/overlaps, and nearby-collider scans. Default `4294967295`. Range 0 to 4294967295. |
| `collideWithAreas` | boolean | No | Include Area3D objects as well as physics bodies. Default `true`. |
| `maxHitsPerDirection` | integer | No | Maximum physics hits and visual AABB hits retained for each direction. Default `3`. Range 1 to 8. |
| `maxResults` | integer | No | Maximum retained contact/overlap and nearby entries per evidence channel. Default `64`. Range 1 to 128. |
| `margin` | number | No | Tolerance for exact-geometry physics shape intersection queries; touching and candidates within this margin are reported as contact\_or\_overlap. Default `0.001`. Range 0 to 1. |

<Accordion title="Input JSON schema">
  ```json theme={null}
  {
    "type": "object",
    "properties": {
      "scenePath": {
        "type": "string",
        "minLength": 1,
        "maxLength": 512,
        "description": "Exact scene containing the subject, e.g. 'res://levels/level1.tscn'."
      },
      "path": {
        "type": "string",
        "minLength": 1,
        "maxLength": 256,
        "description": "Exact Node3D path relative to the scene root, e.g. './World/Crate'."
      },
      "detail": {
        "type": "string",
        "enum": [
          "summary",
          "full"
        ],
        "default": "summary",
        "description": "summary: compact placement report (at most 5 KB). full: adds bounded hit geometry, an objects table, and nearby lists (at most 12 KB; the engine downgrades to summary rather than exceed it)."
      },
      "maxDistance": {
        "type": "number",
        "exclusiveMinimum": 0,
        "maximum": 10000,
        "default": 20,
        "description": "Maximum outward cast distance in scene units."
      },
      "nearbyRadius": {
        "type": "number",
        "minimum": 0,
        "maximum": 10000,
        "default": 10,
        "description": "Maximum gap from the subject bounds for the nearby-object lists (full detail)."
      },
      "directionSpace": {
        "type": "string",
        "enum": [
          "world",
          "local"
        ],
        "default": "world",
        "description": "Cast along world axes, or along the subject's orthonormalized local axes when 'front', 'side', or 'up' mean the rotated subject's own orientation."
      },
      "collisionMask": {
        "type": "integer",
        "minimum": 0,
        "maximum": 4294967295,
        "default": 4294967295,
        "description": "Godot 3D physics layer mask queried by rays, shape contacts/overlaps, and nearby-collider scans."
      },
      "collideWithAreas": {
        "type": "boolean",
        "default": true,
        "description": "Include Area3D objects as well as physics bodies."
      },
      "maxHitsPerDirection": {
        "type": "integer",
        "minimum": 1,
        "maximum": 8,
        "default": 3,
        "description": "Maximum physics hits and visual AABB hits retained for each direction."
      },
      "maxResults": {
        "type": "integer",
        "minimum": 1,
        "maximum": 128,
        "default": 64,
        "description": "Maximum retained contact/overlap and nearby entries per evidence channel."
      },
      "margin": {
        "type": "number",
        "minimum": 0,
        "maximum": 1,
        "default": 0.001,
        "description": "Tolerance for exact-geometry physics shape intersection queries; touching and candidates within this margin are reported as contact_or_overlap."
      }
    },
    "required": [
      "scenePath",
      "path"
    ],
    "additionalProperties": false
  }
  ```
</Accordion>

**Output:** MCP text content holding JSON; errors set `isError`.

```json Example call theme={null}
{
  "name": "summer_starcast",
  "arguments": {
    "scenePath": "res://levels/level1.tscn",
    "path": "./World/Crate"
  }
}
```

***

### summer\_start\_game\_task

On the local MCP (`summer-engine` npm).

Start here for any substantial AI game-building task.

Takes the user's goal and returns the recommended Summer workflow: skill routes,
MCP tool groups, host-file boundaries, asset policy, user confirmation gates,
and verification steps. This is the router before deep skills and before
mutating the project.

| | |
| - | - |
| **Needs** | No open editor and no sign-in |
| **Effects** | read-only |
| **CLI** | `summer plan` |

**Use when:**

* starting any substantial AI game-building task, before mutating the project
* the user asks for a whole feature (inventory, boss fight, day-night cycle) and the path is not obvious
* choosing which skills and confirmation gates apply before touching the project

**Do not use when:**

* a one-step edit (one property, one node) — call the tool directly

**Inputs:**

| Input | Type | Required | Description |
| - | - | - | - |
| `goal` | string | Yes | The user's game-building goal or task. |
| `mode` | "auto" \| "new-game" \| "feature" \| "asset" \| "debug" \| "playtest" \| "polish" \| "ship" | No | Optional task mode override. Default `"auto"`. |
| `target` | "auto" \| "2d" \| "3d" \| "ui" \| "audio" \| "animation" \| "level" \| "npc" \| "multiplayer" | No | Optional content/system target override. Default `"auto"`. |
| `assetPolicy` | "reuse-first" \| "ask-before-paid-generation" \| "no-paid-generation" \| "generate-when-clearly-needed" | No | How aggressively to use paid asset generation. Default `"ask-before-paid-generation"`. |
| `verification` | "none" \| "fast" \| "full" | No | How much engine verification the agent should plan for. Default `"full"`. |

<Accordion title="Input JSON schema">
  ```json theme={null}
  {
    "type": "object",
    "properties": {
      "goal": {
        "type": "string",
        "description": "The user's game-building goal or task."
      },
      "mode": {
        "type": "string",
        "enum": [
          "auto",
          "new-game",
          "feature",
          "asset",
          "debug",
          "playtest",
          "polish",
          "ship"
        ],
        "default": "auto",
        "description": "Optional task mode override."
      },
      "target": {
        "type": "string",
        "enum": [
          "auto",
          "2d",
          "3d",
          "ui",
          "audio",
          "animation",
          "level",
          "npc",
          "multiplayer"
        ],
        "default": "auto",
        "description": "Optional content/system target override."
      },
      "assetPolicy": {
        "type": "string",
        "enum": [
          "reuse-first",
          "ask-before-paid-generation",
          "no-paid-generation",
          "generate-when-clearly-needed"
        ],
        "default": "ask-before-paid-generation",
        "description": "How aggressively to use paid asset generation."
      },
      "verification": {
        "type": "string",
        "enum": [
          "none",
          "fast",
          "full"
        ],
        "default": "full",
        "description": "How much engine verification the agent should plan for."
      }
    },
    "required": [
      "goal"
    ],
    "additionalProperties": false
  }
  ```
</Accordion>

**Output:** MCP text content holding JSON; errors set `isError`.

```json Example call theme={null}
{
  "name": "summer_start_game_task",
  "arguments": {
    "goal": "<goal>"
  }
}
```

***

### summer\_studio\_map

On the hosted MCP.

The map of Summer Studio: every page (destination id, title, what it is for, path) and the product guide the Studio assistant answers from. No open tab needed. Use a destination id with [`summer_studio_open`](/mcp/tools/build#summer_studio_open).

| | |
| - | - |
| **Needs** | Your Summer account (OAuth). In the npm MCP: `summer login --store` |
| **Hints** | `readOnlyHint` |

**Inputs:**

| Input | Type | Required | Description |
| - | - | - | - |
| `guide` | boolean | No | Also return the full product guide text. Default `false`. |

<Accordion title="Input JSON schema">
  ```json theme={null}
  {
    "type": "object",
    "properties": {
      "guide": {
        "description": "Also return the full product guide text.",
        "default": false,
        "type": "boolean"
      }
    }
  }
  ```
</Accordion>

**Output:** MCP text content holding JSON; errors set `isError`.

```json Example call theme={null}
{
  "name": "summer_studio_map",
  "arguments": {}
}
```

***

### summer\_studio\_open

On the hosted MCP.

Move the person's open Summer Studio tab to a Studio page (a destination id from [`summer_studio_map`](/mcp/tools/build#summer_studio_map), or a /studio or /create path). Returns the page's fields and buttons once it has loaded. The person sees a notice that their agent opened it.

| | |
| - | - |
| **Needs** | Your Summer account (OAuth). In the npm MCP: `summer login --store` |

**Inputs:**

| Input | Type | Required | Description |
| - | - | - | - |
| `destination` | string | No | Length 0 to 64. |
| `path` | string | No | Length 0 to 500. |
| `tabId` | string | No | A specific Studio tab (from an earlier answer); default: the tab the person is looking at. |

<Accordion title="Input JSON schema">
  ```json theme={null}
  {
    "type": "object",
    "properties": {
      "destination": {
        "type": "string",
        "maxLength": 64
      },
      "path": {
        "type": "string",
        "maxLength": 500
      },
      "tabId": {
        "description": "A specific Studio tab (from an earlier answer); default: the tab the person is looking at.",
        "type": "string",
        "pattern": "^[A-Za-z0-9_-]{8,64}$"
      }
    }
  }
  ```
</Accordion>

**Output:** MCP text content holding JSON; errors set `isError`. From the tool's own description: Returns the page's fields and buttons once it has loaded.

```json Example call theme={null}
{
  "name": "summer_studio_open",
  "arguments": {}
}
```

***

### summer\_studio\_page

On the hosted MCP.

Read the person's open Summer Studio tab: its path, the fields an agent may fill (id, label, kind, value, limits, choices) and the buttons it may press (confirm buttons are the person's to press).

| | |
| - | - |
| **Needs** | Your Summer account (OAuth). In the npm MCP: `summer login --store` |
| **Hints** | `readOnlyHint` |

**Inputs:**

| Input | Type | Required | Description |
| - | - | - | - |
| `tabId` | string | No | A specific Studio tab (from an earlier answer); default: the tab the person is looking at. |

<Accordion title="Input JSON schema">
  ```json theme={null}
  {
    "type": "object",
    "properties": {
      "tabId": {
        "description": "A specific Studio tab (from an earlier answer); default: the tab the person is looking at.",
        "type": "string",
        "pattern": "^[A-Za-z0-9_-]{8,64}$"
      }
    }
  }
  ```
</Accordion>

**Output:** MCP text content holding JSON; errors set `isError`.

```json Example call theme={null}
{
  "name": "summer_studio_page",
  "arguments": {}
}
```

***

### summer\_studio\_use\_page

On the hosted MCP.

Fill fields and press one button on the person's open Summer Studio tab, exactly like the Studio assistant's use\_page: ids and values are checked against the page (text is trimmed to its limit, choices take their value or label, picture fields take the person's own asset ids). A button that publishes, uploads, pays or deletes is never pressed: it is shown to the person to click. Read the page first with [`summer_studio_page`](/mcp/tools/build#summer_studio_page).

| | |
| - | - |
| **Needs** | Your Summer account (OAuth). In the npm MCP: `summer login --store` |

**Inputs:**

| Input | Type | Required | Description |
| - | - | - | - |
| `fill` | object\[] | No | Items 0 to 20. |
| `fill[].field` | string | Yes | Length 0 to 64. |
| `fill[].value` | string \| number \| boolean | Yes | |
| `press` | string | No | Length 0 to 64. |
| `tabId` | string | No | A specific Studio tab (from an earlier answer); default: the tab the person is looking at. |

<Accordion title="Input JSON schema">
  ```json theme={null}
  {
    "type": "object",
    "properties": {
      "fill": {
        "maxItems": 20,
        "type": "array",
        "items": {
          "type": "object",
          "properties": {
            "field": {
              "type": "string",
              "maxLength": 64
            },
            "value": {
              "anyOf": [
                {
                  "type": "string",
                  "maxLength": 4000
                },
                {
                  "type": "number"
                },
                {
                  "type": "boolean"
                }
              ]
            }
          },
          "required": [
            "field",
            "value"
          ],
          "additionalProperties": false
        }
      },
      "press": {
        "type": "string",
        "maxLength": 64
      },
      "tabId": {
        "description": "A specific Studio tab (from an earlier answer); default: the tab the person is looking at.",
        "type": "string",
        "pattern": "^[A-Za-z0-9_-]{8,64}$"
      }
    }
  }
  ```
</Accordion>

**Output:** MCP text content holding JSON; errors set `isError`.

```json Example call theme={null}
{
  "name": "summer_studio_use_page",
  "arguments": {}
}
```

***

### summer\_test\_placement

On the local MCP (`summer-engine` npm).

Ghost-test one 3D node at an explicit candidate global pose without moving it or saving the scene.

Use this before placing a prop in a shelf, cubby, doorway, platform, or dense set. The compact result reports known overlap evidence, grounded state, signed floor gap, and at most eight overlapping object paths. Physics evidence uses enabled collider shapes; because Godot exposes no query-completeness bit, its overlap count is labeled a lower bound and an otherwise-clear physics result reports fits:null rather than claiming proof. visual\_aabb evidence is a broad-phase fallback that also catches visible mesh-only obstacles.

The pose is always global/world-space: position and Euler rotation in degrees are both required, while the subject's current global scale is preserved. scenePath and subjectPath are exact; this tool never falls back to editor selection. The normal result is below 5 KB and the scene is never mutated. On an engine build that predates TestPlacement3D the result is a structured engine\_lacks\_op failure naming the fallback.

| | |
| - | - |
| **Needs** | Summer Engine open with your project |
| **Effects** | read-only |
| **CLI** | `summer tool test-placement --args '<json>'` |

**Use when:**

* deciding whether a prop fits in a shelf, cubby, doorway, platform, or dense set before committing the transform
* re-checking a saved pose after snap or align to confirm it still clears its neighbours

**Do not use when:**

* you want the engine to move the prop for you — [`summer_snap_to_surface`](/mcp/tools/build#summer_snap_to_surface)
* the prop is 2D or has no visual/collider geometry to test

**Inputs:**

| Input | Type | Required | Description |
| - | - | - | - |
| `scenePath` | string | Yes | Exact scene path containing the subject, e.g. 'res\://levels/workshop.tscn'. Length 1 to 512. |
| `subjectPath` | string | Yes | Exact node path relative to the scene root, e.g. './World/Crate'. Length 1 to 256. |
| `candidateGlobalPosition` | any\[] | Yes | Candidate global/world position as \[x, y, z]. Items 3 to 3. |
| `candidateGlobalRotationDegrees` | any\[] | Yes | Candidate global/world Euler rotation in degrees as \[x, y, z]; current global scale is preserved. Items 3 to 3. |
| `collisionMask` | integer | No | Godot 3D physics layers included in overlap and floor queries. Default `4294967295`. Range 0 to 4294967295. |
| `collideWithAreas` | boolean | No | Include Area3D objects as placement obstacles/support candidates. Default `true`. |
| `maxFloorDistance` | number | No | Maximum world-space distance searched below the candidate footprint; range 0.001..1000. Default `5`. Range 0.001 to 1000. |
| `groundTolerance` | number | No | Absolute floor-gap tolerance used to classify grounded support. Default `0.05`. Range 0 to 1. |
| `margin` | number | No | Physics shape-intersection margin; only an exact physics support collider+shape contact is excluded from overlaps. Default `0.001`. Range 0 to 1. |

<Accordion title="Input JSON schema">
  ```json theme={null}
  {
    "type": "object",
    "properties": {
      "scenePath": {
        "type": "string",
        "minLength": 1,
        "maxLength": 512,
        "description": "Exact scene path containing the subject, e.g. 'res://levels/workshop.tscn'."
      },
      "subjectPath": {
        "type": "string",
        "minLength": 1,
        "maxLength": 256,
        "description": "Exact node path relative to the scene root, e.g. './World/Crate'."
      },
      "candidateGlobalPosition": {
        "type": "array",
        "minItems": 3,
        "maxItems": 3,
        "items": [
          {
            "type": "number"
          },
          {
            "type": "number"
          },
          {
            "type": "number"
          }
        ],
        "description": "Candidate global/world position as [x, y, z]."
      },
      "candidateGlobalRotationDegrees": {
        "type": "array",
        "minItems": 3,
        "maxItems": 3,
        "items": [
          {
            "$ref": "#/properties/candidateGlobalPosition/items/0"
          },
          {
            "$ref": "#/properties/candidateGlobalPosition/items/1"
          },
          {
            "$ref": "#/properties/candidateGlobalPosition/items/2"
          }
        ],
        "description": "Candidate global/world Euler rotation in degrees as [x, y, z]; current global scale is preserved."
      },
      "collisionMask": {
        "type": "integer",
        "minimum": 0,
        "maximum": 4294967295,
        "default": 4294967295,
        "description": "Godot 3D physics layers included in overlap and floor queries."
      },
      "collideWithAreas": {
        "type": "boolean",
        "default": true,
        "description": "Include Area3D objects as placement obstacles/support candidates."
      },
      "maxFloorDistance": {
        "type": "number",
        "minimum": 0.001,
        "maximum": 1000,
        "default": 5,
        "description": "Maximum world-space distance searched below the candidate footprint; range 0.001..1000."
      },
      "groundTolerance": {
        "type": "number",
        "minimum": 0,
        "maximum": 1,
        "default": 0.05,
        "description": "Absolute floor-gap tolerance used to classify grounded support."
      },
      "margin": {
        "type": "number",
        "minimum": 0,
        "maximum": 1,
        "default": 0.001,
        "description": "Physics shape-intersection margin; only an exact physics support collider+shape contact is excluded from overlaps."
      }
    },
    "required": [
      "scenePath",
      "subjectPath",
      "candidateGlobalPosition",
      "candidateGlobalRotationDegrees"
    ],
    "additionalProperties": false
  }
  ```
</Accordion>

**Output:** MCP text content holding JSON; errors set `isError`.

```json Example call theme={null}
{
  "name": "summer_test_placement",
  "arguments": {
    "scenePath": "res://levels/workshop.tscn",
    "subjectPath": "./World/Crate",
    "candidateGlobalPosition": [
      "<candidateGlobalPosition>"
    ],
    "candidateGlobalRotationDegrees": [
      "<candidateGlobalRotationDegree>"
    ]
  }
}
```

***

### summer\_ui\_actions

On the local MCP (`summer-engine` npm).

List the editor's named actions, or invoke ONE by name exactly as its menu item / shortcut would — the primary way to drive the editor UI. (preview — needs an engine build with UiListActions/UiInvoke)

SCENE WORK IS NOT UI WORK: to add, move, retune, or read nodes use [`summer_run_script`](/mcp/tools/build#summer_run_script), the scene tools, [`summer_world_snapshot`](/mcp/tools/run-and-test#summer_world_snapshot) and [`summer_screenshot`](/mcp/tools/run-and-test#summer_screenshot) — never by clicking through the editor. UI ops are for editor-workflow steps a human would do with the mouse: open Project Settings or the Import dock, switch the 2D/3D/Script main screen, clear a dialog that is blocking input, read what a dock currently shows.

mode:'list' -> \{actions:\[\{name, label, shortcut\_text, category, source:'shortcut'|'command', denied?}], total, truncated, filter}. name is the stable shortcut path ('editor/save\_scene', 'editor/project\_settings', 'spatial\_editor/focus\_selection', 'summer/design\_mode'); filter is a case-insensitive substring over name and label. denied:true marks names mode:'invoke' will refuse — read it and do not try them.
mode:'invoke' action\_name:'\<name>' -> \{action, label, invoked:true, handled, via:'shortcut\_event'|'command\_palette', opened\_dialog?, mutates:true}. The event runs through the same MenuBar/PopupMenu/EditorNode handlers the key would. opened\_dialog is a window that appeared synchronously; a dialog shown deferred appears on the next [`summer_ui_tree`](/mcp/tools/run-and-test#summer_ui_tree) root:'dialogs'.

Order of preference: a dedicated tool -> [`summer_ui_actions`](/mcp/tools/build#summer_ui_actions) mode:'invoke' by name -> [`summer_ui_tree`](/mcp/tools/run-and-test#summer_ui_tree) + [`summer_ui_activate`](/mcp/tools/build#summer_ui_activate) by control path -> [`summer_ui_screenshot`](/mcp/tools/run-and-test#summer_ui_screenshot) (pixels, last, and only to LOOK — never to pick coordinates). Read back, never assume: after an invoke, confirm the effect with [`summer_ui_tree`](/mcp/tools/run-and-test#summer_ui_tree) root:'dialogs' (a dialog opened), [`summer_ui_tree`](/mcp/tools/run-and-test#summer_ui_tree) root:'dock:\<name>' (a dock changed), or the scene/perception tools (the scene changed).

Failures carry failure\_reason: unknown\_action (+close\_matches — pick the exact name) | denied\_action (+reason — stop; do not route around it) | modal\_open (+blocking\_dialog — an exclusive dialog is eating input: [`summer_ui_tree`](/mcp/tools/run-and-test#summer_ui_tree) root:'dialogs', then [`summer_ui_activate`](/mcp/tools/build#summer_ui_activate) action:'dismiss\_dialog', then retry) | not\_handled (invoked but no live receiver — switch context first, e.g. [`summer_ui_activate`](/mcp/tools/build#summer_ui_activate) path:'main\_screen' action:'select\_tab' value:'3D') | editor\_unavailable. Never try to quit the editor, quit to the project list, reload the project, or delete without confirmation (editor/file\_quit, editor/quit\_to\_project\_list, editor/reload\_current\_project, scene\_tree/delete\_no\_confirm, project\_manager/\*): the engine refuses them with denied\_action, and buttons/menu items with those labels are denied the same way. They end the session you are talking over. On an engine build without these ops the result is a structured engine\_lacks\_op failure (nothing is sent) naming the dedicated tools to use instead.

| | |
| - | - |
| **Needs** | Summer Engine open with your project |
| **Effects** | changes the open project |
| **CLI** | `summer tool ui-actions --args '<json>'` |

**Use when:**

* "open project settings in the editor" / "open the Import dock" / "toggle the animation bottom panel" — an editor-workflow step a human would do with the mouse, driven by its stable action name
* finding the exact action name (mode list, filter) before invoking it, and reading which names are denied
* a step has no dedicated tool ([`summer_open_scene`](/mcp/tools/build#summer_open_scene), [`summer_select_node`](/mcp/tools/build#summer_select_node), [`summer_save_scene`](/mcp/tools/build#summer_save_scene)) but the editor has a menu item or shortcut for it

**Do not use when:**

* scene work — adding, moving, retuning, or reading nodes goes through [`summer_run_script`](/mcp/tools/build#summer_run_script), the scene tools, [`summer_world_snapshot`](/mcp/tools/run-and-test#summer_world_snapshot) and [`summer_screenshot`](/mcp/tools/run-and-test#summer_screenshot), never through editor clicks
* quitting the editor, quitting to the project list, reloading the project, or deleting without confirmation — denied by the engine (denied\_action); they end the session
* a control has no named action — read [`summer_ui_tree`](/mcp/tools/run-and-test#summer_ui_tree) and activate it by path with [`summer_ui_activate`](/mcp/tools/build#summer_ui_activate)
* requires an engine build with UiListActions / UiInvoke (Summer Engine 0.5.66 or newer); older engines return engine\_lacks\_op

**Inputs:**

| Input | Type | Required | Description |
| - | - | - | - |
| `mode` | "list" \| "invoke" | Yes | 'list' enumerates the editor's named actions (UiListActions, a read). 'invoke' runs ONE named action exactly as its menu item / shortcut would (UiInvoke, mutates editor state). |
| `filter` | string | No | mode:'list' only. Case-insensitive substring over action name and label, e.g. 'project\_settings', 'save', 'spatial\_editor', 'bottom\_panel'. |
| `limit` | integer | No | mode:'list' only. Maximum actions returned (engine default 200, max 2000). The result carries total + truncated — never assume a capped list is complete. |
| `action_name` | string | No | mode:'invoke' only (required there). The exact action name from a 'list' result — the stable shortcut path such as 'editor/project\_settings', 'editor/save\_scene', 'spatial\_editor/focus\_selection'. Palette-only commands are accepted too. |

<Accordion title="Input JSON schema">
  ```json theme={null}
  {
    "type": "object",
    "properties": {
      "mode": {
        "type": "string",
        "enum": [
          "list",
          "invoke"
        ],
        "description": "'list' enumerates the editor's named actions (UiListActions, a read). 'invoke' runs ONE named action exactly as its menu item / shortcut would (UiInvoke, mutates editor state)."
      },
      "filter": {
        "type": "string",
        "description": "mode:'list' only. Case-insensitive substring over action name and label, e.g. 'project_settings', 'save', 'spatial_editor', 'bottom_panel'."
      },
      "limit": {
        "type": "integer",
        "exclusiveMinimum": 0,
        "description": "mode:'list' only. Maximum actions returned (engine default 200, max 2000). The result carries total + truncated — never assume a capped list is complete."
      },
      "action_name": {
        "type": "string",
        "description": "mode:'invoke' only (required there). The exact action name from a 'list' result — the stable shortcut path such as 'editor/project_settings', 'editor/save_scene', 'spatial_editor/focus_selection'. Palette-only commands are accepted too."
      }
    },
    "required": [
      "mode"
    ],
    "additionalProperties": false
  }
  ```
</Accordion>

**Output:** MCP text content holding JSON; errors set `isError`.

```json Example call theme={null}
{
  "name": "summer_ui_actions",
  "arguments": {
    "mode": "list"
  }
}
```

***

### summer\_ui\_activate

On the local MCP (`summer-engine` npm).

Activate ONE editor control by its [`summer_ui_tree`](/mcp/tools/run-and-test#summer_ui_tree) path through the control's own input path — a synthetic click for buttons, the public setter + signal for tabs, text fields and ranges — or dismiss a visible dialog (action:'dismiss\_dialog'). Mutates editor state; the result's state is READ BACK from the control after the action, not echoed. (preview — needs an engine build with UiActivate/UiDismissDialog)

SCENE WORK IS NOT UI WORK: to add, move, retune, or read nodes use [`summer_run_script`](/mcp/tools/build#summer_run_script), the scene tools, [`summer_world_snapshot`](/mcp/tools/run-and-test#summer_world_snapshot) and [`summer_screenshot`](/mcp/tools/run-and-test#summer_screenshot) — never by clicking through the editor. UI ops are for editor-workflow steps a human would do with the mouse: open Project Settings or the Import dock, switch the 2D/3D/Script main screen, clear a dialog that is blocking input, read what a dock currently shows. Reach for this only when no named action covers the step ([`summer_ui_actions`](/mcp/tools/build#summer_ui_actions) mode:'list' first). There is no coordinate click: if a thing is visible it is in the tree and this reaches it by path.

actions: press (BaseButton: hover+press+release at the rect centre — pressed\_emitted is observed, not assumed; ItemList/PopupMenu item by index; MenuBar -> unsupported\_control, use [`summer_ui_actions`](/mcp/tools/build#summer_ui_actions)) | toggle (toggle-mode button) | focus (any control/window) | select\_tab (TabContainer/TabBar by value title or index; path:'main\_screen' switches the 2D/3D/Script/Game/AssetLib editor by value or index and reads back current\_tab + text) | set\_text (LineEdit/TextEdit; submit:true also presses Enter; value '' clears) | set\_value (Range number) | dismiss\_dialog (path or title from [`summer_ui_tree`](/mcp/tools/run-and-test#summer_ui_tree) root:'dialogs'; button 'cancel' default = the safe close, 'ok' or a button text to confirm — only when the user asked for that).

Returns \{path, class, action, via, state:\{...the node's tree fields...}, mutates:true} plus clicked\_at/hover\_established/pressed\_emitted for press, item\_text for menus, submitted for set\_text; dismiss\_dialog returns \{title, class, button, via, visible\_after} — visible\_after:true means the dialog re-validated and stayed up (read it: [`summer_ui_tree`](/mcp/tools/run-and-test#summer_ui_tree) root:'dialog:\<title>'). Verify with the read-back (state.checked, state.current\_tab, state.text, visible\_after), never by assumption.

Failures: not\_found | not\_visible (hidden — reveal the dock/tab first) | disabled | unsupported\_control (+supported\_actions) | obscured (+hit\_control — something on top, usually a dialog) | modal\_open (+blocking\_dialog — dismiss it first) | no\_activation\_path (use the named action instead) | denied\_action / denied\_path (safety: quit/reload labels, file-dialog paths outside the project) | tab\_not\_found (+tabs) | index\_out\_of\_range | missing\_value | not\_selected | button\_not\_found (+buttons) | ambiguous\_dialog (+candidates). Never try to quit the editor, quit to the project list, reload the project, or delete without confirmation (editor/file\_quit, editor/quit\_to\_project\_list, editor/reload\_current\_project, scene\_tree/delete\_no\_confirm, project\_manager/\*): the engine refuses them with denied\_action, and buttons/menu items with those labels are denied the same way. They end the session you are talking over. Engine builds without these ops return a structured engine\_lacks\_op failure (nothing is sent).

| | |
| - | - |
| **Needs** | Summer Engine open with your project |
| **Effects** | changes the open project |
| **CLI** | `summer tool ui-activate --args '<json>'` |

**Use when:**

* "dismiss the dialog that is blocking the editor" / "close that popup" — action dismiss\_dialog with the path or title from [`summer_ui_tree`](/mcp/tools/run-and-test#summer_ui_tree) root dialogs
* "switch the editor to the 3D view" / "go to the Script screen" — path main\_screen, action select\_tab, value 3D
* pressing a button, selecting a tab, typing into a search field, or dialling a slider that no named action covers, using a path from [`summer_ui_tree`](/mcp/tools/run-and-test#summer_ui_tree)

**Do not use when:**

* a named action exists — [`summer_ui_actions`](/mcp/tools/build#summer_ui_actions) mode invoke is the first choice; the tree walk is for the long tail
* scene work — nodes, properties, and placement go through [`summer_run_script`](/mcp/tools/build#summer_run_script) and the scene tools, never through editor clicks
* confirming a quit, reload, or delete-without-confirmation button — denied by the engine (denied\_action) because it ends the session or bypasses the human's confirmation
* requires an engine build with UiActivate / UiDismissDialog (Summer Engine 0.5.66 or newer); older engines return engine\_lacks\_op

**Inputs:**

| Input | Type | Required | Description |
| - | - | - | - |
| `action` | "press" \| "toggle" \| "focus" \| "select\_tab" \| "set\_text" \| "set\_value" \| "dismiss\_dialog" | No | Default 'press'. press = synthetic left click on a button / ItemList item / PopupMenu item (index); toggle = flip a toggle-mode button; focus = grab\_focus on any control; select\_tab = TabContainer/TabBar by value (title) or index — and the synthetic path 'main\_screen' switches the 2D/3D/Script/Game/AssetLib editor by value or index; set\_text = LineEdit/TextEdit text (submit:true also emits text\_submitted); set\_value = Range (SpinBox/Slider) number; dismiss\_dialog = close a visible dialog by path or title (UiDismissDialog). |
| `path` | string | No | A control `path` from summer\_ui\_tree (required for every action except dismiss\_dialog, which may use title instead), or 'main\_screen' with action:'select\_tab'. Auto-named paths (@Panel\@123) are stable within a session only — re-read the tree rather than persist them. |
| `value` | string \| number | No | select\_tab: tab title (or the main-screen editor name: '2D', '3D', 'Script', 'Game', 'AssetLib'); set\_text: the text; set\_value: the number. |
| `index` | integer | No | select\_tab: tab index; press on an ItemList / PopupMenu: item index. Range 0 to …. |
| `submit` | boolean | No | set\_text on a LineEdit only: also emit text\_submitted (the Enter key), e.g. to run a search box. |
| `title` | string | No | dismiss\_dialog only: a visible window title (case-insensitive; exact wins, one substring match accepted, otherwise ambiguous\_dialog) — from summer\_ui\_tree root:'dialogs'. |
| `button` | string | No | dismiss\_dialog only. 'cancel' (default — the safe close: cancel button / hide / OS close request), 'ok', or the exact text of a button in the dialog's row. Buttons whose label quits or reloads the editor are denied by the engine. |

<Accordion title="Input JSON schema">
  ```json theme={null}
  {
    "type": "object",
    "properties": {
      "action": {
        "type": "string",
        "enum": [
          "press",
          "toggle",
          "focus",
          "select_tab",
          "set_text",
          "set_value",
          "dismiss_dialog"
        ],
        "description": "Default 'press'. press = synthetic left click on a button / ItemList item / PopupMenu item (index); toggle = flip a toggle-mode button; focus = grab_focus on any control; select_tab = TabContainer/TabBar by value (title) or index — and the synthetic path 'main_screen' switches the 2D/3D/Script/Game/AssetLib editor by value or index; set_text = LineEdit/TextEdit text (submit:true also emits text_submitted); set_value = Range (SpinBox/Slider) number; dismiss_dialog = close a visible dialog by path or title (UiDismissDialog)."
      },
      "path": {
        "type": "string",
        "description": "A control `path` from summer_ui_tree (required for every action except dismiss_dialog, which may use title instead), or 'main_screen' with action:'select_tab'. Auto-named paths (@Panel@123) are stable within a session only — re-read the tree rather than persist them."
      },
      "value": {
        "type": [
          "string",
          "number"
        ],
        "description": "select_tab: tab title (or the main-screen editor name: '2D', '3D', 'Script', 'Game', 'AssetLib'); set_text: the text; set_value: the number."
      },
      "index": {
        "type": "integer",
        "minimum": 0,
        "description": "select_tab: tab index; press on an ItemList / PopupMenu: item index."
      },
      "submit": {
        "type": "boolean",
        "description": "set_text on a LineEdit only: also emit text_submitted (the Enter key), e.g. to run a search box."
      },
      "title": {
        "type": "string",
        "description": "dismiss_dialog only: a visible window title (case-insensitive; exact wins, one substring match accepted, otherwise ambiguous_dialog) — from summer_ui_tree root:'dialogs'."
      },
      "button": {
        "type": "string",
        "description": "dismiss_dialog only. 'cancel' (default — the safe close: cancel button / hide / OS close request), 'ok', or the exact text of a button in the dialog's row. Buttons whose label quits or reloads the editor are denied by the engine."
      }
    },
    "additionalProperties": false
  }
  ```
</Accordion>

**Output:** MCP text content holding JSON; errors set `isError`. From the tool's own description: Returns \{path, class, action, via, state:\{...the node's tree fields...}, mutates:true} plus clicked\_at/hover\_established/pressed\_emitted for press, item\_text for menus, submitted for set\_text; dismiss\_dialog returns \{title, class, button, via, visible\_after} — visible\_after:true means the dialog re-validated and stayed up (read it: summer\_ui\_tree root:'dialog:\<title>').

```json Example call theme={null}
{
  "name": "summer_ui_activate",
  "arguments": {}
}
```

***

### summer\_write\_file

On the local MCP (`summer-engine` npm).

Create or safely overwrite a complete text file through the identity-bound engine.

For a new file, set create\_only:true. For an existing file, first call [`summer_read_file`](/mcp/tools/build#summer_read_file) and pass its sha256 as expected\_sha256. Exactly one guard is required; unguarded writes fail closed. Supports scripts, .tscn scenes, .tres resources, JSON, docs, and project config.

| | |
| - | - |
| **Needs** | Summer Engine open with your project |
| **Effects** | writes files |
| **CLI** | `summer tool write-file --args '<json>'` |

**Use when:**

* creating a new project file with the create-only guard
* overwriting an existing file with its sha256 receipt

**Inputs:**

| Input | Type | Required | Description |
| - | - | - | - |
| `path` | string | Yes | Project path, e.g. res\://scenes/player.tscn |
| `content` | string | Yes | Complete new UTF-8 file content. |
| `create_only` | boolean | No | Required for a new file; refuses if the path already exists. |
| `expected_sha256` | string | No | Required for overwriting an existing file; obtain from summer\_read\_file. |

<Accordion title="Input JSON schema">
  ```json theme={null}
  {
    "type": "object",
    "properties": {
      "path": {
        "type": "string",
        "description": "Project path, e.g. res://scenes/player.tscn"
      },
      "content": {
        "type": "string",
        "description": "Complete new UTF-8 file content."
      },
      "create_only": {
        "type": "boolean",
        "description": "Required for a new file; refuses if the path already exists."
      },
      "expected_sha256": {
        "type": "string",
        "description": "Required for overwriting an existing file; obtain from summer_read_file."
      }
    },
    "required": [
      "path",
      "content"
    ],
    "additionalProperties": false
  }
  ```
</Accordion>

**Output:** MCP text content holding JSON; errors set `isError`.

```json Example call theme={null}
{
  "name": "summer_write_file",
  "arguments": {
    "path": "<path>",
    "content": "<content>"
  }
}
```

***


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.