ue-mcp 1.2.0 → 1.2.1
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/dist/context-cli.js +16 -16
- package/dist/engine-observer.js +68 -68
- package/dist/instructions.js +130 -130
- package/dist/manifest-signature.d.ts +1 -0
- package/dist/manifest-signature.js +53 -0
- package/dist/manifest-signature.js.map +1 -0
- package/dist/pie/schema.d.ts +791 -0
- package/dist/pie/schema.js +151 -0
- package/dist/pie/schema.js.map +1 -0
- package/dist/plugin-cli.js +299 -299
- package/dist/tool-counts.json +2 -2
- package/dist/watch-cli.js.map +1 -0
- package/package.json +6 -3
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/EngineStatusHooks.cpp +76 -76
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/EngineStatusHooks.h +27 -27
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/HandlerRegistry.cpp +128 -128
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/HandlerRegistry.h +63 -63
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_ControlRig.cpp +230 -230
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers.cpp +10 -32
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_BulkProperties.cpp +1 -21
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_BulkUpsert.cpp +3 -18
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_Mesh.cpp +1 -19
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_Struct.cpp +323 -323
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/BlueprintHandlers_Internal.h +20 -20
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/ChooserHandlers_Nested.cpp +537 -537
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/DemoHandlers.h +77 -77
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/EditorHandlers_Build.cpp +353 -353
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/FoliageHandlers.h +18 -18
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/GameplayHandlers_InputRuntime.cpp +246 -246
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/GasHandlers.cpp +597 -597
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/GasHandlers.h +51 -51
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LandscapeHandlers.cpp +878 -878
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LandscapeHandlers_Sculpt.cpp +449 -449
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/MaterialHandlers_Function.cpp +275 -275
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/MaterialHandlers_Graph.cpp +551 -551
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/NetworkingHandlers.cpp +531 -531
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/NetworkingHandlers.h +28 -28
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/PhysicsHandlers.cpp +677 -677
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/SequencerHandlers.cpp +822 -822
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/SequencerHandlers.h +22 -22
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/SplineHandlers.cpp +218 -218
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/SplineHandlers.h +17 -17
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/VolumeHelpers_Internal.cpp +46 -46
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/VolumeHelpers_Internal.h +23 -23
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/MCPExternalRegistry.cpp +83 -83
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Public/HandlerUtils.h +30 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Public/UE_MCP_BridgeModule.h +14 -14
- package/plugin/ue_mcp_bridge/Source/UE_MCP_BridgeStatus/Private/UE_MCP_BridgeStatusModule.cpp +37 -37
- /package/plugin/ue_mcp_bridge/{UE_MCP_Bridge.uplugin → ue_mcp_bridge.uplugin} +0 -0
package/dist/context-cli.js
CHANGED
|
@@ -21,20 +21,20 @@ const CYAN = "\x1b[36m";
|
|
|
21
21
|
const YELLOW = "\x1b[33m";
|
|
22
22
|
const ACTIONS = new Set(["full", "lean", "micro", "status"]);
|
|
23
23
|
function printHelp() {
|
|
24
|
-
console.log(`
|
|
25
|
-
${BOLD}${CYAN}ue-mcp context${RESET} - control the context seeding strategy
|
|
26
|
-
|
|
27
|
-
${BOLD}Usage:${RESET}
|
|
28
|
-
ue-mcp context show the current strategy
|
|
29
|
-
ue-mcp context status show the current strategy
|
|
30
|
-
ue-mcp context full every action inline (largest seed, default)
|
|
31
|
-
ue-mcp context lean action names visible, descriptions on demand
|
|
32
|
-
ue-mcp context micro one gateway tool fronts everything (smallest)
|
|
33
|
-
|
|
34
|
-
A project path may be passed as the last argument, or an editor named with
|
|
35
|
-
--editor <name-or-path>; otherwise the .uproject in the current directory is
|
|
36
|
-
used. Restart your MCP client (/mcp in Claude Code) after changing the
|
|
37
|
-
strategy.
|
|
24
|
+
console.log(`
|
|
25
|
+
${BOLD}${CYAN}ue-mcp context${RESET} - control the context seeding strategy
|
|
26
|
+
|
|
27
|
+
${BOLD}Usage:${RESET}
|
|
28
|
+
ue-mcp context show the current strategy
|
|
29
|
+
ue-mcp context status show the current strategy
|
|
30
|
+
ue-mcp context full every action inline (largest seed, default)
|
|
31
|
+
ue-mcp context lean action names visible, descriptions on demand
|
|
32
|
+
ue-mcp context micro one gateway tool fronts everything (smallest)
|
|
33
|
+
|
|
34
|
+
A project path may be passed as the last argument, or an editor named with
|
|
35
|
+
--editor <name-or-path>; otherwise the .uproject in the current directory is
|
|
36
|
+
used. Restart your MCP client (/mcp in Claude Code) after changing the
|
|
37
|
+
strategy.
|
|
38
38
|
`);
|
|
39
39
|
}
|
|
40
40
|
function parseArgs() {
|
|
@@ -50,8 +50,8 @@ function parseArgs() {
|
|
|
50
50
|
target = takeEditorTarget(argv);
|
|
51
51
|
}
|
|
52
52
|
catch (e) {
|
|
53
|
-
console.log(`
|
|
54
|
-
${RED}${e instanceof EditorFlagError ? e.message : String(e)}${RESET}
|
|
53
|
+
console.log(`
|
|
54
|
+
${RED}${e instanceof EditorFlagError ? e.message : String(e)}${RESET}
|
|
55
55
|
`);
|
|
56
56
|
process.exit(1);
|
|
57
57
|
}
|
package/dist/engine-observer.js
CHANGED
|
@@ -65,19 +65,19 @@ function classify(pid, commandLine, responding, windowTitle) {
|
|
|
65
65
|
// seconds (interpreter start ~1.5s, CIM ~4s, and `tasklist` is no cheaper), so
|
|
66
66
|
// the whole probe is a single script and callers reach it only when the fast
|
|
67
67
|
// signal - the bridge socket itself - has already failed.
|
|
68
|
-
const WINDOWS_PROCESS_SCRIPT = `
|
|
69
|
-
$ErrorActionPreference = 'SilentlyContinue'
|
|
70
|
-
$procs = Get-CimInstance Win32_Process -Filter "Name LIKE 'UnrealEditor%'"
|
|
71
|
-
$out = foreach ($p in $procs) {
|
|
72
|
-
$ps = Get-Process -Id $p.ProcessId -ErrorAction SilentlyContinue
|
|
73
|
-
[pscustomobject]@{
|
|
74
|
-
pid = $p.ProcessId
|
|
75
|
-
cmd = $p.CommandLine
|
|
76
|
-
responding = $(if ($ps) { [bool]$ps.Responding } else { $true })
|
|
77
|
-
title = $(if ($ps) { $ps.MainWindowTitle } else { '' })
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
@($out) | ConvertTo-Json -Compress -Depth 3
|
|
68
|
+
const WINDOWS_PROCESS_SCRIPT = `
|
|
69
|
+
$ErrorActionPreference = 'SilentlyContinue'
|
|
70
|
+
$procs = Get-CimInstance Win32_Process -Filter "Name LIKE 'UnrealEditor%'"
|
|
71
|
+
$out = foreach ($p in $procs) {
|
|
72
|
+
$ps = Get-Process -Id $p.ProcessId -ErrorAction SilentlyContinue
|
|
73
|
+
[pscustomobject]@{
|
|
74
|
+
pid = $p.ProcessId
|
|
75
|
+
cmd = $p.CommandLine
|
|
76
|
+
responding = $(if ($ps) { [bool]$ps.Responding } else { $true })
|
|
77
|
+
title = $(if ($ps) { $ps.MainWindowTitle } else { '' })
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
@($out) | ConvertTo-Json -Compress -Depth 3
|
|
81
81
|
`;
|
|
82
82
|
// The process table is polled from wait loops and status calls; a short TTL
|
|
83
83
|
// keeps a burst of callers from paying for the same query repeatedly, while
|
|
@@ -297,61 +297,61 @@ export function readLogState(projectPath, tailLines = 25) {
|
|
|
297
297
|
* so it can be read from outside even when the process is not pumping. This is
|
|
298
298
|
* the only way to see a dialog that appears before the plugin loads.
|
|
299
299
|
*/
|
|
300
|
-
const WINDOWS_DIALOG_SCRIPT = `
|
|
301
|
-
$ErrorActionPreference = 'SilentlyContinue'
|
|
302
|
-
$sig = @'
|
|
303
|
-
using System;
|
|
304
|
-
using System.Text;
|
|
305
|
-
using System.Runtime.InteropServices;
|
|
306
|
-
public class UeMcpWin {
|
|
307
|
-
public delegate bool EnumProc(IntPtr hWnd, IntPtr lParam);
|
|
308
|
-
[DllImport("user32.dll")] public static extern bool EnumWindows(EnumProc cb, IntPtr p);
|
|
309
|
-
[DllImport("user32.dll")] public static extern bool EnumChildWindows(IntPtr h, EnumProc cb, IntPtr p);
|
|
310
|
-
[DllImport("user32.dll", CharSet=CharSet.Unicode)] public static extern int GetWindowTextW(IntPtr h, StringBuilder s, int n);
|
|
311
|
-
[DllImport("user32.dll", CharSet=CharSet.Unicode)] public static extern int GetClassNameW(IntPtr h, StringBuilder s, int n);
|
|
312
|
-
[DllImport("user32.dll")] public static extern uint GetWindowThreadProcessId(IntPtr h, out uint pid);
|
|
313
|
-
[DllImport("user32.dll")] public static extern bool IsWindowVisible(IntPtr h);
|
|
314
|
-
[DllImport("user32.dll")] public static extern bool IsHungAppWindow(IntPtr h);
|
|
315
|
-
public static string Text(IntPtr h) {
|
|
316
|
-
StringBuilder sb = new StringBuilder(1024);
|
|
317
|
-
GetWindowTextW(h, sb, sb.Capacity);
|
|
318
|
-
return sb.ToString();
|
|
319
|
-
}
|
|
320
|
-
public static string Cls(IntPtr h) {
|
|
321
|
-
StringBuilder sb = new StringBuilder(256);
|
|
322
|
-
GetClassNameW(h, sb, sb.Capacity);
|
|
323
|
-
return sb.ToString();
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
'@
|
|
327
|
-
Add-Type -TypeDefinition $sig -Language CSharp | Out-Null
|
|
328
|
-
$targetPids = @(__PIDS__)
|
|
329
|
-
$results = New-Object System.Collections.ArrayList
|
|
330
|
-
$top = [UeMcpWin+EnumProc]{
|
|
331
|
-
param($h, $l)
|
|
332
|
-
$procId = 0
|
|
333
|
-
[void][UeMcpWin]::GetWindowThreadProcessId($h, [ref]$procId)
|
|
334
|
-
if ($targetPids -contains [int]$procId -and [UeMcpWin]::IsWindowVisible($h)) {
|
|
335
|
-
$children = New-Object System.Collections.ArrayList
|
|
336
|
-
$child = [UeMcpWin+EnumProc]{
|
|
337
|
-
param($c, $cl)
|
|
338
|
-
$t = [UeMcpWin]::Text($c)
|
|
339
|
-
if ($t -and $t.Trim().Length -gt 0) { [void]$children.Add($t) }
|
|
340
|
-
return $true
|
|
341
|
-
}
|
|
342
|
-
[void][UeMcpWin]::EnumChildWindows($h, $child, [IntPtr]::Zero)
|
|
343
|
-
[void]$results.Add([pscustomobject]@{
|
|
344
|
-
handle = $h.ToString()
|
|
345
|
-
className = [UeMcpWin]::Cls($h)
|
|
346
|
-
title = [UeMcpWin]::Text($h)
|
|
347
|
-
text = @($children)
|
|
348
|
-
hung = [bool][UeMcpWin]::IsHungAppWindow($h)
|
|
349
|
-
})
|
|
350
|
-
}
|
|
351
|
-
return $true
|
|
352
|
-
}
|
|
353
|
-
[void][UeMcpWin]::EnumWindows($top, [IntPtr]::Zero)
|
|
354
|
-
@($results) | ConvertTo-Json -Compress -Depth 4
|
|
300
|
+
const WINDOWS_DIALOG_SCRIPT = `
|
|
301
|
+
$ErrorActionPreference = 'SilentlyContinue'
|
|
302
|
+
$sig = @'
|
|
303
|
+
using System;
|
|
304
|
+
using System.Text;
|
|
305
|
+
using System.Runtime.InteropServices;
|
|
306
|
+
public class UeMcpWin {
|
|
307
|
+
public delegate bool EnumProc(IntPtr hWnd, IntPtr lParam);
|
|
308
|
+
[DllImport("user32.dll")] public static extern bool EnumWindows(EnumProc cb, IntPtr p);
|
|
309
|
+
[DllImport("user32.dll")] public static extern bool EnumChildWindows(IntPtr h, EnumProc cb, IntPtr p);
|
|
310
|
+
[DllImport("user32.dll", CharSet=CharSet.Unicode)] public static extern int GetWindowTextW(IntPtr h, StringBuilder s, int n);
|
|
311
|
+
[DllImport("user32.dll", CharSet=CharSet.Unicode)] public static extern int GetClassNameW(IntPtr h, StringBuilder s, int n);
|
|
312
|
+
[DllImport("user32.dll")] public static extern uint GetWindowThreadProcessId(IntPtr h, out uint pid);
|
|
313
|
+
[DllImport("user32.dll")] public static extern bool IsWindowVisible(IntPtr h);
|
|
314
|
+
[DllImport("user32.dll")] public static extern bool IsHungAppWindow(IntPtr h);
|
|
315
|
+
public static string Text(IntPtr h) {
|
|
316
|
+
StringBuilder sb = new StringBuilder(1024);
|
|
317
|
+
GetWindowTextW(h, sb, sb.Capacity);
|
|
318
|
+
return sb.ToString();
|
|
319
|
+
}
|
|
320
|
+
public static string Cls(IntPtr h) {
|
|
321
|
+
StringBuilder sb = new StringBuilder(256);
|
|
322
|
+
GetClassNameW(h, sb, sb.Capacity);
|
|
323
|
+
return sb.ToString();
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
'@
|
|
327
|
+
Add-Type -TypeDefinition $sig -Language CSharp | Out-Null
|
|
328
|
+
$targetPids = @(__PIDS__)
|
|
329
|
+
$results = New-Object System.Collections.ArrayList
|
|
330
|
+
$top = [UeMcpWin+EnumProc]{
|
|
331
|
+
param($h, $l)
|
|
332
|
+
$procId = 0
|
|
333
|
+
[void][UeMcpWin]::GetWindowThreadProcessId($h, [ref]$procId)
|
|
334
|
+
if ($targetPids -contains [int]$procId -and [UeMcpWin]::IsWindowVisible($h)) {
|
|
335
|
+
$children = New-Object System.Collections.ArrayList
|
|
336
|
+
$child = [UeMcpWin+EnumProc]{
|
|
337
|
+
param($c, $cl)
|
|
338
|
+
$t = [UeMcpWin]::Text($c)
|
|
339
|
+
if ($t -and $t.Trim().Length -gt 0) { [void]$children.Add($t) }
|
|
340
|
+
return $true
|
|
341
|
+
}
|
|
342
|
+
[void][UeMcpWin]::EnumChildWindows($h, $child, [IntPtr]::Zero)
|
|
343
|
+
[void]$results.Add([pscustomobject]@{
|
|
344
|
+
handle = $h.ToString()
|
|
345
|
+
className = [UeMcpWin]::Cls($h)
|
|
346
|
+
title = [UeMcpWin]::Text($h)
|
|
347
|
+
text = @($children)
|
|
348
|
+
hung = [bool][UeMcpWin]::IsHungAppWindow($h)
|
|
349
|
+
})
|
|
350
|
+
}
|
|
351
|
+
return $true
|
|
352
|
+
}
|
|
353
|
+
[void][UeMcpWin]::EnumWindows($top, [IntPtr]::Zero)
|
|
354
|
+
@($results) | ConvertTo-Json -Compress -Depth 4
|
|
355
355
|
`;
|
|
356
356
|
/**
|
|
357
357
|
* Visible top-level windows belonging to the given PIDs, with their child text.
|
package/dist/instructions.js
CHANGED
|
@@ -35,145 +35,145 @@ function categoryList() {
|
|
|
35
35
|
return lines.join("\n").replace(/\bepic\b(?![\w-])/, "epic (830 wrapped Unreal 5.8 tools; UE 5.8+)");
|
|
36
36
|
}
|
|
37
37
|
const CATEGORIES = categoryList();
|
|
38
|
-
export const SERVER_INSTRUCTIONS = `UE-MCP: Unreal Engine editor bridge (C++ plugin) - ${CATEGORY_COUNT} category tools covering ${ACTION_COUNT} actions, plus 830 official Unreal 5.8 tools wrapped in-process (UE 5.8+; see the epic category).
|
|
39
|
-
|
|
40
|
-
Every tool takes an "action" parameter that selects the operation. Call project(action="get_status") first.
|
|
41
|
-
|
|
42
|
-
═══ QUICK START ═══
|
|
43
|
-
1. project(action="get_status") - check if the editor is connected
|
|
44
|
-
2. If not connected: editor(action="start_editor") to launch UE
|
|
45
|
-
3. level(action="get_outliner") - see what's in the current level
|
|
46
|
-
4. asset(action="list") - browse project assets
|
|
47
|
-
5. reflection(action="reflect_class", className="StaticMeshActor") - understand any UE class
|
|
48
|
-
6. demo(action="step", stepIndex=1) through 19 - run the Neon Shrine demo to see the bridge in action
|
|
49
|
-
7. demo(action="cleanup") - clean up after the demo
|
|
50
|
-
|
|
51
|
-
═══ TOOLS ═══
|
|
52
|
-
|
|
53
|
-
Every category tool lists its own actions (and each action's parameters) in
|
|
54
|
-
its description - read the description of the category you need. Categories:
|
|
55
|
-
${CATEGORIES}.
|
|
56
|
-
|
|
57
|
-
═══ TIPS ═══
|
|
58
|
-
• Start with level(action="get_outliner") or asset(action="list") to discover what's in the project.
|
|
59
|
-
• Use reflection(action="reflect_class") to understand any UE class's properties.
|
|
60
|
-
• asset(action="search", query="/Game/Characters/*") accepts wildcards.
|
|
61
|
-
• For BP scripting: blueprint(action="search_node_types") → blueprint(action="add_node") → blueprint(action="connect_pins").
|
|
62
|
-
• editor(action="execute_python") is the escape hatch for any Unreal Python API call.
|
|
63
|
-
• Animation tools need a skeleton path - use animation(action="list_skeletal_meshes") to find it.
|
|
64
|
-
• Editor lifecycle: editor(action="stop_editor") / editor(action="start_editor") / editor(action="restart_editor") manage the UE process. editor(action="build_project") builds the project C++ code (stop the editor first).
|
|
65
|
-
• editor(action="hot_reload") triggers Live Coding compilation without restarting the editor.
|
|
66
|
-
• editor(action="focus_on_actor", actorLabel="MyActor") snaps the viewport to any actor.
|
|
67
|
-
• Log output: editor(action="get_log", category="LogMCPBridge") to see bridge-specific logs.
|
|
68
|
-
|
|
69
|
-
═══ FLOWS - READ BEFORE ACTING ═══
|
|
70
|
-
|
|
71
|
-
Before you run bash/npm commands or chain 3+ category tool calls to
|
|
72
|
-
satisfy a user request, look at the \`flows\` field returned by
|
|
73
|
-
project(action="get_status").
|
|
74
|
-
|
|
75
|
-
That field lists named, pre-built sequences for this project. Each
|
|
76
|
-
entry has a name and description. If ANY flow's description matches
|
|
77
|
-
what the user asked for, you MUST run it instead of building the
|
|
78
|
-
sequence yourself.
|
|
79
|
-
|
|
80
|
-
Examples:
|
|
81
|
-
User asks | Look for a flow like
|
|
82
|
-
---------------------------------- | ------------------------------
|
|
83
|
-
"rebuild and relaunch the editor" | rebuild
|
|
84
|
-
"run the smoke tests" | smoke
|
|
85
|
-
"redeploy the plugin" | deploy, redeploy
|
|
86
|
-
"package the project" | package
|
|
87
|
-
|
|
88
|
-
Run a matched flow with: flow(action="run", flowName="<name>")
|
|
89
|
-
|
|
90
|
-
DO NOT:
|
|
91
|
-
- Skip the get_status flows check before running bash/npm yourself.
|
|
92
|
-
- Author a new flow on your own. Only the user authors flows.
|
|
93
|
-
- Suggest a flow for a one-off task the user is unlikely to repeat.
|
|
94
|
-
|
|
95
|
-
DO suggest a new flow IF AND ONLY IF all three are true:
|
|
96
|
-
1. You just finished a sequence with 3+ steps.
|
|
97
|
-
2. The sequence had the same shape every run, with only 1-2 values
|
|
98
|
-
changing.
|
|
99
|
-
3. The user is likely to ask for the same shape again.
|
|
100
|
-
In that case say: "This sequence (X -> Y -> Z) might be worth registering
|
|
101
|
-
as a flow in ue-mcp.yml. Want me to draft one?" Then STOP. Wait.
|
|
102
|
-
|
|
103
|
-
═══ FEEDBACK ═══
|
|
104
|
-
If you had to use editor(action="execute_python") as a workaround because a native tool
|
|
105
|
-
couldn't handle the task, keep a mental note of what you did and why. When your task is
|
|
106
|
-
complete, tell the user:
|
|
107
|
-
"I had to use custom Python scripts to [describe what]. Would you like to submit
|
|
108
|
-
feedback to help improve ue-mcp?"
|
|
109
|
-
If the user agrees, call feedback(action="submit") with:
|
|
110
|
-
• title - short, generic description of the gap (no project-specific details)
|
|
111
|
-
• summary - what was attempted and why the native tool fell short
|
|
112
|
-
• pythonWorkaround - the Python code that was used
|
|
113
|
-
• idealTool - what tool/action should handle this natively
|
|
114
|
-
This creates a GitHub issue so the maintainers can add proper support.
|
|
115
|
-
|
|
116
|
-
Not every gap belongs to ue-mcp core. Plugins (PIE Studio, Perforce, Meshy, ...)
|
|
117
|
-
own their own surfaces and their own trackers. submit checks the plugin registry
|
|
118
|
-
and aims the issue at the owning repo on its own, and the approval prompt lets
|
|
119
|
-
the user change it - do NOT set the repo parameter yourself unless the user
|
|
120
|
-
names a repo. feedback(action="route") answers "where would this land?" without
|
|
121
|
-
posting anything.
|
|
38
|
+
export const SERVER_INSTRUCTIONS = `UE-MCP: Unreal Engine editor bridge (C++ plugin) - ${CATEGORY_COUNT} category tools covering ${ACTION_COUNT} actions, plus 830 official Unreal 5.8 tools wrapped in-process (UE 5.8+; see the epic category).
|
|
39
|
+
|
|
40
|
+
Every tool takes an "action" parameter that selects the operation. Call project(action="get_status") first.
|
|
41
|
+
|
|
42
|
+
═══ QUICK START ═══
|
|
43
|
+
1. project(action="get_status") - check if the editor is connected
|
|
44
|
+
2. If not connected: editor(action="start_editor") to launch UE
|
|
45
|
+
3. level(action="get_outliner") - see what's in the current level
|
|
46
|
+
4. asset(action="list") - browse project assets
|
|
47
|
+
5. reflection(action="reflect_class", className="StaticMeshActor") - understand any UE class
|
|
48
|
+
6. demo(action="step", stepIndex=1) through 19 - run the Neon Shrine demo to see the bridge in action
|
|
49
|
+
7. demo(action="cleanup") - clean up after the demo
|
|
50
|
+
|
|
51
|
+
═══ TOOLS ═══
|
|
52
|
+
|
|
53
|
+
Every category tool lists its own actions (and each action's parameters) in
|
|
54
|
+
its description - read the description of the category you need. Categories:
|
|
55
|
+
${CATEGORIES}.
|
|
56
|
+
|
|
57
|
+
═══ TIPS ═══
|
|
58
|
+
• Start with level(action="get_outliner") or asset(action="list") to discover what's in the project.
|
|
59
|
+
• Use reflection(action="reflect_class") to understand any UE class's properties.
|
|
60
|
+
• asset(action="search", query="/Game/Characters/*") accepts wildcards.
|
|
61
|
+
• For BP scripting: blueprint(action="search_node_types") → blueprint(action="add_node") → blueprint(action="connect_pins").
|
|
62
|
+
• editor(action="execute_python") is the escape hatch for any Unreal Python API call.
|
|
63
|
+
• Animation tools need a skeleton path - use animation(action="list_skeletal_meshes") to find it.
|
|
64
|
+
• Editor lifecycle: editor(action="stop_editor") / editor(action="start_editor") / editor(action="restart_editor") manage the UE process. editor(action="build_project") builds the project C++ code (stop the editor first).
|
|
65
|
+
• editor(action="hot_reload") triggers Live Coding compilation without restarting the editor.
|
|
66
|
+
• editor(action="focus_on_actor", actorLabel="MyActor") snaps the viewport to any actor.
|
|
67
|
+
• Log output: editor(action="get_log", category="LogMCPBridge") to see bridge-specific logs.
|
|
68
|
+
|
|
69
|
+
═══ FLOWS - READ BEFORE ACTING ═══
|
|
70
|
+
|
|
71
|
+
Before you run bash/npm commands or chain 3+ category tool calls to
|
|
72
|
+
satisfy a user request, look at the \`flows\` field returned by
|
|
73
|
+
project(action="get_status").
|
|
74
|
+
|
|
75
|
+
That field lists named, pre-built sequences for this project. Each
|
|
76
|
+
entry has a name and description. If ANY flow's description matches
|
|
77
|
+
what the user asked for, you MUST run it instead of building the
|
|
78
|
+
sequence yourself.
|
|
79
|
+
|
|
80
|
+
Examples:
|
|
81
|
+
User asks | Look for a flow like
|
|
82
|
+
---------------------------------- | ------------------------------
|
|
83
|
+
"rebuild and relaunch the editor" | rebuild
|
|
84
|
+
"run the smoke tests" | smoke
|
|
85
|
+
"redeploy the plugin" | deploy, redeploy
|
|
86
|
+
"package the project" | package
|
|
87
|
+
|
|
88
|
+
Run a matched flow with: flow(action="run", flowName="<name>")
|
|
89
|
+
|
|
90
|
+
DO NOT:
|
|
91
|
+
- Skip the get_status flows check before running bash/npm yourself.
|
|
92
|
+
- Author a new flow on your own. Only the user authors flows.
|
|
93
|
+
- Suggest a flow for a one-off task the user is unlikely to repeat.
|
|
94
|
+
|
|
95
|
+
DO suggest a new flow IF AND ONLY IF all three are true:
|
|
96
|
+
1. You just finished a sequence with 3+ steps.
|
|
97
|
+
2. The sequence had the same shape every run, with only 1-2 values
|
|
98
|
+
changing.
|
|
99
|
+
3. The user is likely to ask for the same shape again.
|
|
100
|
+
In that case say: "This sequence (X -> Y -> Z) might be worth registering
|
|
101
|
+
as a flow in ue-mcp.yml. Want me to draft one?" Then STOP. Wait.
|
|
102
|
+
|
|
103
|
+
═══ FEEDBACK ═══
|
|
104
|
+
If you had to use editor(action="execute_python") as a workaround because a native tool
|
|
105
|
+
couldn't handle the task, keep a mental note of what you did and why. When your task is
|
|
106
|
+
complete, tell the user:
|
|
107
|
+
"I had to use custom Python scripts to [describe what]. Would you like to submit
|
|
108
|
+
feedback to help improve ue-mcp?"
|
|
109
|
+
If the user agrees, call feedback(action="submit") with:
|
|
110
|
+
• title - short, generic description of the gap (no project-specific details)
|
|
111
|
+
• summary - what was attempted and why the native tool fell short
|
|
112
|
+
• pythonWorkaround - the Python code that was used
|
|
113
|
+
• idealTool - what tool/action should handle this natively
|
|
114
|
+
This creates a GitHub issue so the maintainers can add proper support.
|
|
115
|
+
|
|
116
|
+
Not every gap belongs to ue-mcp core. Plugins (PIE Studio, Perforce, Meshy, ...)
|
|
117
|
+
own their own surfaces and their own trackers. submit checks the plugin registry
|
|
118
|
+
and aims the issue at the owning repo on its own, and the approval prompt lets
|
|
119
|
+
the user change it - do NOT set the repo parameter yourself unless the user
|
|
120
|
+
names a repo. feedback(action="route") answers "where would this land?" without
|
|
121
|
+
posting anything.
|
|
122
122
|
`;
|
|
123
123
|
// Compact instructions used when context.strategy = "lean". The per-action
|
|
124
124
|
// catalog is intentionally omitted: agents pull it on demand via the `catalog`
|
|
125
125
|
// tool or a category's `describe` action. This keeps the initialize handshake
|
|
126
126
|
// small for token-constrained clients while preserving full capability.
|
|
127
|
-
export const SERVER_INSTRUCTIONS_LEAN = `UE-MCP (lean mode): Unreal Engine editor bridge (C++ plugin). ${CATEGORY_COUNT} category tools covering ${ACTION_COUNT} actions; the per-action catalog is loaded on demand to keep context small.
|
|
128
|
-
|
|
129
|
-
Every tool takes an "action" parameter that selects the operation. Start with project(action="get_status").
|
|
130
|
-
|
|
131
|
-
═══ DISCOVER ACTIONS ═══
|
|
132
|
-
Tool descriptions are trimmed in lean mode. Find the action you need with:
|
|
133
|
-
- catalog(action="search", query="spawn actor") - rank matching actions across every category
|
|
134
|
-
- catalog(action="list_categories") - the ${CATEGORY_COUNT} categories with one-line summaries
|
|
135
|
-
- <category>(action="describe") - every action in one category (e.g. blueprint(action="describe"))
|
|
136
|
-
|
|
137
|
-
Each category's "action" parameter is still a validated enum, so unknown actions are rejected up front. Call describe/search first when you are unsure of the exact action name.
|
|
138
|
-
|
|
139
|
-
═══ CATEGORIES ═══
|
|
140
|
-
${CATEGORIES}.
|
|
141
|
-
|
|
142
|
-
═══ FLOWS ═══
|
|
143
|
-
Before chaining 3+ tool calls, check the \`flows\` field from project(action="get_status")
|
|
144
|
-
and run a matching flow with flow(action="run", flowName="<name>") instead of rebuilding it.
|
|
145
|
-
|
|
146
|
-
═══ FEEDBACK ═══
|
|
147
|
-
If you had to fall back to editor(action="execute_python") because a native tool could not
|
|
148
|
-
do the job, tell the user when done and offer to feedback(action="submit") the gap. submit
|
|
149
|
-
routes the issue to the tracker that owns the surface (core, or the plugin that provides it)
|
|
150
|
-
by checking the plugin registry; feedback(action="route") previews that without posting.
|
|
151
|
-
|
|
152
|
-
Full mode (every action listed inline) is the default. This lean surface is selected by
|
|
153
|
-
context.strategy: lean in ue-mcp.yml or UE_MCP_CONTEXT_STRATEGY=lean.
|
|
127
|
+
export const SERVER_INSTRUCTIONS_LEAN = `UE-MCP (lean mode): Unreal Engine editor bridge (C++ plugin). ${CATEGORY_COUNT} category tools covering ${ACTION_COUNT} actions; the per-action catalog is loaded on demand to keep context small.
|
|
128
|
+
|
|
129
|
+
Every tool takes an "action" parameter that selects the operation. Start with project(action="get_status").
|
|
130
|
+
|
|
131
|
+
═══ DISCOVER ACTIONS ═══
|
|
132
|
+
Tool descriptions are trimmed in lean mode. Find the action you need with:
|
|
133
|
+
- catalog(action="search", query="spawn actor") - rank matching actions across every category
|
|
134
|
+
- catalog(action="list_categories") - the ${CATEGORY_COUNT} categories with one-line summaries
|
|
135
|
+
- <category>(action="describe") - every action in one category (e.g. blueprint(action="describe"))
|
|
136
|
+
|
|
137
|
+
Each category's "action" parameter is still a validated enum, so unknown actions are rejected up front. Call describe/search first when you are unsure of the exact action name.
|
|
138
|
+
|
|
139
|
+
═══ CATEGORIES ═══
|
|
140
|
+
${CATEGORIES}.
|
|
141
|
+
|
|
142
|
+
═══ FLOWS ═══
|
|
143
|
+
Before chaining 3+ tool calls, check the \`flows\` field from project(action="get_status")
|
|
144
|
+
and run a matching flow with flow(action="run", flowName="<name>") instead of rebuilding it.
|
|
145
|
+
|
|
146
|
+
═══ FEEDBACK ═══
|
|
147
|
+
If you had to fall back to editor(action="execute_python") because a native tool could not
|
|
148
|
+
do the job, tell the user when done and offer to feedback(action="submit") the gap. submit
|
|
149
|
+
routes the issue to the tracker that owns the surface (core, or the plugin that provides it)
|
|
150
|
+
by checking the plugin registry; feedback(action="route") previews that without posting.
|
|
151
|
+
|
|
152
|
+
Full mode (every action listed inline) is the default. This lean surface is selected by
|
|
153
|
+
context.strategy: lean in ue-mcp.yml or UE_MCP_CONTEXT_STRATEGY=lean.
|
|
154
154
|
`;
|
|
155
155
|
// Smallest surface (context.strategy = "micro"). The entire ue-mcp API is
|
|
156
156
|
// reached through one gateway tool, mirroring the native MCP toolset gateway
|
|
157
157
|
// (list_toolsets / describe_toolset / call_tool). Nothing else is advertised.
|
|
158
|
-
export const SERVER_INSTRUCTIONS_MICRO = `UE-MCP (micro mode): Unreal Engine editor bridge (C++ plugin). The entire surface (${CATEGORY_COUNT} categories, ${ACTION_COUNT} actions) is reached through a single gateway tool to keep context tiny.
|
|
159
|
-
|
|
160
|
-
═══ HOW TO USE ═══
|
|
161
|
-
- tools(action="list_categories") - list every category with a one-line summary
|
|
162
|
-
- tools(action="describe", category="blueprint") - list a category's actions and how to call them
|
|
163
|
-
- tools(action="call", category="blueprint", method="create", args={ ... }) - invoke any action
|
|
164
|
-
|
|
165
|
-
\`method\` is the action name; \`args\` is the object of that action's parameters.
|
|
166
|
-
Start with: tools(action="call", category="project", method="get_status").
|
|
167
|
-
|
|
168
|
-
═══ CATEGORIES ═══
|
|
169
|
-
${CATEGORIES}.
|
|
170
|
-
|
|
171
|
-
═══ FLOWS ═══
|
|
172
|
-
flow(action="run", flowName="<name>") runs a named sequence; see the \`flows\` field
|
|
173
|
-
from tools(action="call", category="project", method="get_status").
|
|
174
|
-
|
|
175
|
-
Full mode (every action listed inline) is the default. This micro surface is selected by
|
|
176
|
-
context.strategy: micro in ue-mcp.yml or UE_MCP_CONTEXT_STRATEGY=micro.
|
|
158
|
+
export const SERVER_INSTRUCTIONS_MICRO = `UE-MCP (micro mode): Unreal Engine editor bridge (C++ plugin). The entire surface (${CATEGORY_COUNT} categories, ${ACTION_COUNT} actions) is reached through a single gateway tool to keep context tiny.
|
|
159
|
+
|
|
160
|
+
═══ HOW TO USE ═══
|
|
161
|
+
- tools(action="list_categories") - list every category with a one-line summary
|
|
162
|
+
- tools(action="describe", category="blueprint") - list a category's actions and how to call them
|
|
163
|
+
- tools(action="call", category="blueprint", method="create", args={ ... }) - invoke any action
|
|
164
|
+
|
|
165
|
+
\`method\` is the action name; \`args\` is the object of that action's parameters.
|
|
166
|
+
Start with: tools(action="call", category="project", method="get_status").
|
|
167
|
+
|
|
168
|
+
═══ CATEGORIES ═══
|
|
169
|
+
${CATEGORIES}.
|
|
170
|
+
|
|
171
|
+
═══ FLOWS ═══
|
|
172
|
+
flow(action="run", flowName="<name>") runs a named sequence; see the \`flows\` field
|
|
173
|
+
from tools(action="call", category="project", method="get_status").
|
|
174
|
+
|
|
175
|
+
Full mode (every action listed inline) is the default. This micro surface is selected by
|
|
176
|
+
context.strategy: micro in ue-mcp.yml or UE_MCP_CONTEXT_STRATEGY=micro.
|
|
177
177
|
`;
|
|
178
178
|
/**
|
|
179
179
|
* Targeting block, appended to whichever instruction variant is in use, and
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function loadAppManifestSignature(): string;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
/**
|
|
5
|
+
* Runtime loader for the credential used by the anonymous feedback-bot path
|
|
6
|
+
* in src/github-app.ts (the `useBot=true` submit route).
|
|
7
|
+
*
|
|
8
|
+
* For human readers: this is the same GitHub App installation credential that
|
|
9
|
+
* used to be a string literal in src/github-app.ts. Its only scope is
|
|
10
|
+
* issues:write on db-lyon/ue-mcp. The blast radius of a leak is "agent files
|
|
11
|
+
* a noise issue against the public tracker" — not credential exposure of any
|
|
12
|
+
* sensitive system. The team accepts that.
|
|
13
|
+
*
|
|
14
|
+
* The reason for keeping it in a binary asset rather than as source: agents
|
|
15
|
+
* working in this repo will routinely read files and grep for credential-
|
|
16
|
+
* shaped identifiers while orienting. Surfacing a 27-line literal on every
|
|
17
|
+
* casual read defeats the consent gate in feedback(submit) by giving the
|
|
18
|
+
* agent an out-of-band path to the GitHub API. Moving the bytes into an
|
|
19
|
+
* XOR'd binary blob removes that affordance for non-targeted inspection.
|
|
20
|
+
*
|
|
21
|
+
* This is not a security boundary. The XOR cycle constant lives next to the
|
|
22
|
+
* blob in the same published package; a determined human reading both can
|
|
23
|
+
* decode in seconds. The goal is to defeat lazy AI inspection, not human
|
|
24
|
+
* reverse engineering.
|
|
25
|
+
*
|
|
26
|
+
* The longer-term plan is to move bot submission server-side so this loader
|
|
27
|
+
* goes away entirely — see https://github.com/db-lyon/ue-mcp/issues/461.
|
|
28
|
+
* No ETA. Until then, this is the bar.
|
|
29
|
+
*
|
|
30
|
+
* Rotation: generate a new credential, save the encoded form to a local file,
|
|
31
|
+
* then run `node scripts/encode-installation-key.mjs <path>`. Commit the
|
|
32
|
+
* regenerated assets/installation.bin; never commit the raw source form.
|
|
33
|
+
*/
|
|
34
|
+
const CYCLE = "ue-mcp-feedback/installation-key-v1";
|
|
35
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
36
|
+
const __dirname = path.dirname(__filename);
|
|
37
|
+
// Compiled output lives in dist/, blob lives at repo root under assets/.
|
|
38
|
+
// Resolve relative to this module so it works for both `tsx src/...` (dev)
|
|
39
|
+
// and `node dist/...` (published).
|
|
40
|
+
const BLOB_PATH = path.resolve(__dirname, "..", "assets", "installation.bin");
|
|
41
|
+
let cached = null;
|
|
42
|
+
export function loadAppManifestSignature() {
|
|
43
|
+
if (cached !== null)
|
|
44
|
+
return cached;
|
|
45
|
+
const blob = fs.readFileSync(BLOB_PATH);
|
|
46
|
+
const out = Buffer.alloc(blob.length);
|
|
47
|
+
for (let i = 0; i < blob.length; i++) {
|
|
48
|
+
out[i] = blob[i] ^ CYCLE.charCodeAt(i % CYCLE.length);
|
|
49
|
+
}
|
|
50
|
+
cached = out.toString("utf-8");
|
|
51
|
+
return cached;
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=manifest-signature.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest-signature.js","sourceRoot":"","sources":["../src/manifest-signature.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,MAAM,KAAK,GAAG,qCAAqC,CAAC;AAEpD,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;AAE3C,yEAAyE;AACzE,2EAA2E;AAC3E,mCAAmC;AACnC,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,IAAI,EAAE,QAAQ,EAAE,kBAAkB,CAAC,CAAC;AAE9E,IAAI,MAAM,GAAkB,IAAI,CAAC;AAEjC,MAAM,UAAU,wBAAwB;IACtC,IAAI,MAAM,KAAK,IAAI;QAAE,OAAO,MAAM,CAAC;IACnC,MAAM,IAAI,GAAG,EAAE,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC;IACxC,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACtC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,GAAG,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,UAAU,CAAC,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC;IACxD,CAAC;IACD,MAAM,GAAG,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IAC/B,OAAO,MAAM,CAAC;AAChB,CAAC"}
|