ue-mcp 1.2.1 → 1.2.2
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/flow/guard.d.ts +26 -37
- package/dist/flow/guard.js +40 -25
- package/dist/flow/guard.js.map +1 -1
- package/dist/flow/guarded-bridge.d.ts +0 -10
- package/dist/flow/guarded-bridge.js +18 -23
- package/dist/flow/guarded-bridge.js.map +1 -1
- package/dist/flow/schema.d.ts +276 -16
- package/dist/flow/task-guards.d.ts +1 -1
- package/dist/flow/task-guards.js +44 -68
- package/dist/flow/task-guards.js.map +1 -1
- package/dist/instructions.js +130 -130
- package/dist/plugin-cli.js +299 -299
- package/dist/tool-counts.json +2 -2
- package/package.json +2 -2
- 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_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/UE_MCP_BridgeModule.h +14 -14
- package/plugin/ue_mcp_bridge/Source/UE_MCP_BridgeStatus/Private/UE_MCP_BridgeStatusModule.cpp +37 -37
- package/dist/manifest-signature.d.ts +0 -1
- package/dist/manifest-signature.js +0 -53
- package/dist/manifest-signature.js.map +0 -1
- package/dist/pie/schema.d.ts +0 -791
- package/dist/pie/schema.js +0 -151
- package/dist/pie/schema.js.map +0 -1
- package/dist/watch-cli.js.map +0 -1
- /package/plugin/ue_mcp_bridge/{ue_mcp_bridge.uplugin → UE_MCP_Bridge.uplugin} +0 -0
package/dist/plugin-cli.js
CHANGED
|
@@ -478,117 +478,117 @@ function writeScaffold(dir, pkgName, prefix) {
|
|
|
478
478
|
include: ["src/**/*"],
|
|
479
479
|
};
|
|
480
480
|
fs.writeFileSync(path.join(dir, "tsconfig.json"), JSON.stringify(tsconfig, null, 2) + "\n");
|
|
481
|
-
const manifestYaml = `actionPrefix: ${prefix}
|
|
482
|
-
minServerVersion: ${minServer}
|
|
483
|
-
|
|
484
|
-
# This scaffold is a SUPERSET: it shows every way a plugin can extend ue-mcp.
|
|
485
|
-
# Keep the shapes you need and delete the rest.
|
|
486
|
-
# 1) inject - add actions onto a built-in category (names are prefixed)
|
|
487
|
-
# 2) provides - own a brand-new top-level category (names are NOT prefixed)
|
|
488
|
-
# 3) flows - chain tasks/actions into one orchestrated call
|
|
489
|
-
# 4) nativeModule (commented, at the bottom) - ship C++ handlers on the bridge
|
|
490
|
-
|
|
491
|
-
# 1) inject: '${prefix}_hello' lands on the built-in 'project' tool, reached as
|
|
492
|
-
# project(action="${prefix}_hello").
|
|
493
|
-
inject:
|
|
494
|
-
project:
|
|
495
|
-
hello:
|
|
496
|
-
task: ${prefix}.hello
|
|
497
|
-
description: "Greet by name - a stand-in inject action this scaffold ships with"
|
|
498
|
-
schema:
|
|
499
|
-
name: { type: string, description: "Who to greet (default: world)" }
|
|
500
|
-
|
|
501
|
-
# 2) provides: a category the plugin owns. Actions are NOT prefixed - the
|
|
502
|
-
# category name is the namespace, e.g. ${prefix}(action="greet").
|
|
503
|
-
provides:
|
|
504
|
-
${prefix}:
|
|
505
|
-
description: "${pkgName} - example plugin-owned category"
|
|
506
|
-
actions:
|
|
507
|
-
greet:
|
|
508
|
-
task: ${prefix}.greet
|
|
509
|
-
description: "Greet by name from a plugin-owned category"
|
|
510
|
-
schema:
|
|
511
|
-
name: { type: string, description: "Who to greet (default: world)" }
|
|
512
|
-
|
|
513
|
-
tasks:
|
|
514
|
-
${prefix}.hello:
|
|
515
|
-
class_path: tasks/${helloClass}
|
|
516
|
-
${prefix}.greet:
|
|
517
|
-
class_path: tasks/${greetClass}
|
|
518
|
-
|
|
519
|
-
# 3) flows: chain tasks/actions into one call. This one just runs the hello
|
|
520
|
-
# task; expand 'steps' to orchestrate real multi-step work.
|
|
521
|
-
flows:
|
|
522
|
-
${prefix}_demo:
|
|
523
|
-
description: "Example flow: run the hello task"
|
|
524
|
-
steps:
|
|
525
|
-
1:
|
|
526
|
-
task: ${prefix}.hello
|
|
527
|
-
options:
|
|
528
|
-
name: world
|
|
529
|
-
|
|
530
|
-
# 4) nativeModule: ship C++ handlers that register on the bridge. DORMANT by
|
|
531
|
-
# default - the C++ skeleton already lives under ue/Plugins/${uePlugin}/, but
|
|
532
|
-
# it is not deployed or compiled until you UNCOMMENT this block. Activating it
|
|
533
|
-
# makes 'ue-mcp plugin install' deploy the module and require a UE rebuild.
|
|
534
|
-
# The handlers then surface unprefixed under a '${nativeCategory}' category,
|
|
535
|
-
# e.g. ${nativeCategory}(action="echo").
|
|
536
|
-
# nativeModule:
|
|
537
|
-
# uePluginName: ${uePlugin}
|
|
538
|
-
# minBridgeApi: 1
|
|
539
|
-
# source: ue/Plugins/${uePlugin}
|
|
540
|
-
# category: ${nativeCategory}
|
|
541
|
-
# categoryDescription: "${pkgName} native C++ handlers"
|
|
542
|
-
# handlers:
|
|
543
|
-
# echo:
|
|
544
|
-
# description: "Echo a name back from native C++ (required: name)"
|
|
545
|
-
# schema:
|
|
546
|
-
# name: { type: string, description: "Name to echo" }
|
|
481
|
+
const manifestYaml = `actionPrefix: ${prefix}
|
|
482
|
+
minServerVersion: ${minServer}
|
|
483
|
+
|
|
484
|
+
# This scaffold is a SUPERSET: it shows every way a plugin can extend ue-mcp.
|
|
485
|
+
# Keep the shapes you need and delete the rest.
|
|
486
|
+
# 1) inject - add actions onto a built-in category (names are prefixed)
|
|
487
|
+
# 2) provides - own a brand-new top-level category (names are NOT prefixed)
|
|
488
|
+
# 3) flows - chain tasks/actions into one orchestrated call
|
|
489
|
+
# 4) nativeModule (commented, at the bottom) - ship C++ handlers on the bridge
|
|
490
|
+
|
|
491
|
+
# 1) inject: '${prefix}_hello' lands on the built-in 'project' tool, reached as
|
|
492
|
+
# project(action="${prefix}_hello").
|
|
493
|
+
inject:
|
|
494
|
+
project:
|
|
495
|
+
hello:
|
|
496
|
+
task: ${prefix}.hello
|
|
497
|
+
description: "Greet by name - a stand-in inject action this scaffold ships with"
|
|
498
|
+
schema:
|
|
499
|
+
name: { type: string, description: "Who to greet (default: world)" }
|
|
500
|
+
|
|
501
|
+
# 2) provides: a category the plugin owns. Actions are NOT prefixed - the
|
|
502
|
+
# category name is the namespace, e.g. ${prefix}(action="greet").
|
|
503
|
+
provides:
|
|
504
|
+
${prefix}:
|
|
505
|
+
description: "${pkgName} - example plugin-owned category"
|
|
506
|
+
actions:
|
|
507
|
+
greet:
|
|
508
|
+
task: ${prefix}.greet
|
|
509
|
+
description: "Greet by name from a plugin-owned category"
|
|
510
|
+
schema:
|
|
511
|
+
name: { type: string, description: "Who to greet (default: world)" }
|
|
512
|
+
|
|
513
|
+
tasks:
|
|
514
|
+
${prefix}.hello:
|
|
515
|
+
class_path: tasks/${helloClass}
|
|
516
|
+
${prefix}.greet:
|
|
517
|
+
class_path: tasks/${greetClass}
|
|
518
|
+
|
|
519
|
+
# 3) flows: chain tasks/actions into one call. This one just runs the hello
|
|
520
|
+
# task; expand 'steps' to orchestrate real multi-step work.
|
|
521
|
+
flows:
|
|
522
|
+
${prefix}_demo:
|
|
523
|
+
description: "Example flow: run the hello task"
|
|
524
|
+
steps:
|
|
525
|
+
1:
|
|
526
|
+
task: ${prefix}.hello
|
|
527
|
+
options:
|
|
528
|
+
name: world
|
|
529
|
+
|
|
530
|
+
# 4) nativeModule: ship C++ handlers that register on the bridge. DORMANT by
|
|
531
|
+
# default - the C++ skeleton already lives under ue/Plugins/${uePlugin}/, but
|
|
532
|
+
# it is not deployed or compiled until you UNCOMMENT this block. Activating it
|
|
533
|
+
# makes 'ue-mcp plugin install' deploy the module and require a UE rebuild.
|
|
534
|
+
# The handlers then surface unprefixed under a '${nativeCategory}' category,
|
|
535
|
+
# e.g. ${nativeCategory}(action="echo").
|
|
536
|
+
# nativeModule:
|
|
537
|
+
# uePluginName: ${uePlugin}
|
|
538
|
+
# minBridgeApi: 1
|
|
539
|
+
# source: ue/Plugins/${uePlugin}
|
|
540
|
+
# category: ${nativeCategory}
|
|
541
|
+
# categoryDescription: "${pkgName} native C++ handlers"
|
|
542
|
+
# handlers:
|
|
543
|
+
# echo:
|
|
544
|
+
# description: "Echo a name back from native C++ (required: name)"
|
|
545
|
+
# schema:
|
|
546
|
+
# name: { type: string, description: "Name to echo" }
|
|
547
547
|
`;
|
|
548
548
|
fs.writeFileSync(path.join(dir, "ue-mcp.plugin.yml"), manifestYaml);
|
|
549
549
|
// ── TypeScript: index stub + the two example tasks ──────────────────────
|
|
550
550
|
fs.mkdirSync(path.join(dir, "src", "tasks"), { recursive: true });
|
|
551
|
-
const indexTs = `// Entry point for the npm package. ue-mcp loads tasks by their manifest
|
|
552
|
-
// class_path, not through this file, so it can stay empty - but package.json's
|
|
553
|
-
// "main" points here, so the build must emit it.
|
|
554
|
-
export {};
|
|
551
|
+
const indexTs = `// Entry point for the npm package. ue-mcp loads tasks by their manifest
|
|
552
|
+
// class_path, not through this file, so it can stay empty - but package.json's
|
|
553
|
+
// "main" points here, so the build must emit it.
|
|
554
|
+
export {};
|
|
555
555
|
`;
|
|
556
556
|
fs.writeFileSync(path.join(dir, "src", "index.ts"), indexTs);
|
|
557
|
-
const helloTs = `import { UeMcpTask, type TaskResult } from "ue-mcp/task";
|
|
558
|
-
|
|
559
|
-
interface Options {
|
|
560
|
-
name?: string;
|
|
561
|
-
}
|
|
562
|
-
|
|
563
|
-
/** Backs project(action="${prefix}_hello") and the ${prefix}_demo flow. */
|
|
564
|
-
export default class ${helloClass} extends UeMcpTask<Options> {
|
|
565
|
-
get taskName() { return "${prefix}.hello"; }
|
|
566
|
-
|
|
567
|
-
async execute(): Promise<TaskResult> {
|
|
568
|
-
const who = this.options.name ?? "world";
|
|
569
|
-
return { success: true, data: { greeting: \`hello, \${who}\` } };
|
|
570
|
-
}
|
|
571
|
-
}
|
|
557
|
+
const helloTs = `import { UeMcpTask, type TaskResult } from "ue-mcp/task";
|
|
558
|
+
|
|
559
|
+
interface Options {
|
|
560
|
+
name?: string;
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
/** Backs project(action="${prefix}_hello") and the ${prefix}_demo flow. */
|
|
564
|
+
export default class ${helloClass} extends UeMcpTask<Options> {
|
|
565
|
+
get taskName() { return "${prefix}.hello"; }
|
|
566
|
+
|
|
567
|
+
async execute(): Promise<TaskResult> {
|
|
568
|
+
const who = this.options.name ?? "world";
|
|
569
|
+
return { success: true, data: { greeting: \`hello, \${who}\` } };
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
572
|
`;
|
|
573
573
|
fs.writeFileSync(path.join(dir, "src", "tasks", `${helloClass}.ts`), helloTs);
|
|
574
|
-
const greetTs = `import { UeMcpTask, type TaskResult } from "ue-mcp/task";
|
|
575
|
-
|
|
576
|
-
interface Options {
|
|
577
|
-
name?: string;
|
|
578
|
-
}
|
|
579
|
-
|
|
580
|
-
/**
|
|
581
|
-
* Backs ${prefix}(action="greet") - the plugin-owned category. Swap the body
|
|
582
|
-
* for real work; compose built-ins with \`this.call("level.get_outliner", {})\`.
|
|
583
|
-
*/
|
|
584
|
-
export default class ${greetClass} extends UeMcpTask<Options> {
|
|
585
|
-
get taskName() { return "${prefix}.greet"; }
|
|
586
|
-
|
|
587
|
-
async execute(): Promise<TaskResult> {
|
|
588
|
-
const who = this.options.name ?? "world";
|
|
589
|
-
return { success: true, data: { greeting: \`greetings, \${who}\` } };
|
|
590
|
-
}
|
|
591
|
-
}
|
|
574
|
+
const greetTs = `import { UeMcpTask, type TaskResult } from "ue-mcp/task";
|
|
575
|
+
|
|
576
|
+
interface Options {
|
|
577
|
+
name?: string;
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
/**
|
|
581
|
+
* Backs ${prefix}(action="greet") - the plugin-owned category. Swap the body
|
|
582
|
+
* for real work; compose built-ins with \`this.call("level.get_outliner", {})\`.
|
|
583
|
+
*/
|
|
584
|
+
export default class ${greetClass} extends UeMcpTask<Options> {
|
|
585
|
+
get taskName() { return "${prefix}.greet"; }
|
|
586
|
+
|
|
587
|
+
async execute(): Promise<TaskResult> {
|
|
588
|
+
const who = this.options.name ?? "world";
|
|
589
|
+
return { success: true, data: { greeting: \`greetings, \${who}\` } };
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
592
|
`;
|
|
593
593
|
fs.writeFileSync(path.join(dir, "src", "tasks", `${greetClass}.ts`), greetTs);
|
|
594
594
|
// ── Pre-publish sanity check ────────────────────────────────────────────
|
|
@@ -600,66 +600,66 @@ export default class ${greetClass} extends UeMcpTask<Options> {
|
|
|
600
600
|
// ── Dormant native C++ module ────────────────────────────────────────────
|
|
601
601
|
writeNativeSkeleton(dir, uePlugin, pkgName);
|
|
602
602
|
// ── README / LICENSE / .gitignore ────────────────────────────────────────
|
|
603
|
-
const readme = `# ${pkgName}
|
|
604
|
-
|
|
605
|
-
A ue-mcp plugin. Install with:
|
|
606
|
-
|
|
607
|
-
\`\`\`bash
|
|
608
|
-
ue-mcp plugin install ${pkgName}
|
|
609
|
-
\`\`\`
|
|
610
|
-
|
|
611
|
-
## What this scaffold ships
|
|
612
|
-
|
|
613
|
-
It is a **superset** - every way a plugin can extend ue-mcp, wired and working.
|
|
614
|
-
Keep what you want, delete the rest.
|
|
615
|
-
|
|
616
|
-
- **inject** -> \`project(action="${prefix}_hello")\` (an action added onto a built-in category)
|
|
617
|
-
- **provides** -> \`${prefix}(action="greet")\` (a new top-level category this plugin owns)
|
|
618
|
-
- **flows** -> \`${prefix}_demo\` (a chained, one-call orchestration)
|
|
619
|
-
- **nativeModule** -> a C++ handler skeleton under \`ue/Plugins/${uePlugin}/\`, **dormant** until you activate it
|
|
620
|
-
|
|
621
|
-
## Activate the native C++ module
|
|
622
|
-
|
|
623
|
-
The C++ source is already on disk but inert. To turn it on:
|
|
624
|
-
|
|
625
|
-
1. Uncomment the \`nativeModule:\` block at the bottom of \`ue-mcp.plugin.yml\`.
|
|
626
|
-
2. Reinstall (\`ue-mcp plugin install ${pkgName}\`) - this deploys the module into
|
|
627
|
-
your project's \`Plugins/\` and requires a UE rebuild before the editor starts.
|
|
628
|
-
|
|
629
|
-
The handler then surfaces as \`${prefix}_native(action="echo")\`.
|
|
630
|
-
|
|
631
|
-
## Develop
|
|
632
|
-
|
|
633
|
-
\`\`\`bash
|
|
634
|
-
npm install
|
|
635
|
-
npm run build
|
|
636
|
-
npm run check # validate the manifest + task wiring
|
|
637
|
-
\`\`\`
|
|
638
|
-
|
|
639
|
-
See https://ue-mcp.com/docs/plugins/ for the full author contract.
|
|
603
|
+
const readme = `# ${pkgName}
|
|
604
|
+
|
|
605
|
+
A ue-mcp plugin. Install with:
|
|
606
|
+
|
|
607
|
+
\`\`\`bash
|
|
608
|
+
ue-mcp plugin install ${pkgName}
|
|
609
|
+
\`\`\`
|
|
610
|
+
|
|
611
|
+
## What this scaffold ships
|
|
612
|
+
|
|
613
|
+
It is a **superset** - every way a plugin can extend ue-mcp, wired and working.
|
|
614
|
+
Keep what you want, delete the rest.
|
|
615
|
+
|
|
616
|
+
- **inject** -> \`project(action="${prefix}_hello")\` (an action added onto a built-in category)
|
|
617
|
+
- **provides** -> \`${prefix}(action="greet")\` (a new top-level category this plugin owns)
|
|
618
|
+
- **flows** -> \`${prefix}_demo\` (a chained, one-call orchestration)
|
|
619
|
+
- **nativeModule** -> a C++ handler skeleton under \`ue/Plugins/${uePlugin}/\`, **dormant** until you activate it
|
|
620
|
+
|
|
621
|
+
## Activate the native C++ module
|
|
622
|
+
|
|
623
|
+
The C++ source is already on disk but inert. To turn it on:
|
|
624
|
+
|
|
625
|
+
1. Uncomment the \`nativeModule:\` block at the bottom of \`ue-mcp.plugin.yml\`.
|
|
626
|
+
2. Reinstall (\`ue-mcp plugin install ${pkgName}\`) - this deploys the module into
|
|
627
|
+
your project's \`Plugins/\` and requires a UE rebuild before the editor starts.
|
|
628
|
+
|
|
629
|
+
The handler then surfaces as \`${prefix}_native(action="echo")\`.
|
|
630
|
+
|
|
631
|
+
## Develop
|
|
632
|
+
|
|
633
|
+
\`\`\`bash
|
|
634
|
+
npm install
|
|
635
|
+
npm run build
|
|
636
|
+
npm run check # validate the manifest + task wiring
|
|
637
|
+
\`\`\`
|
|
638
|
+
|
|
639
|
+
See https://ue-mcp.com/docs/plugins/ for the full author contract.
|
|
640
640
|
`;
|
|
641
641
|
fs.writeFileSync(path.join(dir, "README.md"), readme);
|
|
642
|
-
fs.writeFileSync(path.join(dir, "LICENSE"), `MIT License
|
|
643
|
-
|
|
644
|
-
Copyright (c) ${year} ${pkgName} authors
|
|
645
|
-
|
|
646
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
647
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
648
|
-
in the Software without restriction, including without limitation the rights
|
|
649
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
650
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
651
|
-
furnished to do so, subject to the following conditions:
|
|
652
|
-
|
|
653
|
-
The above copyright notice and this permission notice shall be included in all
|
|
654
|
-
copies or substantial portions of the Software.
|
|
655
|
-
|
|
656
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
657
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
658
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
659
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
660
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
661
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
662
|
-
SOFTWARE.
|
|
642
|
+
fs.writeFileSync(path.join(dir, "LICENSE"), `MIT License
|
|
643
|
+
|
|
644
|
+
Copyright (c) ${year} ${pkgName} authors
|
|
645
|
+
|
|
646
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
647
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
648
|
+
in the Software without restriction, including without limitation the rights
|
|
649
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
650
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
651
|
+
furnished to do so, subject to the following conditions:
|
|
652
|
+
|
|
653
|
+
The above copyright notice and this permission notice shall be included in all
|
|
654
|
+
copies or substantial portions of the Software.
|
|
655
|
+
|
|
656
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
657
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
658
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
659
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
660
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
661
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
662
|
+
SOFTWARE.
|
|
663
663
|
`);
|
|
664
664
|
fs.writeFileSync(path.join(dir, ".gitignore"), `node_modules/\ndist/\n*.tgz\n.DS_Store\n`);
|
|
665
665
|
}
|
|
@@ -704,96 +704,96 @@ function writeNativeSkeleton(dir, uePlugin, pkgName) {
|
|
|
704
704
|
],
|
|
705
705
|
};
|
|
706
706
|
fs.writeFileSync(path.join(base, `${uePlugin}.uplugin`), JSON.stringify(uplugin, null, 2) + "\n");
|
|
707
|
-
fs.writeFileSync(path.join(moduleDir, `${uePlugin}.Build.cs`), `using UnrealBuildTool;
|
|
708
|
-
|
|
709
|
-
public class ${uePlugin} : ModuleRules
|
|
710
|
-
{
|
|
711
|
-
\tpublic ${uePlugin}(ReadOnlyTargetRules Target) : base(Target)
|
|
712
|
-
\t{
|
|
713
|
-
\t\tPCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs;
|
|
714
|
-
|
|
715
|
-
\t\tPublicDependencyModuleNames.AddRange(new string[]
|
|
716
|
-
\t\t{
|
|
717
|
-
\t\t\t"Core",
|
|
718
|
-
\t\t\t"CoreUObject",
|
|
719
|
-
\t\t\t"Engine",
|
|
720
|
-
\t\t\t"Json",
|
|
721
|
-
\t\t\t"JsonUtilities",
|
|
722
|
-
\t\t});
|
|
723
|
-
|
|
724
|
-
\t\t// UE_MCP_Bridge exposes UEMCP::RegisterExternalHandler (MCPHandlerRegistration.h).
|
|
725
|
-
\t\tPrivateDependencyModuleNames.AddRange(new string[]
|
|
726
|
-
\t\t{
|
|
727
|
-
\t\t\t"UE_MCP_Bridge",
|
|
728
|
-
\t\t});
|
|
729
|
-
\t}
|
|
730
|
-
}
|
|
707
|
+
fs.writeFileSync(path.join(moduleDir, `${uePlugin}.Build.cs`), `using UnrealBuildTool;
|
|
708
|
+
|
|
709
|
+
public class ${uePlugin} : ModuleRules
|
|
710
|
+
{
|
|
711
|
+
\tpublic ${uePlugin}(ReadOnlyTargetRules Target) : base(Target)
|
|
712
|
+
\t{
|
|
713
|
+
\t\tPCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs;
|
|
714
|
+
|
|
715
|
+
\t\tPublicDependencyModuleNames.AddRange(new string[]
|
|
716
|
+
\t\t{
|
|
717
|
+
\t\t\t"Core",
|
|
718
|
+
\t\t\t"CoreUObject",
|
|
719
|
+
\t\t\t"Engine",
|
|
720
|
+
\t\t\t"Json",
|
|
721
|
+
\t\t\t"JsonUtilities",
|
|
722
|
+
\t\t});
|
|
723
|
+
|
|
724
|
+
\t\t// UE_MCP_Bridge exposes UEMCP::RegisterExternalHandler (MCPHandlerRegistration.h).
|
|
725
|
+
\t\tPrivateDependencyModuleNames.AddRange(new string[]
|
|
726
|
+
\t\t{
|
|
727
|
+
\t\t\t"UE_MCP_Bridge",
|
|
728
|
+
\t\t});
|
|
729
|
+
\t}
|
|
730
|
+
}
|
|
731
731
|
`);
|
|
732
|
-
fs.writeFileSync(path.join(publicDir, `${uePlugin}Module.h`), `#pragma once
|
|
733
|
-
|
|
734
|
-
#include "CoreMinimal.h"
|
|
735
|
-
#include "Modules/ModuleManager.h"
|
|
736
|
-
|
|
737
|
-
DECLARE_LOG_CATEGORY_EXTERN(Log${uePlugin}, Log, All);
|
|
738
|
-
|
|
739
|
-
class F${uePlugin}Module : public IModuleInterface
|
|
740
|
-
{
|
|
741
|
-
public:
|
|
742
|
-
\tvirtual void StartupModule() override;
|
|
743
|
-
\tvirtual void ShutdownModule() override;
|
|
744
|
-
};
|
|
732
|
+
fs.writeFileSync(path.join(publicDir, `${uePlugin}Module.h`), `#pragma once
|
|
733
|
+
|
|
734
|
+
#include "CoreMinimal.h"
|
|
735
|
+
#include "Modules/ModuleManager.h"
|
|
736
|
+
|
|
737
|
+
DECLARE_LOG_CATEGORY_EXTERN(Log${uePlugin}, Log, All);
|
|
738
|
+
|
|
739
|
+
class F${uePlugin}Module : public IModuleInterface
|
|
740
|
+
{
|
|
741
|
+
public:
|
|
742
|
+
\tvirtual void StartupModule() override;
|
|
743
|
+
\tvirtual void ShutdownModule() override;
|
|
744
|
+
};
|
|
745
745
|
`);
|
|
746
|
-
fs.writeFileSync(path.join(privateDir, `${uePlugin}Module.cpp`), `#include "${uePlugin}Module.h"
|
|
747
|
-
#include "Modules/ModuleManager.h"
|
|
748
|
-
#include "MCPHandlerRegistration.h"
|
|
749
|
-
#include "Handlers/ExampleHandlers.h"
|
|
750
|
-
|
|
751
|
-
DEFINE_LOG_CATEGORY(Log${uePlugin});
|
|
752
|
-
IMPLEMENT_MODULE(F${uePlugin}Module, ${uePlugin})
|
|
753
|
-
|
|
754
|
-
void F${uePlugin}Module::StartupModule()
|
|
755
|
-
{
|
|
756
|
-
\t// Bare method names. When this module is surfaced via nativeModule.category
|
|
757
|
-
\t// in ue-mcp.plugin.yml, ue-mcp routes <category>(action="echo") to "echo".
|
|
758
|
-
\tUEMCP::RegisterExternalHandler(TEXT("echo"), &FExampleHandlers::Echo);
|
|
759
|
-
|
|
760
|
-
\tUE_LOG(Log${uePlugin}, Log, TEXT("[${uePlugin}] Registered 1 handler"));
|
|
761
|
-
}
|
|
762
|
-
|
|
763
|
-
void F${uePlugin}Module::ShutdownModule()
|
|
764
|
-
{
|
|
765
|
-
\tUEMCP::UnregisterExternalHandler(TEXT("echo"));
|
|
766
|
-
}
|
|
746
|
+
fs.writeFileSync(path.join(privateDir, `${uePlugin}Module.cpp`), `#include "${uePlugin}Module.h"
|
|
747
|
+
#include "Modules/ModuleManager.h"
|
|
748
|
+
#include "MCPHandlerRegistration.h"
|
|
749
|
+
#include "Handlers/ExampleHandlers.h"
|
|
750
|
+
|
|
751
|
+
DEFINE_LOG_CATEGORY(Log${uePlugin});
|
|
752
|
+
IMPLEMENT_MODULE(F${uePlugin}Module, ${uePlugin})
|
|
753
|
+
|
|
754
|
+
void F${uePlugin}Module::StartupModule()
|
|
755
|
+
{
|
|
756
|
+
\t// Bare method names. When this module is surfaced via nativeModule.category
|
|
757
|
+
\t// in ue-mcp.plugin.yml, ue-mcp routes <category>(action="echo") to "echo".
|
|
758
|
+
\tUEMCP::RegisterExternalHandler(TEXT("echo"), &FExampleHandlers::Echo);
|
|
759
|
+
|
|
760
|
+
\tUE_LOG(Log${uePlugin}, Log, TEXT("[${uePlugin}] Registered 1 handler"));
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
void F${uePlugin}Module::ShutdownModule()
|
|
764
|
+
{
|
|
765
|
+
\tUEMCP::UnregisterExternalHandler(TEXT("echo"));
|
|
766
|
+
}
|
|
767
767
|
`);
|
|
768
|
-
fs.writeFileSync(path.join(handlersDir, "ExampleHandlers.h"), `#pragma once
|
|
769
|
-
|
|
770
|
-
#include "CoreMinimal.h"
|
|
771
|
-
#include "Dom/JsonObject.h"
|
|
772
|
-
#include "Dom/JsonValue.h"
|
|
773
|
-
|
|
774
|
-
/** Example external handler registered on the UE-MCP bridge. */
|
|
775
|
-
class FExampleHandlers
|
|
776
|
-
{
|
|
777
|
-
public:
|
|
778
|
-
\t/** Echo a 'name' param back. Bridge method: "echo". */
|
|
779
|
-
\tstatic TSharedPtr<FJsonValue> Echo(const TSharedPtr<FJsonObject>& Params);
|
|
780
|
-
};
|
|
768
|
+
fs.writeFileSync(path.join(handlersDir, "ExampleHandlers.h"), `#pragma once
|
|
769
|
+
|
|
770
|
+
#include "CoreMinimal.h"
|
|
771
|
+
#include "Dom/JsonObject.h"
|
|
772
|
+
#include "Dom/JsonValue.h"
|
|
773
|
+
|
|
774
|
+
/** Example external handler registered on the UE-MCP bridge. */
|
|
775
|
+
class FExampleHandlers
|
|
776
|
+
{
|
|
777
|
+
public:
|
|
778
|
+
\t/** Echo a 'name' param back. Bridge method: "echo". */
|
|
779
|
+
\tstatic TSharedPtr<FJsonValue> Echo(const TSharedPtr<FJsonObject>& Params);
|
|
780
|
+
};
|
|
781
781
|
`);
|
|
782
|
-
fs.writeFileSync(path.join(handlersDir, "ExampleHandlers.cpp"), `#include "Handlers/ExampleHandlers.h"
|
|
783
|
-
|
|
784
|
-
TSharedPtr<FJsonValue> FExampleHandlers::Echo(const TSharedPtr<FJsonObject>& Params)
|
|
785
|
-
{
|
|
786
|
-
\tFString Name = TEXT("world");
|
|
787
|
-
\tif (Params.IsValid())
|
|
788
|
-
\t{
|
|
789
|
-
\t\tParams->TryGetStringField(TEXT("name"), Name);
|
|
790
|
-
\t}
|
|
791
|
-
|
|
792
|
-
\tTSharedPtr<FJsonObject> Result = MakeShared<FJsonObject>();
|
|
793
|
-
\tResult->SetBoolField(TEXT("success"), true);
|
|
794
|
-
\tResult->SetStringField(TEXT("echo"), FString::Printf(TEXT("hello, %s"), *Name));
|
|
795
|
-
\treturn MakeShared<FJsonValueObject>(Result);
|
|
796
|
-
}
|
|
782
|
+
fs.writeFileSync(path.join(handlersDir, "ExampleHandlers.cpp"), `#include "Handlers/ExampleHandlers.h"
|
|
783
|
+
|
|
784
|
+
TSharedPtr<FJsonValue> FExampleHandlers::Echo(const TSharedPtr<FJsonObject>& Params)
|
|
785
|
+
{
|
|
786
|
+
\tFString Name = TEXT("world");
|
|
787
|
+
\tif (Params.IsValid())
|
|
788
|
+
\t{
|
|
789
|
+
\t\tParams->TryGetStringField(TEXT("name"), Name);
|
|
790
|
+
\t}
|
|
791
|
+
|
|
792
|
+
\tTSharedPtr<FJsonObject> Result = MakeShared<FJsonObject>();
|
|
793
|
+
\tResult->SetBoolField(TEXT("success"), true);
|
|
794
|
+
\tResult->SetStringField(TEXT("echo"), FString::Printf(TEXT("hello, %s"), *Name));
|
|
795
|
+
\treturn MakeShared<FJsonValueObject>(Result);
|
|
796
|
+
}
|
|
797
797
|
`);
|
|
798
798
|
}
|
|
799
799
|
/**
|
|
@@ -802,58 +802,58 @@ TSharedPtr<FJsonValue> FExampleHandlers::Echo(const TSharedPtr<FJsonObject>& Par
|
|
|
802
802
|
* resolves to a tasks: entry, and every tasks: class_path points at a real
|
|
803
803
|
* source/built file. No build step required - runs on plain node.
|
|
804
804
|
*/
|
|
805
|
-
const CHECK_SCRIPT = `#!/usr/bin/env node
|
|
806
|
-
// Sanity-check a ue-mcp plugin: manifest parses, task references resolve, and
|
|
807
|
-
// every class_path points at a real source or built file.
|
|
808
|
-
import fs from "node:fs";
|
|
809
|
-
import path from "node:path";
|
|
810
|
-
import yaml from "js-yaml";
|
|
811
|
-
|
|
812
|
-
const root = process.cwd();
|
|
813
|
-
const manifestPath = path.join(root, "ue-mcp.plugin.yml");
|
|
814
|
-
let errors = 0;
|
|
815
|
-
const fail = (m) => { console.error(" x " + m); errors++; };
|
|
816
|
-
|
|
817
|
-
if (!fs.existsSync(manifestPath)) {
|
|
818
|
-
console.error("ue-mcp.plugin.yml not found");
|
|
819
|
-
process.exit(1);
|
|
820
|
-
}
|
|
821
|
-
const m = yaml.load(fs.readFileSync(manifestPath, "utf8")) ?? {};
|
|
822
|
-
const tasks = m.tasks ?? {};
|
|
823
|
-
|
|
824
|
-
// Collect every task reference from inject + provides + flows.
|
|
825
|
-
const refs = [];
|
|
826
|
-
for (const [cat, actions] of Object.entries(m.inject ?? {}))
|
|
827
|
-
for (const [a, def] of Object.entries(actions))
|
|
828
|
-
if (def?.task) refs.push(["inject " + cat + "." + a, def.task]);
|
|
829
|
-
for (const [cat, spec] of Object.entries(m.provides ?? {}))
|
|
830
|
-
for (const [a, def] of Object.entries(spec?.actions ?? {}))
|
|
831
|
-
if (def?.task) refs.push(["provides " + cat + "." + a, def.task]);
|
|
832
|
-
for (const [fname, fdef] of Object.entries(m.flows ?? {}))
|
|
833
|
-
for (const [s, step] of Object.entries(fdef?.steps ?? {}))
|
|
834
|
-
if (step?.task) refs.push(["flow " + fname + "." + s, step.task]);
|
|
835
|
-
|
|
836
|
-
for (const [where, task] of refs)
|
|
837
|
-
if (!tasks[task]) fail(where + " references task '" + task + "' with no tasks: entry");
|
|
838
|
-
|
|
839
|
-
for (const [name, def] of Object.entries(tasks)) {
|
|
840
|
-
const seg = String(def.class_path).replace(/\\./g, "/");
|
|
841
|
-
const candidates = [
|
|
842
|
-
path.join(root, "src", seg + ".ts"),
|
|
843
|
-
path.join(root, "dist", seg + ".js"),
|
|
844
|
-
];
|
|
845
|
-
if (!candidates.some((c) => fs.existsSync(c)))
|
|
846
|
-
fail("task '" + name + "' class_path '" + def.class_path + "' resolves to no src/*.ts or dist/*.js");
|
|
847
|
-
}
|
|
848
|
-
|
|
849
|
-
if (m.nativeModule?.source && !fs.existsSync(path.join(root, m.nativeModule.source)))
|
|
850
|
-
fail("nativeModule.source '" + m.nativeModule.source + "' does not exist");
|
|
851
|
-
|
|
852
|
-
if (errors) {
|
|
853
|
-
console.error("\\n" + errors + " problem(s) found.");
|
|
854
|
-
process.exit(1);
|
|
855
|
-
}
|
|
856
|
-
console.log("ue-mcp plugin check: OK");
|
|
805
|
+
const CHECK_SCRIPT = `#!/usr/bin/env node
|
|
806
|
+
// Sanity-check a ue-mcp plugin: manifest parses, task references resolve, and
|
|
807
|
+
// every class_path points at a real source or built file.
|
|
808
|
+
import fs from "node:fs";
|
|
809
|
+
import path from "node:path";
|
|
810
|
+
import yaml from "js-yaml";
|
|
811
|
+
|
|
812
|
+
const root = process.cwd();
|
|
813
|
+
const manifestPath = path.join(root, "ue-mcp.plugin.yml");
|
|
814
|
+
let errors = 0;
|
|
815
|
+
const fail = (m) => { console.error(" x " + m); errors++; };
|
|
816
|
+
|
|
817
|
+
if (!fs.existsSync(manifestPath)) {
|
|
818
|
+
console.error("ue-mcp.plugin.yml not found");
|
|
819
|
+
process.exit(1);
|
|
820
|
+
}
|
|
821
|
+
const m = yaml.load(fs.readFileSync(manifestPath, "utf8")) ?? {};
|
|
822
|
+
const tasks = m.tasks ?? {};
|
|
823
|
+
|
|
824
|
+
// Collect every task reference from inject + provides + flows.
|
|
825
|
+
const refs = [];
|
|
826
|
+
for (const [cat, actions] of Object.entries(m.inject ?? {}))
|
|
827
|
+
for (const [a, def] of Object.entries(actions))
|
|
828
|
+
if (def?.task) refs.push(["inject " + cat + "." + a, def.task]);
|
|
829
|
+
for (const [cat, spec] of Object.entries(m.provides ?? {}))
|
|
830
|
+
for (const [a, def] of Object.entries(spec?.actions ?? {}))
|
|
831
|
+
if (def?.task) refs.push(["provides " + cat + "." + a, def.task]);
|
|
832
|
+
for (const [fname, fdef] of Object.entries(m.flows ?? {}))
|
|
833
|
+
for (const [s, step] of Object.entries(fdef?.steps ?? {}))
|
|
834
|
+
if (step?.task) refs.push(["flow " + fname + "." + s, step.task]);
|
|
835
|
+
|
|
836
|
+
for (const [where, task] of refs)
|
|
837
|
+
if (!tasks[task]) fail(where + " references task '" + task + "' with no tasks: entry");
|
|
838
|
+
|
|
839
|
+
for (const [name, def] of Object.entries(tasks)) {
|
|
840
|
+
const seg = String(def.class_path).replace(/\\./g, "/");
|
|
841
|
+
const candidates = [
|
|
842
|
+
path.join(root, "src", seg + ".ts"),
|
|
843
|
+
path.join(root, "dist", seg + ".js"),
|
|
844
|
+
];
|
|
845
|
+
if (!candidates.some((c) => fs.existsSync(c)))
|
|
846
|
+
fail("task '" + name + "' class_path '" + def.class_path + "' resolves to no src/*.ts or dist/*.js");
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
if (m.nativeModule?.source && !fs.existsSync(path.join(root, m.nativeModule.source)))
|
|
850
|
+
fail("nativeModule.source '" + m.nativeModule.source + "' does not exist");
|
|
851
|
+
|
|
852
|
+
if (errors) {
|
|
853
|
+
console.error("\\n" + errors + " problem(s) found.");
|
|
854
|
+
process.exit(1);
|
|
855
|
+
}
|
|
856
|
+
console.log("ue-mcp plugin check: OK");
|
|
857
857
|
`;
|
|
858
858
|
function uePluginEnabled(projectDir, name) {
|
|
859
859
|
const files = fs.readdirSync(projectDir).filter((f) => f.endsWith(".uproject"));
|
package/dist/tool-counts.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ue-mcp",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.2",
|
|
4
4
|
"description": "Unreal Engine MCP server - 24 tools, 783+ actions for AI-driven editor control",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -89,7 +89,7 @@
|
|
|
89
89
|
"prepare": "husky"
|
|
90
90
|
},
|
|
91
91
|
"dependencies": {
|
|
92
|
-
"@db-lyon/flowkit": "
|
|
92
|
+
"@db-lyon/flowkit": "^0.14.0",
|
|
93
93
|
"@modelcontextprotocol/sdk": "^1.12.1",
|
|
94
94
|
"js-yaml": "^4.1.0",
|
|
95
95
|
"ws": "^8.18.0",
|