@uemcp/server 0.4.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +45 -0
  2. package/dist/index.mjs +1137 -122
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -32,6 +32,18 @@ The MCP tool surface currently exposes:
32
32
  - `set_config_value`
33
33
  - `list_config_section`
34
34
  - `run_clang_tidy`
35
+ - `list_actors`
36
+ - `get_actor_details`
37
+ - `get_current_level`
38
+ - `spawn_actor`
39
+ - `destroy_actor`
40
+ - `set_actor_transform`
41
+ - `set_actor_property`
42
+ - `select_actors`
43
+ - `undo`
44
+ - `redo`
45
+ - `open_level`
46
+ - `get_open_level_status`
35
47
 
36
48
  ## Project Identity
37
49
 
@@ -137,6 +149,39 @@ This is intended to let an MCP client resolve the canonical Unreal project ident
137
149
  - Spawns `clang-tidy` (server-configured via `CLANG_TIDY_PATH`, else `PATH`) over the translation units and returns structured findings (file, line, column, check, severity, message)
138
150
  - Report only — does not apply fixes
139
151
 
152
+ ### `list_actors` / `get_actor_details` / `get_current_level`
153
+
154
+ - The read half of the level surface. All three answer about actors instantiated in the **editor world** — not the PIE world, and not assets on disk (`find_assets` remains the tool for those)
155
+ - Every actor is identified by `actorPath` — `AActor::GetPathName()`, e.g. `/Game/Maps/Test.Test:PersistentLevel.StaticMeshActor_3` — carried alongside the display `label`. The path is the only stable, unique, resolvable identifier; labels are neither unique nor resolvable, so never address an actor by one. The same `actorPath` round-trips through `get_editor_state`, `list_actors`, and `select_actors`
156
+ - `list_actors` filters by class and by name substring, and pages with `nextCursor` / `totalCount` / `truncated`. Pages are trimmed by encoded bytes as well as by entry count, because actor paths vary wildly in length — `totalCount` stays authoritative when a page truncates
157
+ - `get_actor_details` reports the actor's class, transform, folder, tags, components, and reflected properties, paging components and properties independently. Property values are `ExportText`, the same format `get_cdo_defaults` emits and `set_actor_property` accepts
158
+ - `get_current_level` reports the loaded map's package name plus its streaming levels and World Partition state
159
+
160
+ ### `spawn_actor` / `destroy_actor` / `set_actor_transform` / `set_actor_property` / `select_actors`
161
+
162
+ - The mutating half. **Every one of these runs inside a single `FScopedTransaction` on the game thread, so one Ctrl+Z in the editor reverses the whole call** — a batch of 64 spawns undoes as one step, not 64. The response reports the `transactionTitle` the batch collapsed into
163
+ - All five take **arrays** and return per-item results (`{ index, ok, actorPath?, error? }`) with `successCount` / `failureCount`. One bad entry fails its own item and neither aborts the batch nor rolls back the transaction. The batch bound is 64 (`BRIDGE_LEVEL_EDIT_MAX_BATCH`), sized so the request also stays under the 64 KiB payload cap
164
+ - `dryRun: true` validates everything the real call validates — class resolves, actor exists, property path resolves and the value coerces — and reports what *would* change with `state: 'validated'`, opening no transaction and touching no world state
165
+ - Mutations `Modify()` the objects they touch and dirty their packages, so `save_dirty_packages` subsequently reports and persists them
166
+ - `set_actor_transform` treats each of `location` / `rotation` / `scale` as optional: an omitted component keeps its current value, so a move need not restate the rest. An entry naming none of the three is rejected rather than silently doing nothing
167
+ - `set_actor_property` addresses a property on the actor (`bHidden`) or on one of its components (`StaticMeshComponent.RelativeScale3D`), and writes via `ImportText_InContainer` — the exact inverse of the reader, so a value read from `get_actor_details` or `get_cdo_defaults` can be edited and written back with no format translation. `EditConst` and non-editable properties are rejected with an explicit error rather than silently no-op'ing
168
+ - `select_actors` sets the editor selection; an empty `actorPaths` clears it, and `addToSelection` adds rather than replaces. It reports the resulting `selectedActorCount`
169
+ - In a non-editor plugin build every one of these returns `state: 'unsupported'` rather than failing
170
+
171
+ ### `undo` / `redo`
172
+
173
+ - Act on the editor's own transaction buffer — the same buffer Ctrl+Z and Ctrl+Y drive — and report the `transactionTitle` they acted on, or `state: 'nothing_to_undo'` / `'nothing_to_redo'`
174
+ - The head of that buffer may be a **human's** edit rather than the agent's, so check the returned `transactionTitle` before assuming what was reversed
175
+
176
+ ### `open_level` / `get_open_level_status`
177
+
178
+ - Loading a map tears down and rebuilds the world, which runs far past the plugin's 5 s game-thread budget, so `open_level` does not load inline: it validates the request, schedules the load onto the next editor tick, and returns `state: 'opening'` with an `openLevelJobId`. Poll it with `get_open_level_status` (or `wait_for_job`) until the state leaves `opening`
179
+ - `dryRun: true` checks that the level package exists and reports `state: 'validated'` with no job — nothing was scheduled, so nothing is pollable
180
+ - Unsaved changes in the current world are **discarded** unless `saveDirtyPackages: true`, which saves before the teardown. There is no user in front of a bridge request to answer the editor's usual "save these?" prompt
181
+ - **Not undoable.** Loading a map clears the transaction buffer, so `undo` cannot bring the previous level back
182
+ - Actor paths do not survive a load: re-run `list_actors` against the new world rather than reusing paths from the old one
183
+ - One load at a time per editor; a second request while one is running is refused with `open_level_in_progress` rather than queued
184
+
140
185
  ## MCP Resources
141
186
 
142
187
  Resources carry context a client can attach without spending a tool call and a model turn. Every one of them is served from in-memory state or the local filesystem: **a resource read never opens a bridge socket and never waits on the editor**, so an unreachable or absent editor produces a structured payload rather than a timeout.