ultimate-unreal-engine-mcp 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (124) hide show
  1. package/README.md +729 -0
  2. package/dist/build/error-parser.js +51 -0
  3. package/dist/build/fix-suggester.js +84 -0
  4. package/dist/build/ubt-runner.js +146 -0
  5. package/dist/cli.js +13 -0
  6. package/dist/config.js +8 -0
  7. package/dist/docs/data/ue57-api.js +228 -0
  8. package/dist/docs/doc-index.js +110 -0
  9. package/dist/docs/types.js +4 -0
  10. package/dist/generators/class-generator.js +363 -0
  11. package/dist/generators/file-modifier.js +276 -0
  12. package/dist/generators/uht-validator.js +177 -0
  13. package/dist/index.js +89 -0
  14. package/dist/parsers/cpp-class-index.js +230 -0
  15. package/dist/parsers/cpp-parser.js +369 -0
  16. package/dist/parsers/ini-parser.js +216 -0
  17. package/dist/parsers/uproject-parser.js +130 -0
  18. package/dist/plugin-bridge/client.js +217 -0
  19. package/dist/plugin-bridge/protocol.js +6 -0
  20. package/dist/plugin-bridge/retry.js +23 -0
  21. package/dist/setup.js +209 -0
  22. package/dist/tools/ai-systems/index.js +247 -0
  23. package/dist/tools/ai-systems/types.js +4 -0
  24. package/dist/tools/animation/index.js +241 -0
  25. package/dist/tools/animation/types.js +4 -0
  26. package/dist/tools/audio/index.js +204 -0
  27. package/dist/tools/audio/types.js +4 -0
  28. package/dist/tools/blueprint/index.js +495 -0
  29. package/dist/tools/blueprint/types.js +4 -0
  30. package/dist/tools/build/index.js +163 -0
  31. package/dist/tools/chaos/index.js +230 -0
  32. package/dist/tools/chaos/types.js +4 -0
  33. package/dist/tools/collision-physics/index.js +211 -0
  34. package/dist/tools/config/index.js +288 -0
  35. package/dist/tools/cpp/index.js +305 -0
  36. package/dist/tools/docs/index.js +251 -0
  37. package/dist/tools/editor/index.js +242 -0
  38. package/dist/tools/gas/index.js +222 -0
  39. package/dist/tools/gas/types.js +5 -0
  40. package/dist/tools/import-export/index.js +218 -0
  41. package/dist/tools/input/index.js +146 -0
  42. package/dist/tools/known-issues/index.js +88 -0
  43. package/dist/tools/known-issues/middleware.js +55 -0
  44. package/dist/tools/known-issues/store.js +125 -0
  45. package/dist/tools/livelink/index.js +203 -0
  46. package/dist/tools/livelink/types.js +4 -0
  47. package/dist/tools/material/index.js +190 -0
  48. package/dist/tools/motion-design/index.js +251 -0
  49. package/dist/tools/motion-design/types.js +6 -0
  50. package/dist/tools/movie-render/index.js +220 -0
  51. package/dist/tools/networking/index.js +149 -0
  52. package/dist/tools/pcg/index.js +164 -0
  53. package/dist/tools/selection/index.js +180 -0
  54. package/dist/tools/sequencer/index.js +218 -0
  55. package/dist/tools/validation/index.js +183 -0
  56. package/dist/tools/validation/types.js +4 -0
  57. package/dist/tools/viewport/index.js +310 -0
  58. package/dist/tools/worldpartition/index.js +226 -0
  59. package/dist/tools/worldpartition/types.js +4 -0
  60. package/dist/utils/execFileNoThrow.js +40 -0
  61. package/dist/utils/logger.js +27 -0
  62. package/dist/utils/path-guard.js +26 -0
  63. package/package.json +40 -0
  64. package/unreal-plugin/MCPBridge/MCPBridge.uplugin +29 -0
  65. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/MCPBridgeEditor.Build.cs +68 -0
  66. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPAICommands.cpp +919 -0
  67. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPAICommands.h +23 -0
  68. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPActorCommands.cpp +415 -0
  69. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPActorCommands.h +16 -0
  70. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPAnimationCommands.cpp +653 -0
  71. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPAnimationCommands.h +24 -0
  72. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPAssetCommands.cpp +290 -0
  73. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPAssetCommands.h +17 -0
  74. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPAudioCommands.cpp +624 -0
  75. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPAudioCommands.h +22 -0
  76. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPBlueprintHandlers.cpp +616 -0
  77. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPBlueprintHandlers.h +25 -0
  78. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPBlueprintWriteHandlers.cpp +744 -0
  79. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPBlueprintWriteHandlers.h +24 -0
  80. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPBridgeEditor.cpp +23 -0
  81. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPBridgeSubsystem.cpp +149 -0
  82. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPBridgeSubsystem.h +38 -0
  83. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPChaosCommands.cpp +771 -0
  84. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPChaosCommands.h +22 -0
  85. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPCollisionPhysicsCommands.cpp +749 -0
  86. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPCollisionPhysicsCommands.h +22 -0
  87. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPEditorStateCommands.cpp +172 -0
  88. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPEditorStateCommands.h +16 -0
  89. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPGASCommands.cpp +715 -0
  90. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPGASCommands.h +22 -0
  91. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPImportExportCommands.cpp +679 -0
  92. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPImportExportCommands.h +22 -0
  93. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPInputHandlers.cpp +381 -0
  94. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPInputHandlers.h +24 -0
  95. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPLiveLinkCommands.cpp +504 -0
  96. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPLiveLinkCommands.h +22 -0
  97. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPMaterialCommands.cpp +511 -0
  98. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPMaterialCommands.h +22 -0
  99. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPMotionDesignCommands.cpp +1110 -0
  100. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPMotionDesignCommands.h +28 -0
  101. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPMovieRenderCommands.cpp +590 -0
  102. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPMovieRenderCommands.h +16 -0
  103. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPNetworkingCommands.cpp +482 -0
  104. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPNetworkingCommands.h +16 -0
  105. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPPieCommands.cpp +338 -0
  106. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPPieCommands.h +16 -0
  107. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPSelectionCommands.cpp +677 -0
  108. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPSelectionCommands.h +22 -0
  109. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPSequencerCommands.cpp +721 -0
  110. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPSequencerCommands.h +16 -0
  111. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPValidationCommands.cpp +368 -0
  112. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPValidationCommands.h +22 -0
  113. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPViewportCommands.cpp +1208 -0
  114. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPViewportCommands.h +29 -0
  115. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPWorldPartitionCommands.cpp +822 -0
  116. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPWorldPartitionCommands.h +23 -0
  117. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Public/MCPBridgeEditor.h +14 -0
  118. package/unreal-plugin/MCPBridge/Source/MCPBridgeRuntime/MCPBridgeRuntime.Build.cs +28 -0
  119. package/unreal-plugin/MCPBridge/Source/MCPBridgeRuntime/Private/MCPBridgeRuntime.cpp +22 -0
  120. package/unreal-plugin/MCPBridge/Source/MCPBridgeRuntime/Private/MCPCommandRouter.cpp +118 -0
  121. package/unreal-plugin/MCPBridge/Source/MCPBridgeRuntime/Private/MCPTcpServer.cpp +196 -0
  122. package/unreal-plugin/MCPBridge/Source/MCPBridgeRuntime/Public/MCPBridgeRuntime.h +15 -0
  123. package/unreal-plugin/MCPBridge/Source/MCPBridgeRuntime/Public/MCPCommandRouter.h +55 -0
  124. package/unreal-plugin/MCPBridge/Source/MCPBridgeRuntime/Public/MCPTcpServer.h +59 -0
package/dist/setup.js ADDED
@@ -0,0 +1,209 @@
1
+ #!/usr/bin/env node
2
+ // setup.ts — One-command installer for Ultimate Unreal Engine MCP.
3
+ // Automatically configures Claude Desktop, Claude Code, or Cursor to use this server.
4
+ //
5
+ // Usage:
6
+ // npx ultimate-unreal-engine-mcp setup
7
+ // npx ultimate-unreal-engine-mcp setup --project "C:/MyGame"
8
+ // npx ultimate-unreal-engine-mcp setup --client claude-code
9
+ // npx ultimate-unreal-engine-mcp setup --port 55557
10
+ import { readFileSync, writeFileSync, existsSync, mkdirSync, cpSync } from 'node:fs';
11
+ import { join, resolve, dirname } from 'node:path';
12
+ import { platform, env } from 'node:process';
13
+ // ---------------------------------------------------------------------------
14
+ // Helpers
15
+ // ---------------------------------------------------------------------------
16
+ function log(msg) {
17
+ console.error(msg);
18
+ }
19
+ function getConfigPath(client) {
20
+ const home = env['USERPROFILE'] || env['HOME'] || '';
21
+ switch (client) {
22
+ case 'claude-desktop':
23
+ if (platform === 'win32') {
24
+ return join(env['APPDATA'] || join(home, 'AppData', 'Roaming'), 'Claude', 'claude_desktop_config.json');
25
+ }
26
+ return join(home, 'Library', 'Application Support', 'Claude', 'claude_desktop_config.json');
27
+ case 'claude-code':
28
+ return join(home, '.claude', 'settings.json');
29
+ case 'cursor':
30
+ if (platform === 'win32') {
31
+ return join(env['APPDATA'] || join(home, 'AppData', 'Roaming'), 'Cursor', 'User', 'globalStorage', 'cursor.mcp', 'config.json');
32
+ }
33
+ return join(home, '.config', 'cursor', 'mcp.json');
34
+ default:
35
+ return '';
36
+ }
37
+ }
38
+ function parseArgs(argv) {
39
+ let project = '';
40
+ let client = 'claude-desktop';
41
+ let port = 55557;
42
+ let pluginOnly = false;
43
+ for (let i = 0; i < argv.length; i++) {
44
+ if (argv[i] === '--project' && argv[i + 1]) {
45
+ project = argv[++i];
46
+ }
47
+ else if (argv[i] === '--client' && argv[i + 1]) {
48
+ client = argv[++i];
49
+ }
50
+ else if (argv[i] === '--port' && argv[i + 1]) {
51
+ port = parseInt(argv[++i], 10);
52
+ }
53
+ else if (argv[i] === '--plugin-only') {
54
+ pluginOnly = true;
55
+ }
56
+ }
57
+ return { project, client, port, pluginOnly };
58
+ }
59
+ // ---------------------------------------------------------------------------
60
+ // Plugin installer
61
+ // ---------------------------------------------------------------------------
62
+ function installPlugin(projectRoot) {
63
+ const pluginSrc = join(dirname(new URL(import.meta.url).pathname.replace(/^\/([A-Z]:)/, '$1')), '..', 'unreal-plugin', 'MCPBridge');
64
+ const pluginDest = join(projectRoot, 'Plugins', 'MCPBridge');
65
+ if (!existsSync(pluginSrc)) {
66
+ log(` Plugin source not found at ${pluginSrc}`);
67
+ log(' You may need to copy unreal-plugin/MCPBridge/ manually.');
68
+ return false;
69
+ }
70
+ if (existsSync(pluginDest)) {
71
+ log(` Plugin already exists at ${pluginDest} — skipping copy.`);
72
+ return true;
73
+ }
74
+ try {
75
+ mkdirSync(dirname(pluginDest), { recursive: true });
76
+ cpSync(pluginSrc, pluginDest, { recursive: true });
77
+ log(` Copied MCPBridge plugin to ${pluginDest}`);
78
+ return true;
79
+ }
80
+ catch (err) {
81
+ log(` Failed to copy plugin: ${err}`);
82
+ log(` Copy manually: cp -r "${pluginSrc}" "${pluginDest}"`);
83
+ return false;
84
+ }
85
+ }
86
+ // ---------------------------------------------------------------------------
87
+ // Config writer
88
+ // ---------------------------------------------------------------------------
89
+ function configureClient(client, port, projectRoot) {
90
+ const configPath = getConfigPath(client);
91
+ if (!configPath) {
92
+ log(` Unknown client: ${client}`);
93
+ log(' Supported: claude-desktop, claude-code, cursor');
94
+ return;
95
+ }
96
+ // For claude-code, we use the mcpServers format in settings.json
97
+ // For claude-desktop and cursor, we use the standard MCP config format
98
+ let config = {};
99
+ if (existsSync(configPath)) {
100
+ try {
101
+ config = JSON.parse(readFileSync(configPath, 'utf-8'));
102
+ }
103
+ catch {
104
+ log(` Warning: Could not parse existing ${configPath}, creating fresh config.`);
105
+ }
106
+ }
107
+ const serverEntry = {
108
+ command: 'npx',
109
+ args: ['-y', 'ultimate-unreal-engine-mcp'],
110
+ };
111
+ // Only add env if project root is specified
112
+ const envBlock = {};
113
+ if (projectRoot) {
114
+ envBlock['UE_PROJECT_ROOT'] = projectRoot;
115
+ }
116
+ if (port !== 55557) {
117
+ envBlock['UE_PLUGIN_PORT'] = String(port);
118
+ }
119
+ if (Object.keys(envBlock).length > 0) {
120
+ serverEntry['env'] = envBlock;
121
+ }
122
+ if (client === 'claude-code') {
123
+ // Claude Code uses settings.json with mcpServers at top level
124
+ if (!config['mcpServers'] || typeof config['mcpServers'] !== 'object') {
125
+ config['mcpServers'] = {};
126
+ }
127
+ config['mcpServers']['unreal-engine'] = serverEntry;
128
+ }
129
+ else {
130
+ // Claude Desktop and Cursor use the standard format
131
+ if (!config['mcpServers'] || typeof config['mcpServers'] !== 'object') {
132
+ config['mcpServers'] = {};
133
+ }
134
+ config['mcpServers']['unreal-engine'] = serverEntry;
135
+ }
136
+ mkdirSync(dirname(configPath), { recursive: true });
137
+ writeFileSync(configPath, JSON.stringify(config, null, 2) + '\n', 'utf-8');
138
+ log(` Configured ${client} at ${configPath}`);
139
+ }
140
+ // ---------------------------------------------------------------------------
141
+ // Main
142
+ // ---------------------------------------------------------------------------
143
+ function main() {
144
+ const args = parseArgs(process.argv.slice(2));
145
+ // Check if this is a "setup" invocation or just running the server
146
+ const command = process.argv[2];
147
+ if (command !== 'setup') {
148
+ // Not setup — just import and run the server
149
+ // This is handled by the bin entry pointing to dist/index.js
150
+ console.error('Usage: npx ultimate-unreal-engine-mcp setup [--project <path>] [--client <name>] [--port <num>]');
151
+ console.error('');
152
+ console.error('Options:');
153
+ console.error(' --project <path> Path to your UE project (optional, can set later via UE_PROJECT_ROOT)');
154
+ console.error(' --client <name> claude-desktop (default), claude-code, or cursor');
155
+ console.error(' --port <num> Plugin TCP port (default: 55557)');
156
+ console.error(' --plugin-only Only install the UE plugin, skip MCP config');
157
+ console.error('');
158
+ console.error('Examples:');
159
+ console.error(' npx ultimate-unreal-engine-mcp setup');
160
+ console.error(' npx ultimate-unreal-engine-mcp setup --project "C:/MyGame" --client claude-code');
161
+ process.exit(1);
162
+ }
163
+ log('');
164
+ log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
165
+ log(' Ultimate Unreal Engine MCP — Setup');
166
+ log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
167
+ log('');
168
+ // Step 1: Configure MCP client
169
+ if (!args.pluginOnly) {
170
+ log('Step 1: Configuring MCP client...');
171
+ configureClient(args.client, args.port, args.project);
172
+ log('');
173
+ }
174
+ // Step 2: Install UE plugin (if project path provided)
175
+ if (args.project) {
176
+ const projectRoot = resolve(args.project);
177
+ if (!existsSync(projectRoot)) {
178
+ log(`Step 2: Project path not found: ${projectRoot}`);
179
+ log(' Skipping plugin install. You can copy it manually later.');
180
+ }
181
+ else {
182
+ log('Step 2: Installing UE plugin...');
183
+ installPlugin(projectRoot);
184
+ log('');
185
+ log(' After installing, regenerate project files and compile.');
186
+ log(' The plugin starts a TCP server on port ' + args.port + ' when the editor launches.');
187
+ }
188
+ }
189
+ else {
190
+ log('Step 2: No --project path specified.');
191
+ log(' To install the UE plugin later, copy unreal-plugin/MCPBridge/');
192
+ log(' into your UE project\'s Plugins/ folder.');
193
+ }
194
+ log('');
195
+ log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
196
+ log(' Setup complete!');
197
+ log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
198
+ log('');
199
+ log('Next steps:');
200
+ log(' 1. Restart ' + args.client);
201
+ log(' 2. Ask Claude: "List all Blueprint assets in my project"');
202
+ log('');
203
+ if (!args.project) {
204
+ log('Optional: Set your UE project path:');
205
+ log(' npx ultimate-unreal-engine-mcp setup --project "C:/path/to/MyGame"');
206
+ log('');
207
+ }
208
+ }
209
+ main();
@@ -0,0 +1,247 @@
1
+ // src/tools/ai-systems/index.ts
2
+ // MCP tool implementations for AI system asset inspection (Phase 22).
3
+ // All tools route commands through PluginBridgeClient to the C++ MCPBridge handlers.
4
+ // Returns structured plugin_not_connected errors when the plugin is absent.
5
+ //
6
+ // Tools registered (Phase 22 — AI-01 through AI-05):
7
+ // ue_inspect_behavior_tree — Inspect BT node hierarchy, decorators, and services
8
+ // ue_inspect_state_tree — Read State Tree states, transitions, and tasks
9
+ // ue_inspect_blackboard — List Blackboard keys with types and instance-sync status
10
+ // ue_inspect_eqs — Inspect EQS query templates: generators, tests, scoring
11
+ // ue_query_navmesh — Query NavMesh build status, bounds, and point reachability
12
+ //
13
+ // All tools require MCPBridge plugin (Phase 22 — AI-01 through AI-05).
14
+ import { z } from 'zod';
15
+ import { withKnownIssues } from '../known-issues/middleware.js';
16
+ import { PluginBridgeClient, PluginNotConnectedError } from '../../plugin-bridge/client.js';
17
+ // Module-level bridge instance — injected in tests via exported handler signatures.
18
+ const bridge = new PluginBridgeClient();
19
+ // ---------------------------------------------------------------------------
20
+ // sendOrDisconnect helper
21
+ // ---------------------------------------------------------------------------
22
+ /**
23
+ * Sends a command to the bridge and returns a ToolResult.
24
+ *
25
+ * - On success (response.success true): returns data as JSON text.
26
+ * - On command-level failure (response.success false): returns isError:true with error JSON.
27
+ * - On PluginNotConnectedError: returns isError:true with plugin_not_connected JSON.
28
+ * - On other errors: rethrows (withKnownIssues catches and formats).
29
+ *
30
+ * NOTE: sendCommand() overwrites correlationId with crypto.randomUUID() internally;
31
+ * passing an empty string is safe and correct (per STATE.md decision).
32
+ */
33
+ async function sendOrDisconnect(b, cmd) {
34
+ try {
35
+ const response = await b.sendCommand({ ...cmd, correlationId: '' });
36
+ if (!response.success) {
37
+ return {
38
+ isError: true,
39
+ content: [{ type: 'text', text: JSON.stringify({ error: response.error }) }],
40
+ };
41
+ }
42
+ return {
43
+ content: [{ type: 'text', text: JSON.stringify(response.data ?? {}) }],
44
+ };
45
+ }
46
+ catch (err) {
47
+ if (err instanceof PluginNotConnectedError) {
48
+ return {
49
+ isError: true,
50
+ content: [{ type: 'text', text: JSON.stringify(err.bridgeError) }],
51
+ };
52
+ }
53
+ throw err; // withKnownIssues catches unexpected errors
54
+ }
55
+ }
56
+ // ---------------------------------------------------------------------------
57
+ // Exported handler functions (for direct unit testing via bridge injection)
58
+ // ---------------------------------------------------------------------------
59
+ /**
60
+ * ue_inspect_behavior_tree handler — satisfies AI-01.
61
+ * Sends ai.behaviorTree to the plugin; returns node hierarchy, decorators, and services.
62
+ *
63
+ * @param args Tool arguments including asset_path.
64
+ * @param b PluginBridgeClient instance (defaults to module-level singleton).
65
+ */
66
+ export async function handleInspectBehaviorTree(args, b = bridge) {
67
+ // Response data shape: BehaviorTreeInspectResult
68
+ return sendOrDisconnect(b, {
69
+ type: 'ai.behaviorTree',
70
+ payload: { asset_path: args.asset_path },
71
+ });
72
+ }
73
+ /**
74
+ * ue_inspect_state_tree handler — satisfies AI-02.
75
+ * Sends ai.stateTree to the plugin; returns states, transitions, and tasks.
76
+ *
77
+ * @param args Tool arguments including asset_path.
78
+ * @param b PluginBridgeClient instance (defaults to module-level singleton).
79
+ */
80
+ export async function handleInspectStateTree(args, b = bridge) {
81
+ // Response data shape: StateTreeInspectResult
82
+ return sendOrDisconnect(b, {
83
+ type: 'ai.stateTree',
84
+ payload: { asset_path: args.asset_path },
85
+ });
86
+ }
87
+ /**
88
+ * ue_inspect_blackboard handler — satisfies AI-03.
89
+ * Sends ai.blackboard to the plugin; returns Blackboard keys with types and instance-sync status.
90
+ *
91
+ * @param args Tool arguments including asset_path.
92
+ * @param b PluginBridgeClient instance (defaults to module-level singleton).
93
+ */
94
+ export async function handleInspectBlackboard(args, b = bridge) {
95
+ // Response data shape: BlackboardInspectResult
96
+ return sendOrDisconnect(b, {
97
+ type: 'ai.blackboard',
98
+ payload: { asset_path: args.asset_path },
99
+ });
100
+ }
101
+ /**
102
+ * ue_inspect_eqs handler — satisfies AI-04.
103
+ * Sends ai.eqs to the plugin; returns EQS generator classes, tests, and scoring configuration.
104
+ *
105
+ * @param args Tool arguments including asset_path.
106
+ * @param b PluginBridgeClient instance (defaults to module-level singleton).
107
+ */
108
+ export async function handleInspectEqs(args, b = bridge) {
109
+ // Response data shape: EQSInspectResult
110
+ return sendOrDisconnect(b, {
111
+ type: 'ai.eqs',
112
+ payload: { asset_path: args.asset_path },
113
+ });
114
+ }
115
+ /**
116
+ * ue_query_navmesh handler — satisfies AI-05.
117
+ * Sends ai.navmesh to the plugin; returns NavMesh build status, bounds, and optional
118
+ * point-to-point reachability when both start_point and end_point are provided.
119
+ *
120
+ * @param args Tool arguments including optional start_point and end_point.
121
+ * @param b PluginBridgeClient instance (defaults to module-level singleton).
122
+ */
123
+ export async function handleQueryNavmesh(args, b = bridge) {
124
+ // Response data shape: NavMeshQueryResult
125
+ const payload = {};
126
+ if (args.start_point !== undefined && args.end_point !== undefined) {
127
+ payload['start_point'] = args.start_point;
128
+ payload['end_point'] = args.end_point;
129
+ }
130
+ return sendOrDisconnect(b, {
131
+ type: 'ai.navmesh',
132
+ payload,
133
+ });
134
+ }
135
+ // ---------------------------------------------------------------------------
136
+ // registerAISystemsTools
137
+ // ---------------------------------------------------------------------------
138
+ /**
139
+ * Register UE AI system inspection tools on the MCP server.
140
+ *
141
+ * All tools in this domain require the MCPBridge editor plugin.
142
+ * When the plugin is not connected, each handler returns:
143
+ * { isError: true, content: [{ type: 'text', text: <plugin_not_connected JSON> }] }
144
+ *
145
+ * Tools registered (Phase 22):
146
+ * ue_inspect_behavior_tree — AI-01: Inspect BT node hierarchy with decorators and services
147
+ * ue_inspect_state_tree — AI-02: Read State Tree states, transitions, and tasks
148
+ * ue_inspect_blackboard — AI-03: List Blackboard keys with types and instance-sync status
149
+ * ue_inspect_eqs — AI-04: Inspect EQS query generators, tests, and scoring
150
+ * ue_query_navmesh — AI-05: Query NavMesh status, bounds, and reachability
151
+ *
152
+ * @param server The McpServer instance to register tools on.
153
+ * @param _bridge Optional PluginBridgeClient for testing (not used directly — handlers
154
+ * accept bridge injection via their exported function signatures).
155
+ */
156
+ export function registerAISystemsTools(server, _bridge) {
157
+ const b = _bridge ?? new PluginBridgeClient();
158
+ // --------------------------------------------------------------------------
159
+ // ue_inspect_behavior_tree (AI-01)
160
+ // --------------------------------------------------------------------------
161
+ server.registerTool('ue_inspect_behavior_tree', {
162
+ title: 'Inspect Behavior Tree',
163
+ description: '[requires_plugin] Inspect a Behavior Tree asset\'s node hierarchy, decorators, and services.',
164
+ inputSchema: z.object({
165
+ asset_path: z
166
+ .string()
167
+ .min(1)
168
+ .describe('UE long package path to the Behavior Tree asset, e.g. /Game/AI/BT_EnemyLogic'),
169
+ }),
170
+ annotations: {
171
+ readOnlyHint: true,
172
+ destructiveHint: false,
173
+ },
174
+ }, withKnownIssues('ue_inspect_behavior_tree', async (args) => handleInspectBehaviorTree(args, b)));
175
+ // --------------------------------------------------------------------------
176
+ // ue_inspect_state_tree (AI-02)
177
+ // --------------------------------------------------------------------------
178
+ server.registerTool('ue_inspect_state_tree', {
179
+ title: 'Inspect State Tree',
180
+ description: '[requires_plugin] Read a State Tree\'s states, transitions, and tasks.',
181
+ inputSchema: z.object({
182
+ asset_path: z
183
+ .string()
184
+ .min(1)
185
+ .describe('UE long package path to the State Tree asset, e.g. /Game/AI/ST_NPCBehavior'),
186
+ }),
187
+ annotations: {
188
+ readOnlyHint: true,
189
+ destructiveHint: false,
190
+ },
191
+ }, withKnownIssues('ue_inspect_state_tree', async (args) => handleInspectStateTree(args, b)));
192
+ // --------------------------------------------------------------------------
193
+ // ue_inspect_blackboard (AI-03)
194
+ // --------------------------------------------------------------------------
195
+ server.registerTool('ue_inspect_blackboard', {
196
+ title: 'Inspect Blackboard',
197
+ description: '[requires_plugin] List all Blackboard keys with their types, default values, and instance-sync status.',
198
+ inputSchema: z.object({
199
+ asset_path: z
200
+ .string()
201
+ .min(1)
202
+ .describe('UE long package path to the Blackboard Data asset, e.g. /Game/AI/BB_EnemyData'),
203
+ }),
204
+ annotations: {
205
+ readOnlyHint: true,
206
+ destructiveHint: false,
207
+ },
208
+ }, withKnownIssues('ue_inspect_blackboard', async (args) => handleInspectBlackboard(args, b)));
209
+ // --------------------------------------------------------------------------
210
+ // ue_inspect_eqs (AI-04)
211
+ // --------------------------------------------------------------------------
212
+ server.registerTool('ue_inspect_eqs', {
213
+ title: 'Inspect EQS Query',
214
+ description: '[requires_plugin] Inspect an Environment Query System template\'s generators, tests, and scoring configuration.',
215
+ inputSchema: z.object({
216
+ asset_path: z
217
+ .string()
218
+ .min(1)
219
+ .describe('UE long package path to the EQS query asset, e.g. /Game/AI/EQS_FindCover'),
220
+ }),
221
+ annotations: {
222
+ readOnlyHint: true,
223
+ destructiveHint: false,
224
+ },
225
+ }, withKnownIssues('ue_inspect_eqs', async (args) => handleInspectEqs(args, b)));
226
+ // --------------------------------------------------------------------------
227
+ // ue_query_navmesh (AI-05)
228
+ // --------------------------------------------------------------------------
229
+ server.registerTool('ue_query_navmesh', {
230
+ title: 'Query NavMesh',
231
+ description: '[requires_plugin] Query NavMesh build status, bounds, and optionally test reachability between two points.',
232
+ inputSchema: z.object({
233
+ start_point: z
234
+ .object({ x: z.number(), y: z.number(), z: z.number() })
235
+ .optional()
236
+ .describe('Optional start point for reachability test'),
237
+ end_point: z
238
+ .object({ x: z.number(), y: z.number(), z: z.number() })
239
+ .optional()
240
+ .describe('Optional end point for reachability test'),
241
+ }),
242
+ annotations: {
243
+ readOnlyHint: true,
244
+ destructiveHint: false,
245
+ },
246
+ }, withKnownIssues('ue_query_navmesh', async (args) => handleQueryNavmesh(args, b)));
247
+ }
@@ -0,0 +1,4 @@
1
+ // src/tools/ai-systems/types.ts
2
+ // TypeScript result interfaces for the five AI system MCP tools (Phase 22).
3
+ // These interfaces mirror the JSON shapes returned by the C++ handlers in Plan 22-01.
4
+ export {};