@uemcp/server 1.3.0 → 1.4.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.
- package/README.md +114 -0
- package/dist/index.mjs +2352 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -94,6 +94,37 @@ The MCP tool surface currently exposes:
|
|
|
94
94
|
- `list_data_layers`
|
|
95
95
|
- `set_data_layer_state`
|
|
96
96
|
- `load_wp_region`
|
|
97
|
+
- `get_asset_property`
|
|
98
|
+
- `set_asset_property`
|
|
99
|
+
- `array_property_op`
|
|
100
|
+
- `create_struct`
|
|
101
|
+
- `create_enum`
|
|
102
|
+
- `create_blueprint`
|
|
103
|
+
- `add_bp_variable`
|
|
104
|
+
- `add_bp_function`
|
|
105
|
+
- `add_bp_event`
|
|
106
|
+
- `add_bp_component`
|
|
107
|
+
- `add_bp_interface`
|
|
108
|
+
- `set_bp_default`
|
|
109
|
+
- `batch_edit`
|
|
110
|
+
- `import_asset`
|
|
111
|
+
- `reimport_asset`
|
|
112
|
+
- `set_import_settings`
|
|
113
|
+
- `get_import_job_status`
|
|
114
|
+
- `create_blackboard`
|
|
115
|
+
- `set_blackboard_keys`
|
|
116
|
+
- `create_eqs_query`
|
|
117
|
+
- `create_state_tree`
|
|
118
|
+
- `add_state_tree_state`
|
|
119
|
+
- `create_level_sequence`
|
|
120
|
+
- `add_sequence_binding`
|
|
121
|
+
- `add_sequence_track`
|
|
122
|
+
- `add_sequence_keys`
|
|
123
|
+
- `add_foliage_type`
|
|
124
|
+
- `paint_foliage`
|
|
125
|
+
- `create_sound_cue`
|
|
126
|
+
- `create_metasound`
|
|
127
|
+
- `set_metasound_graph`
|
|
97
128
|
|
|
98
129
|
## Project Identity
|
|
99
130
|
|
|
@@ -358,6 +389,89 @@ This is intended to let an MCP client resolve the canonical Unreal project ident
|
|
|
358
389
|
- `load_wp_region` pins a bounding box into the editor through a loader adapter — the same mechanism the World Partition window uses when a human drags a loading region — and reports how many actors that brought into memory. The load is synchronous, so a box covering a large part of a big partitioned map blocks the editor while it runs: pin the area being worked on, not the whole world
|
|
359
390
|
- Pins are held by the bridge and released on `unpin_all`, and every pin is released when the bridge shuts down, so a session cannot silently accumulate loaded actors nobody can name any more
|
|
360
391
|
|
|
392
|
+
### `get_asset_property` / `set_asset_property` / `array_property_op`
|
|
393
|
+
|
|
394
|
+
- The asset-side counterpart to `get_actor_details` / `set_actor_property`: reflected reads and writes against an asset on disk rather than an actor in a level
|
|
395
|
+
- Values cross the wire as **ExportText**, the exact spelling the reader reports and the writer takes back, so a value read from one asset can be written straight into another without translation
|
|
396
|
+
- `propertyPath` walks structs, array elements and object references (`Modifiers[1].Magnitude`), and an `FPostProcessSettings`-style field also sets its `bOverride_` sibling — a write that skipped it would report success and change nothing anyone can see
|
|
397
|
+
- A Blueprint asset resolves to its **class defaults**, which is what the Class Defaults panel edits, rather than to the `UBlueprint` bookkeeping object that carries none of the user's properties
|
|
398
|
+
- `array_property_op` exists because an array cannot be written as one exported string without knowing the whole array. It reports `elementCount` after the operation, and an out-of-range index is refused **before** the transaction opens so a rejected request leaves no undo entry behind
|
|
399
|
+
- Every write leaves the package dirty rather than saving it, so a run of edits is one `save_asset`
|
|
400
|
+
|
|
401
|
+
### `create_struct` / `create_enum`
|
|
402
|
+
|
|
403
|
+
- User-defined types, authored through the engine's own `FStructureEditorUtils` / `FEnumEditorUtils` rather than by writing the asset — those utilities are what recompile every Blueprint that already referenced the type
|
|
404
|
+
- Field and variable types share **one type grammar** with the Blueprint tools: a `kind`, an optional `container` (`array`, `set`, `map`) and a `subtype` naming what the kind points at. A kind that names something in the project without a subtype is refused, because UE would otherwise produce a wildcard pin
|
|
405
|
+
- A fresh struct or enum arrives with one placeholder member so the asset is valid on disk; the requested members are added first and the placeholder removed afterwards, since neither utility will remove the last one
|
|
406
|
+
- `rebuiltAssets` reports what the editor recompiled because the type changed underneath it — empty for a brand-new type, which has no dependents yet
|
|
407
|
+
|
|
408
|
+
### `create_blueprint` / `add_bp_variable` / `add_bp_function` / `add_bp_event` / `add_bp_component` / `add_bp_interface` / `set_bp_default`
|
|
409
|
+
|
|
410
|
+
- Blueprint **authoring**, the write side of `get_blueprint_summary` / `get_blueprint_graph`. Every call leaves the Blueprint compiled and its package dirty: an uncompiled Blueprint reports the old member list to every reader, which makes the next tool call wrong
|
|
411
|
+
- `create_blueprint` reports the **generated class path** (`/Game/BP/BP_Foo.BP_Foo_C`), which is what `spawn_actor` and every class reference take — not the asset path
|
|
412
|
+
- `add_bp_variable` carries replication: `rep_notify` also authors the `OnRep_` handler graph, because a `CPF_RepNotify` variable whose handler does not exist fails to compile
|
|
413
|
+
- `add_bp_event` distinguishes `override` from `custom`. An override takes its signature from the parent, so declaring `inputs` on one is refused rather than silently discarded
|
|
414
|
+
- Batched calls report **per entry**: one variable that fails to resolve its type does not abort the other thirty-one
|
|
415
|
+
- `set_bp_default` writes the same reflected values `set_asset_property` does, against the generated class's CDO
|
|
416
|
+
|
|
417
|
+
### `batch_edit`
|
|
418
|
+
|
|
419
|
+
- The one level tool that is **all-or-nothing**. Every other batch reports per-item failures and keeps going; this one cancels its transaction on the first failure and leaves the level exactly as it was
|
|
420
|
+
- That is the point: ops address actors earlier ops created. A `spawn` binds a caller-supplied `handle`, and a later op addresses it as `handle:<name>` — a half-applied batch would leave the level in a state nobody described
|
|
421
|
+
- Ordered and heterogeneous: spawn, place, transform, set a property, attach, tag and destroy in one call, inside **one** `FScopedTransaction`, so a human presses Ctrl+Z once
|
|
422
|
+
- `handles` reports what each handle bound to, so the new actors are addressable afterwards. A rollback reports `failedIndex` and `failedError` and no handles, because none of them exist any more
|
|
423
|
+
- `dryRun` validates the shape of the batch only. An op addressing a handle can only be checked once the spawn that binds it has run, so anything further is a promise this call cannot keep
|
|
424
|
+
|
|
425
|
+
### `import_asset` / `reimport_asset` / `set_import_settings` / `get_import_job_status`
|
|
426
|
+
|
|
427
|
+
- Source asset import. An FBX of any real size runs far past the game thread budget, so both mutating requests return `state: 'accepted'` with an `importJobId`. Poll it with `get_import_job_status`, or wait with `wait_for_job` using `kind: 'import'`
|
|
428
|
+
- `pipeline: 'auto'` lets the editor route the file — **Interchange first, legacy factory where there is no translator**, which is the engine's own behaviour. `'interchange'` is refused up front for a file no translator claims, rather than quietly running the legacy factory instead; `'legacy_factory'` names the factory explicitly so Interchange cannot take over behind the caller's back
|
|
429
|
+
- Job results are **per source file**, and each one lists **every** asset it produced: a skeletal mesh import yields a mesh, a skeleton and a physics asset, and a caller that only heard about the mesh would leave the rest unreferenced
|
|
430
|
+
- `set_import_settings` stores a named preset. It is applied to the import factory that claims each source file, so a key that factory does not have is a **request error** rather than something dropped on the floor
|
|
431
|
+
- `get_import_job_status` is exposed as its own tool because the accept-then-poll shape needs somewhere to poll; it is not one of the tools the issues named, and it exists only to serve them
|
|
432
|
+
|
|
433
|
+
### `create_blackboard` / `set_blackboard_keys`
|
|
434
|
+
|
|
435
|
+
- Blackboard assets, the data half of a Behavior Tree
|
|
436
|
+
- An `object`, `class` or `enum` key **must** name its base type. Without it the key still appears in the editor and never matches anything at runtime, which is the failure these tools exist to prevent
|
|
437
|
+
- Inherited keys are counted and reported **separately** from local ones: a key that comes from the parent blackboard is not one this asset owns, and adding a local copy of it is exactly the mistake the split prevents
|
|
438
|
+
- `set_blackboard_keys` with `mode: 'replace'` drops the **local** keys only — an inherited key belongs to the parent asset and is not this request's to remove
|
|
439
|
+
|
|
440
|
+
### `create_eqs_query`
|
|
441
|
+
|
|
442
|
+
- Environment queries: one generator plus its tests, each with its own `purpose` (`filter`, `score`, or both), since a failing test either removes an item or merely scores it down
|
|
443
|
+
- Generator and test classes are resolved and their parameters written by reflection **before** the asset exists, so a typo leaves nothing behind in the content browser
|
|
444
|
+
- `eqsEnabled` reports whether the Environment Query editor is switched on. With it off the asset is still valid and still runs, but nothing in the editor will open it — reported rather than failed, and the response names where to turn it on (Editor Preferences → Experimental → AI → Environment Query Editor)
|
|
445
|
+
|
|
446
|
+
### `create_state_tree` / `add_state_tree_state`
|
|
447
|
+
|
|
448
|
+
- StateTree assets and their states. `supportedVersions` is reported on every answer, so an editor this plugin build cannot author StateTrees for says so instead of failing somewhere inside the compiler
|
|
449
|
+
- The schema decides which tasks and conditions the tree may hold at all, so an unresolvable one is refused before the asset exists
|
|
450
|
+
- Tasks and enter conditions are **script structs**, not classes, and are addressed as such; their parameters are written into the instanced struct's own memory by reflection
|
|
451
|
+
- `add_state_tree_state` compiles by default and reports `compiled` separately from the per-state results: a tree that was authored but not compiled reports `false` with no messages, which is a different thing from one that failed to compile
|
|
452
|
+
|
|
453
|
+
### `create_level_sequence` / `add_sequence_binding` / `add_sequence_track` / `add_sequence_keys`
|
|
454
|
+
|
|
455
|
+
- Sequencer authoring. **Every time on this surface is explicit**, because a sequence authored at the wrong rate is silently wrong rather than broken
|
|
456
|
+
- Frame rates cross the wire as the exact rationals Sequencer stores — 30000/1001 is not 29.97 — and `create_level_sequence` reports back both `displayRate` and `tickResolution`, since every frame number in `add_sequence_keys` resolves through them
|
|
457
|
+
- `add_sequence_keys` requires `timeUnit`: `'frames'` resolves through the display rate and `'seconds'` through the tick resolution. It reports `resolvedFrames`, which is the number that proves a seconds-based request converted correctly on a non-default rate
|
|
458
|
+
- A `possessable` binding names an actor in the level; a `spawnable` one needs a template, so it takes an actor to copy or a class to instance
|
|
459
|
+
- A `camera_cut` track belongs to the sequence itself; every other kind belongs to a binding, so `bindingId` is required for them. A `property` track is typed by the property it drives — bool, float and double properties are animatable, and anything else is refused rather than animated as the wrong type
|
|
460
|
+
|
|
461
|
+
### `add_foliage_type` / `paint_foliage`
|
|
462
|
+
|
|
463
|
+
- Foliage types and instance placement
|
|
464
|
+
- `mode: 'explicit'` places the transforms the caller supplies. `mode: 'region'` is a **rule the editor evaluates against the ground** — density over an area, traced downward, filtered by slope — which is the only shape that scales to the tens of thousands of instances a real pass produces
|
|
465
|
+
- A region takes a `randomSeed`, so the same call twice produces the same scatter and a painted region is reviewable rather than a one-off
|
|
466
|
+
- `attemptedCount`, `placedCount` and `skippedCount` are reported separately: a placement whose downward trace hit nothing, or hit ground outside the slope limits, is skipped rather than placed floating. `instanceCount` is the foliage actor's **total** for that type afterwards, so density can be checked against something absolute
|
|
467
|
+
|
|
468
|
+
### `create_sound_cue` / `create_metasound` / `set_metasound_graph`
|
|
469
|
+
|
|
470
|
+
- Audio authoring. Sound Cue nodes are addressed by **caller-supplied ids**, so connections can name nodes before the editor has created them
|
|
471
|
+
- `rootNodeId` must name one of the nodes in the same request, and a `wave_player` must name the wave it plays — both are refused up front rather than producing a cue that plays silence
|
|
472
|
+
- MetaSound documents are **never written directly**. The document format is versioned and migrated by the engine, so everything goes through `UMetaSoundBuilderSubsystem`, which is the only supported way to author one from code
|
|
473
|
+
- `set_metasound_graph` declares interface members, adds nodes by their registered class name and connects them. A connection whose data types do not match is reported with the builder's own refusal rather than left as a silently dead edge
|
|
474
|
+
|
|
361
475
|
## MCP Resources
|
|
362
476
|
|
|
363
477
|
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.
|