ultimate-unreal-engine-mcp 0.1.22 → 0.1.23
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 +46 -0
- package/dist/index.js +63 -0
- package/dist/tools/editor/index.js +6 -6
- package/dist/tools/viewport/index.js +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -23,6 +23,7 @@ npx ultimate-unreal-engine-mcp setup
|
|
|
23
23
|
- [Architecture](#architecture)
|
|
24
24
|
- [Tool Catalog](#tool-catalog)
|
|
25
25
|
- [Visual Review Loop](#visual-review-loop)
|
|
26
|
+
- [Automatic Self-Verification](#automatic-self-verification)
|
|
26
27
|
- [Headless vs Live](#headless-vs-live)
|
|
27
28
|
- [Installation](#installation)
|
|
28
29
|
- [C++ Plugin Setup](#c-plugin-setup)
|
|
@@ -543,6 +544,51 @@ ue_cleanup_screenshots(confirm=true)
|
|
|
543
544
|
|
|
544
545
|
---
|
|
545
546
|
|
|
547
|
+
## Automatic Self-Verification
|
|
548
|
+
|
|
549
|
+
Every mutating tool description includes **mandatory verification guidance** — the AI is instructed to verify its own work before reporting success. This isn't a suggestion; it's baked into the tool interface.
|
|
550
|
+
|
|
551
|
+
**Why this matters:** In spatial work (placing doors, aligning meshes, wiring components), a single transform can have cascading effects — rotating a mesh around a pivot shifts its world position, negative scale flips face normals making geometry invisible, collision volumes don't automatically follow mesh offsets. Without verification, the AI reports "done" while the door is floating 2 meters from the wall.
|
|
552
|
+
|
|
553
|
+
**How it works:**
|
|
554
|
+
|
|
555
|
+
```
|
|
556
|
+
ue_spawn_actor("BP_Door", location={x:1040, y:150, z:0})
|
|
557
|
+
→ Actor spawned
|
|
558
|
+
|
|
559
|
+
ue_get_component_bounds("BP_Door", component="DoorMesh") ← automatic
|
|
560
|
+
→ bounds: X=[806, 994] ✓ — in the doorway
|
|
561
|
+
|
|
562
|
+
ue_set_actor_property("BP_Door", "DoorMesh.RelativeRotation", ...)
|
|
563
|
+
→ Property set
|
|
564
|
+
|
|
565
|
+
ue_get_component_bounds("BP_Door", component="DoorMesh") ← automatic
|
|
566
|
+
→ bounds: X=[1040, 1228] ✗ — rotation shifted mesh out of gap
|
|
567
|
+
|
|
568
|
+
ue_set_actor_property("BP_Door", "DoorMesh.RelativeLocation", ...) ← self-correction
|
|
569
|
+
→ Offset compensated
|
|
570
|
+
|
|
571
|
+
ue_get_component_bounds("BP_Door", component="DoorMesh") ← re-verify
|
|
572
|
+
→ bounds: X=[806, 994] ✓ — back in place
|
|
573
|
+
|
|
574
|
+
ue_look_at("BP_Door", angle="front") ← visual confirm
|
|
575
|
+
→ [screenshot inline] door visible, handle correct side ✓
|
|
576
|
+
```
|
|
577
|
+
|
|
578
|
+
**The Inspect-Reason-Fix cycle:**
|
|
579
|
+
|
|
580
|
+
| Step | What happens | Tool |
|
|
581
|
+
|------|-------------|------|
|
|
582
|
+
| **Act** | Spawn, transform, or set property | `ue_spawn_actor`, `ue_transform_actor`, `ue_set_actor_property` |
|
|
583
|
+
| **Measure** | Get exact numerical positions | `ue_get_component_bounds` |
|
|
584
|
+
| **Reason** | Do bounds match expectations? | (AI reasoning) |
|
|
585
|
+
| **Fix** | Adjust offsets to compensate | Same mutation tools |
|
|
586
|
+
| **Verify** | Confirm fix worked, visually and numerically | `ue_get_component_bounds` + `ue_look_at` |
|
|
587
|
+
|
|
588
|
+
The AI also has access to a `ue://best-practices/self-verification` MCP resource that documents verification patterns, common spatial pitfalls, and the full verification matrix.
|
|
589
|
+
|
|
590
|
+
---
|
|
591
|
+
|
|
546
592
|
## Headless vs Live
|
|
547
593
|
|
|
548
594
|
Some tools work without the UE Editor running. Others require the MCPBridge plugin connected to a live editor instance.
|
package/dist/index.js
CHANGED
|
@@ -77,6 +77,69 @@ import { registerNetworkingTools } from './tools/networking/index.js';
|
|
|
77
77
|
registerMotionDesignTools(server); // Motion Design tools (MD-01..04)
|
|
78
78
|
registerMovieRenderTools(server); // Movie Render Pipeline tools (MRP-01..04)
|
|
79
79
|
registerNetworkingTools(server); // Networking & Replication tools (NET-01..04)
|
|
80
|
+
// ---------------------------------------------------------------------------
|
|
81
|
+
// Register best-practices resource: self-verification guide
|
|
82
|
+
// ---------------------------------------------------------------------------
|
|
83
|
+
server.registerResource('ue_best_practices', 'ue://best-practices/self-verification', {
|
|
84
|
+
title: 'UE MCP Best Practices: Self-Verification',
|
|
85
|
+
description: 'Guidelines for AI assistants using UE MCP tools. Covers mandatory self-verification after mutations, spatial reasoning patterns, and the inspect-reason-fix cycle.',
|
|
86
|
+
mimeType: 'text/markdown',
|
|
87
|
+
}, async (_uri) => ({
|
|
88
|
+
contents: [{
|
|
89
|
+
uri: 'ue://best-practices/self-verification',
|
|
90
|
+
mimeType: 'text/markdown',
|
|
91
|
+
text: `# UE MCP Best Practices: Self-Verification
|
|
92
|
+
|
|
93
|
+
## Core Principle
|
|
94
|
+
|
|
95
|
+
**Always verify your own work before reporting success to the user.**
|
|
96
|
+
|
|
97
|
+
Every mutation (spawn, transform, property set, asset creation) must be followed by a verification step. Never ask the user to "check if that looks right" when you have tools to check it yourself.
|
|
98
|
+
|
|
99
|
+
## Verification Matrix
|
|
100
|
+
|
|
101
|
+
| After this action... | Verify with... |
|
|
102
|
+
|---|---|
|
|
103
|
+
| \`ue_spawn_actor\` | \`ue_get_component_bounds\` to confirm position, then \`ue_look_at\` to visually confirm |
|
|
104
|
+
| \`ue_transform_actor\` | \`ue_get_component_bounds\` — rotations can shift meshes relative to pivots |
|
|
105
|
+
| \`ue_set_actor_property\` (spatial) | \`ue_get_component_bounds\` for position/scale, \`ue_visual_review\` for visual properties |
|
|
106
|
+
| \`ue_set_actor_property\` (material/mesh) | \`ue_look_at\` or \`ue_visual_review\` to confirm visual result |
|
|
107
|
+
| \`ue_delete_actor\` | \`ue_list_actors\` to confirm removal |
|
|
108
|
+
| \`ue_create_data_asset\` / \`ue_create_curve\` | \`ue_query_assets\` to confirm creation |
|
|
109
|
+
| Any visual change | \`ue_visual_review\` or \`ue_look_at\` to see the result |
|
|
110
|
+
|
|
111
|
+
## The Inspect-Reason-Fix Cycle
|
|
112
|
+
|
|
113
|
+
When working with spatial placement (actors, components, doors, furniture):
|
|
114
|
+
|
|
115
|
+
1. **Act** — spawn, transform, or set property
|
|
116
|
+
2. **Measure** — \`ue_get_component_bounds\` to get exact numerical positions
|
|
117
|
+
3. **Reason** — do the bounds match expectations? Are components where they should be?
|
|
118
|
+
4. **Fix** — if not, adjust offsets/rotations to compensate
|
|
119
|
+
5. **Verify** — re-measure to confirm the fix worked
|
|
120
|
+
|
|
121
|
+
Repeat until all components are correctly positioned. Only THEN report success to the user.
|
|
122
|
+
|
|
123
|
+
## Common Spatial Pitfalls
|
|
124
|
+
|
|
125
|
+
- **Negative scale flips normals** — use 180-degree rotation instead of -1 scale to flip meshes
|
|
126
|
+
- **Rotations shift mesh position** — rotating around a pivot moves the mesh; always check bounds after rotation
|
|
127
|
+
- **Component offsets are relative** — a rotated parent changes where child offsets end up in world space
|
|
128
|
+
- **Collision doesn't auto-follow mesh** — if you move/rotate a mesh component, the collision component may need separate adjustment
|
|
129
|
+
|
|
130
|
+
## Visual Verification
|
|
131
|
+
|
|
132
|
+
For any change that affects what the user will SEE in the viewport:
|
|
133
|
+
1. Use \`ue_look_at\` to navigate the camera to the changed actor
|
|
134
|
+
2. Inspect the screenshot — check for: missing meshes, wrong orientation, clipping, z-fighting, scale issues
|
|
135
|
+
3. If something looks wrong, fix it BEFORE telling the user
|
|
136
|
+
|
|
137
|
+
## Cleanup
|
|
138
|
+
|
|
139
|
+
When a visual review session is complete, call \`ue_cleanup_screenshots(confirm=true)\` to free disk space.
|
|
140
|
+
`,
|
|
141
|
+
}],
|
|
142
|
+
}));
|
|
80
143
|
const transport = new StdioServerTransport();
|
|
81
144
|
await server.connect(transport);
|
|
82
145
|
log('Server ready — connected via stdio');
|
|
@@ -85,7 +85,7 @@ export function registerEditorTools(server, bridge) {
|
|
|
85
85
|
// --------------------------------------------------------------------------
|
|
86
86
|
server.registerTool('ue_spawn_actor', {
|
|
87
87
|
title: 'Spawn UE Actor',
|
|
88
|
-
description: '[requires_plugin] Spawn a new actor in the currently open UE Editor level at the specified location.',
|
|
88
|
+
description: '[requires_plugin] Spawn a new actor in the currently open UE Editor level at the specified location. After spawning, ALWAYS verify placement with ue_get_component_bounds or ue_look_at before reporting success to the user.',
|
|
89
89
|
inputSchema: z.object({
|
|
90
90
|
class_name: z.string().describe('The actor class to spawn (e.g., AStaticMeshActor)'),
|
|
91
91
|
location: z.object({
|
|
@@ -114,7 +114,7 @@ export function registerEditorTools(server, bridge) {
|
|
|
114
114
|
// --------------------------------------------------------------------------
|
|
115
115
|
server.registerTool('ue_set_actor_property', {
|
|
116
116
|
title: 'Set Actor Property',
|
|
117
|
-
description: '[requires_plugin] Set a UPROPERTY value on an actor by label. Supports bool, int, float, string, name, text, actor (reference by label), and asset (reference by path).',
|
|
117
|
+
description: '[requires_plugin] Set a UPROPERTY value on an actor by label. Supports bool, int, float, string, name, text, actor (reference by label), and asset (reference by path). After setting spatial properties (transforms, offsets, scale), verify the result with ue_get_component_bounds before reporting success.',
|
|
118
118
|
inputSchema: z.object({
|
|
119
119
|
actor_label: z.string().describe('The editor label of the target actor'),
|
|
120
120
|
property_name: z.string().describe('The UPROPERTY name to set (e.g., RoomID, RoomDoor, DoorCurve)'),
|
|
@@ -146,7 +146,7 @@ export function registerEditorTools(server, bridge) {
|
|
|
146
146
|
// --------------------------------------------------------------------------
|
|
147
147
|
server.registerTool('ue_create_data_asset', {
|
|
148
148
|
title: 'Create Data Asset',
|
|
149
|
-
description: '[requires_plugin] Create a UPrimaryDataAsset (or subclass) at the given path with reflection-set properties.',
|
|
149
|
+
description: '[requires_plugin] Create a UPrimaryDataAsset (or subclass) at the given path with reflection-set properties. After creation, verify the asset exists with ue_query_assets.',
|
|
150
150
|
inputSchema: z.object({
|
|
151
151
|
asset_path: z.string().describe('UE asset path, e.g. /Game/Data/DA_ValveHandle'),
|
|
152
152
|
class_name: z.string().describe('Asset class name, e.g. ItemDefinition'),
|
|
@@ -171,7 +171,7 @@ export function registerEditorTools(server, bridge) {
|
|
|
171
171
|
// --------------------------------------------------------------------------
|
|
172
172
|
server.registerTool('ue_create_curve', {
|
|
173
173
|
title: 'Create Float Curve',
|
|
174
|
-
description: '[requires_plugin] Create a UCurveFloat asset with keyframes at the given path.',
|
|
174
|
+
description: '[requires_plugin] Create a UCurveFloat asset with keyframes at the given path. After creation, verify the asset exists with ue_query_assets.',
|
|
175
175
|
inputSchema: z.object({
|
|
176
176
|
asset_path: z.string().describe('UE asset path, e.g. /Game/Curves/C_DoorSwing'),
|
|
177
177
|
keys: z.array(z.object({
|
|
@@ -195,7 +195,7 @@ export function registerEditorTools(server, bridge) {
|
|
|
195
195
|
// --------------------------------------------------------------------------
|
|
196
196
|
server.registerTool('ue_transform_actor', {
|
|
197
197
|
title: 'Transform UE Actor',
|
|
198
|
-
description: '[requires_plugin] Move, rotate, and/or scale an existing actor in the currently open UE Editor level.',
|
|
198
|
+
description: '[requires_plugin] Move, rotate, and/or scale an existing actor in the currently open UE Editor level. IMPORTANT: After transforming, always verify the result with ue_get_component_bounds (numerical check) or ue_look_at/ue_visual_review (visual check) before telling the user it worked. Rotations can shift meshes relative to pivots — always confirm final bounds.',
|
|
199
199
|
inputSchema: z.object({
|
|
200
200
|
actor_label: z.string().describe('The editor label of the actor to transform'),
|
|
201
201
|
location: z
|
|
@@ -242,7 +242,7 @@ export function registerEditorTools(server, bridge) {
|
|
|
242
242
|
// --------------------------------------------------------------------------
|
|
243
243
|
server.registerTool('ue_delete_actor', {
|
|
244
244
|
title: 'Delete UE Actor',
|
|
245
|
-
description: '[requires_plugin] Delete an actor from the currently open UE Editor level. This operation is destructive.',
|
|
245
|
+
description: '[requires_plugin] Delete an actor from the currently open UE Editor level. This operation is destructive. After deleting, verify with ue_list_actors that the actor is gone.',
|
|
246
246
|
inputSchema: z.object({
|
|
247
247
|
actor_label: z.string().describe('The editor label of the actor to delete'),
|
|
248
248
|
}),
|
|
@@ -428,7 +428,7 @@ export function registerViewportTools(server, bridge) {
|
|
|
428
428
|
// --------------------------------------------------------------------------
|
|
429
429
|
server.registerTool('ue_visual_review', {
|
|
430
430
|
title: 'Visual Review Screenshot',
|
|
431
|
-
description: '[requires_plugin] Take a quick viewport screenshot for visual review. Returns the image inline with camera context. Use this
|
|
431
|
+
description: '[requires_plugin] Take a quick viewport screenshot for visual review. Returns the image inline with camera context. Use this to VERIFY changes after any mutation (spawn, transform, property set). Always screenshot after making visual changes — do not ask the user to check manually.',
|
|
432
432
|
inputSchema: z.object({
|
|
433
433
|
width: z
|
|
434
434
|
.number()
|
|
@@ -662,7 +662,7 @@ export function registerViewportTools(server, bridge) {
|
|
|
662
662
|
// --------------------------------------------------------------------------
|
|
663
663
|
server.registerTool('ue_iterate_scene', {
|
|
664
664
|
title: 'Full Scene Context Snapshot',
|
|
665
|
-
description: '[requires_plugin] Get full visual and semantic context in one call. Takes a screenshot AND returns structured data about nearby actors. Use this to orient yourself — see what you are looking at and
|
|
665
|
+
description: '[requires_plugin] Get full visual and semantic context in one call. Takes a screenshot AND returns structured data about nearby actors. Use this to orient yourself and to verify complex multi-actor changes — see what you are looking at, what is nearby, and whether everything is in the right place.',
|
|
666
666
|
inputSchema: z.object({
|
|
667
667
|
width: z
|
|
668
668
|
.number()
|