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.
- package/README.md +729 -0
- package/dist/build/error-parser.js +51 -0
- package/dist/build/fix-suggester.js +84 -0
- package/dist/build/ubt-runner.js +146 -0
- package/dist/cli.js +13 -0
- package/dist/config.js +8 -0
- package/dist/docs/data/ue57-api.js +228 -0
- package/dist/docs/doc-index.js +110 -0
- package/dist/docs/types.js +4 -0
- package/dist/generators/class-generator.js +363 -0
- package/dist/generators/file-modifier.js +276 -0
- package/dist/generators/uht-validator.js +177 -0
- package/dist/index.js +89 -0
- package/dist/parsers/cpp-class-index.js +230 -0
- package/dist/parsers/cpp-parser.js +369 -0
- package/dist/parsers/ini-parser.js +216 -0
- package/dist/parsers/uproject-parser.js +130 -0
- package/dist/plugin-bridge/client.js +217 -0
- package/dist/plugin-bridge/protocol.js +6 -0
- package/dist/plugin-bridge/retry.js +23 -0
- package/dist/setup.js +209 -0
- package/dist/tools/ai-systems/index.js +247 -0
- package/dist/tools/ai-systems/types.js +4 -0
- package/dist/tools/animation/index.js +241 -0
- package/dist/tools/animation/types.js +4 -0
- package/dist/tools/audio/index.js +204 -0
- package/dist/tools/audio/types.js +4 -0
- package/dist/tools/blueprint/index.js +495 -0
- package/dist/tools/blueprint/types.js +4 -0
- package/dist/tools/build/index.js +163 -0
- package/dist/tools/chaos/index.js +230 -0
- package/dist/tools/chaos/types.js +4 -0
- package/dist/tools/collision-physics/index.js +211 -0
- package/dist/tools/config/index.js +288 -0
- package/dist/tools/cpp/index.js +305 -0
- package/dist/tools/docs/index.js +251 -0
- package/dist/tools/editor/index.js +242 -0
- package/dist/tools/gas/index.js +222 -0
- package/dist/tools/gas/types.js +5 -0
- package/dist/tools/import-export/index.js +218 -0
- package/dist/tools/input/index.js +146 -0
- package/dist/tools/known-issues/index.js +88 -0
- package/dist/tools/known-issues/middleware.js +55 -0
- package/dist/tools/known-issues/store.js +125 -0
- package/dist/tools/livelink/index.js +203 -0
- package/dist/tools/livelink/types.js +4 -0
- package/dist/tools/material/index.js +190 -0
- package/dist/tools/motion-design/index.js +251 -0
- package/dist/tools/motion-design/types.js +6 -0
- package/dist/tools/movie-render/index.js +220 -0
- package/dist/tools/networking/index.js +149 -0
- package/dist/tools/pcg/index.js +164 -0
- package/dist/tools/selection/index.js +180 -0
- package/dist/tools/sequencer/index.js +218 -0
- package/dist/tools/validation/index.js +183 -0
- package/dist/tools/validation/types.js +4 -0
- package/dist/tools/viewport/index.js +310 -0
- package/dist/tools/worldpartition/index.js +226 -0
- package/dist/tools/worldpartition/types.js +4 -0
- package/dist/utils/execFileNoThrow.js +40 -0
- package/dist/utils/logger.js +27 -0
- package/dist/utils/path-guard.js +26 -0
- package/package.json +40 -0
- package/unreal-plugin/MCPBridge/MCPBridge.uplugin +29 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/MCPBridgeEditor.Build.cs +68 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPAICommands.cpp +919 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPAICommands.h +23 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPActorCommands.cpp +415 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPActorCommands.h +16 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPAnimationCommands.cpp +653 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPAnimationCommands.h +24 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPAssetCommands.cpp +290 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPAssetCommands.h +17 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPAudioCommands.cpp +624 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPAudioCommands.h +22 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPBlueprintHandlers.cpp +616 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPBlueprintHandlers.h +25 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPBlueprintWriteHandlers.cpp +744 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPBlueprintWriteHandlers.h +24 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPBridgeEditor.cpp +23 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPBridgeSubsystem.cpp +149 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPBridgeSubsystem.h +38 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPChaosCommands.cpp +771 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPChaosCommands.h +22 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPCollisionPhysicsCommands.cpp +749 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPCollisionPhysicsCommands.h +22 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPEditorStateCommands.cpp +172 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPEditorStateCommands.h +16 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPGASCommands.cpp +715 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPGASCommands.h +22 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPImportExportCommands.cpp +679 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPImportExportCommands.h +22 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPInputHandlers.cpp +381 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPInputHandlers.h +24 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPLiveLinkCommands.cpp +504 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPLiveLinkCommands.h +22 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPMaterialCommands.cpp +511 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPMaterialCommands.h +22 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPMotionDesignCommands.cpp +1110 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPMotionDesignCommands.h +28 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPMovieRenderCommands.cpp +590 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPMovieRenderCommands.h +16 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPNetworkingCommands.cpp +482 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPNetworkingCommands.h +16 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPPieCommands.cpp +338 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPPieCommands.h +16 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPSelectionCommands.cpp +677 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPSelectionCommands.h +22 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPSequencerCommands.cpp +721 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPSequencerCommands.h +16 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPValidationCommands.cpp +368 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPValidationCommands.h +22 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPViewportCommands.cpp +1208 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPViewportCommands.h +29 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPWorldPartitionCommands.cpp +822 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPWorldPartitionCommands.h +23 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Public/MCPBridgeEditor.h +14 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeRuntime/MCPBridgeRuntime.Build.cs +28 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeRuntime/Private/MCPBridgeRuntime.cpp +22 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeRuntime/Private/MCPCommandRouter.cpp +118 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeRuntime/Private/MCPTcpServer.cpp +196 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeRuntime/Public/MCPBridgeRuntime.h +15 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeRuntime/Public/MCPCommandRouter.h +55 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeRuntime/Public/MCPTcpServer.h +59 -0
|
@@ -0,0 +1,495 @@
|
|
|
1
|
+
// src/tools/blueprint/index.ts
|
|
2
|
+
// Registers Blueprint tools on the MCP server.
|
|
3
|
+
// Read tools (ue_read_blueprint, ue_read_blueprint_graph, ue_list_blueprints) send
|
|
4
|
+
// commands to the UE Editor plugin via PluginBridgeClient.sendCommand().
|
|
5
|
+
// Write tools (ue_create_blueprint, ue_add_blueprint_node) remain as Phase 10 stubs.
|
|
6
|
+
// All tools require the UE Editor MCPBridge plugin and return a structured
|
|
7
|
+
// plugin_not_connected error (not a crash) when the plugin is not running.
|
|
8
|
+
import { z } from 'zod';
|
|
9
|
+
import * as fs from 'fs/promises';
|
|
10
|
+
import { withKnownIssues } from '../known-issues/middleware.js';
|
|
11
|
+
import { PluginBridgeClient, PluginNotConnectedError } from '../../plugin-bridge/client.js';
|
|
12
|
+
import { parseCppFile } from '../../parsers/cpp-parser.js';
|
|
13
|
+
import { validatePath } from '../../utils/path-guard.js';
|
|
14
|
+
import { PROJECT_ROOT } from '../../config.js';
|
|
15
|
+
// Module-level bridge instance — Phase 7 will introduce a shared singleton.
|
|
16
|
+
// Two instances (blueprint + editor) is acceptable for Phase 1 stub behaviour.
|
|
17
|
+
const bridge = new PluginBridgeClient();
|
|
18
|
+
/**
|
|
19
|
+
* ue_read_blueprint handler — reads Blueprint structure via plugin bridge.
|
|
20
|
+
* BPR-01: returns parentClass, variables, and components.
|
|
21
|
+
*/
|
|
22
|
+
export async function handleReadBlueprint(args) {
|
|
23
|
+
try {
|
|
24
|
+
const response = await bridge.sendCommand({
|
|
25
|
+
type: 'blueprint.read',
|
|
26
|
+
correlationId: '', // overwritten by sendCommand
|
|
27
|
+
payload: { asset_path: args.asset_path },
|
|
28
|
+
});
|
|
29
|
+
if (!response.success) {
|
|
30
|
+
return {
|
|
31
|
+
isError: true,
|
|
32
|
+
content: [{ type: 'text', text: JSON.stringify({ error: response.error ?? 'unknown_error' }) }],
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
return {
|
|
36
|
+
content: [{ type: 'text', text: JSON.stringify(response.data, null, 2) }],
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
catch (err) {
|
|
40
|
+
if (err instanceof PluginNotConnectedError) {
|
|
41
|
+
return { isError: true, content: [{ type: 'text', text: JSON.stringify(err.bridgeError) }] };
|
|
42
|
+
}
|
|
43
|
+
throw err;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* ue_read_blueprint_graph handler — reads Blueprint graph nodes and connections.
|
|
48
|
+
* BPR-02 (event graph), BPR-03 (function graphs).
|
|
49
|
+
*/
|
|
50
|
+
export async function handleReadBlueprintGraph(args) {
|
|
51
|
+
try {
|
|
52
|
+
const response = await bridge.sendCommand({
|
|
53
|
+
type: 'blueprint.graph',
|
|
54
|
+
correlationId: '', // overwritten by sendCommand
|
|
55
|
+
payload: {
|
|
56
|
+
asset_path: args.asset_path,
|
|
57
|
+
graph_name: args.graph_name ?? 'EventGraph',
|
|
58
|
+
},
|
|
59
|
+
});
|
|
60
|
+
if (!response.success) {
|
|
61
|
+
return {
|
|
62
|
+
isError: true,
|
|
63
|
+
content: [{ type: 'text', text: JSON.stringify({ error: response.error ?? 'unknown_error' }) }],
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
return {
|
|
67
|
+
content: [{ type: 'text', text: JSON.stringify(response.data, null, 2) }],
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
catch (err) {
|
|
71
|
+
if (err instanceof PluginNotConnectedError) {
|
|
72
|
+
return { isError: true, content: [{ type: 'text', text: JSON.stringify(err.bridgeError) }] };
|
|
73
|
+
}
|
|
74
|
+
throw err;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* ue_list_blueprints handler — lists Blueprint assets from the asset registry.
|
|
79
|
+
* BPR-04: returns all Blueprints with optional path_prefix filter.
|
|
80
|
+
*/
|
|
81
|
+
export async function handleListBlueprints(args) {
|
|
82
|
+
try {
|
|
83
|
+
const response = await bridge.sendCommand({
|
|
84
|
+
type: 'blueprint.list',
|
|
85
|
+
correlationId: '', // overwritten by sendCommand
|
|
86
|
+
payload: args.path_prefix ? { path_prefix: args.path_prefix } : {},
|
|
87
|
+
});
|
|
88
|
+
if (!response.success) {
|
|
89
|
+
return {
|
|
90
|
+
isError: true,
|
|
91
|
+
content: [{ type: 'text', text: JSON.stringify({ error: response.error ?? 'unknown_error' }) }],
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
return {
|
|
95
|
+
content: [{ type: 'text', text: JSON.stringify(response.data, null, 2) }],
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
catch (err) {
|
|
99
|
+
if (err instanceof PluginNotConnectedError) {
|
|
100
|
+
return { isError: true, content: [{ type: 'text', text: JSON.stringify(err.bridgeError) }] };
|
|
101
|
+
}
|
|
102
|
+
throw err;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
// ---------------------------------------------------------------------------
|
|
106
|
+
// sendOrDisconnect — shared helper for write handlers (Phase 10)
|
|
107
|
+
// Pattern copied from src/tools/editor/index.ts.
|
|
108
|
+
// ---------------------------------------------------------------------------
|
|
109
|
+
async function sendOrDisconnect(b, cmd) {
|
|
110
|
+
try {
|
|
111
|
+
const response = await b.sendCommand({ ...cmd, correlationId: '' });
|
|
112
|
+
if (!response.success) {
|
|
113
|
+
return {
|
|
114
|
+
isError: true,
|
|
115
|
+
content: [{ type: 'text', text: JSON.stringify({ error: response.error }) }],
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
return {
|
|
119
|
+
content: [{ type: 'text', text: JSON.stringify(response.data ?? {}) }],
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
catch (err) {
|
|
123
|
+
if (err instanceof PluginNotConnectedError) {
|
|
124
|
+
return {
|
|
125
|
+
isError: true,
|
|
126
|
+
content: [{ type: 'text', text: JSON.stringify(err.bridgeError) }],
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
throw err;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
// ---------------------------------------------------------------------------
|
|
133
|
+
// Blueprint Write handlers (Phase 10)
|
|
134
|
+
// ---------------------------------------------------------------------------
|
|
135
|
+
/**
|
|
136
|
+
* ue_create_blueprint handler — creates a new Blueprint asset via plugin bridge.
|
|
137
|
+
* BPW-01: returns assetPath and parentClass on success.
|
|
138
|
+
*/
|
|
139
|
+
export async function handleCreateBlueprint(args, b = bridge) {
|
|
140
|
+
return sendOrDisconnect(b, {
|
|
141
|
+
type: 'blueprint.create',
|
|
142
|
+
payload: { parent_class: args.parent_class, asset_path: args.asset_path },
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* ue_add_blueprint_node handler — adds a node to a Blueprint graph via plugin bridge.
|
|
147
|
+
* BPW-02: returns nodeGuid, type, posX, posY on success.
|
|
148
|
+
*/
|
|
149
|
+
export async function handleAddBlueprintNode(args, b = bridge) {
|
|
150
|
+
return sendOrDisconnect(b, {
|
|
151
|
+
type: 'blueprint.addNode',
|
|
152
|
+
payload: {
|
|
153
|
+
asset_path: args.asset_path,
|
|
154
|
+
graph_name: args.graph_name,
|
|
155
|
+
node_type: args.node_type,
|
|
156
|
+
pos_x: args.pos_x ?? 0,
|
|
157
|
+
pos_y: args.pos_y ?? 0,
|
|
158
|
+
},
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* ue_connect_blueprint_pins handler — connects two pins via plugin bridge.
|
|
163
|
+
* BPW-03: returns connected:true with the four identifiers on success.
|
|
164
|
+
*/
|
|
165
|
+
export async function handleConnectBlueprintPins(args, b = bridge) {
|
|
166
|
+
return sendOrDisconnect(b, {
|
|
167
|
+
type: 'blueprint.connectPins',
|
|
168
|
+
payload: {
|
|
169
|
+
asset_path: args.asset_path,
|
|
170
|
+
graph_name: args.graph_name ?? 'EventGraph',
|
|
171
|
+
from_node_guid: args.from_node_guid,
|
|
172
|
+
from_pin_name: args.from_pin_name,
|
|
173
|
+
to_node_guid: args.to_node_guid,
|
|
174
|
+
to_pin_name: args.to_pin_name,
|
|
175
|
+
},
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* ue_add_blueprint_variable handler — adds a typed variable via plugin bridge.
|
|
180
|
+
* BPW-04: returns variableName and variableType on success.
|
|
181
|
+
*/
|
|
182
|
+
export async function handleAddBlueprintVariable(args, b = bridge) {
|
|
183
|
+
return sendOrDisconnect(b, {
|
|
184
|
+
type: 'blueprint.addVariable',
|
|
185
|
+
payload: {
|
|
186
|
+
asset_path: args.asset_path,
|
|
187
|
+
variable_name: args.variable_name,
|
|
188
|
+
variable_type: args.variable_type,
|
|
189
|
+
},
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* ue_set_blueprint_default handler — sets a default value on a variable or pin.
|
|
194
|
+
* BPW-05: returns set:true on success.
|
|
195
|
+
*/
|
|
196
|
+
export async function handleSetBlueprintDefault(args, b = bridge) {
|
|
197
|
+
return sendOrDisconnect(b, {
|
|
198
|
+
type: 'blueprint.setDefault',
|
|
199
|
+
payload: {
|
|
200
|
+
asset_path: args.asset_path,
|
|
201
|
+
target_type: args.target_type,
|
|
202
|
+
target_name: args.target_name,
|
|
203
|
+
graph_name: args.graph_name ?? 'EventGraph',
|
|
204
|
+
node_guid: args.node_guid,
|
|
205
|
+
pin_name: args.pin_name,
|
|
206
|
+
default_value: args.default_value,
|
|
207
|
+
},
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
// ---------------------------------------------------------------------------
|
|
211
|
+
// Phase 11: Blueprint-C++ Bridge constants and handlers
|
|
212
|
+
// ---------------------------------------------------------------------------
|
|
213
|
+
const BLUEPRINT_SPECIFIERS = new Set([
|
|
214
|
+
'BlueprintCallable',
|
|
215
|
+
'BlueprintReadWrite',
|
|
216
|
+
'BlueprintReadOnly',
|
|
217
|
+
'BlueprintPure',
|
|
218
|
+
'BlueprintImplementableEvent',
|
|
219
|
+
'BlueprintNativeEvent',
|
|
220
|
+
'BlueprintAssignable',
|
|
221
|
+
'BlueprintAuthorityOnly',
|
|
222
|
+
]);
|
|
223
|
+
/**
|
|
224
|
+
* ue_cpp_exposed_members handler — parses a C++ header file locally and returns
|
|
225
|
+
* all UFUNCTION/UPROPERTY members that have Blueprint-relevant specifiers.
|
|
226
|
+
* BPC-01: pure TypeScript parser operation, no plugin required.
|
|
227
|
+
*/
|
|
228
|
+
export async function handleCppExposedMembers(args) {
|
|
229
|
+
let safePath;
|
|
230
|
+
try {
|
|
231
|
+
safePath = validatePath(args.file_path, PROJECT_ROOT);
|
|
232
|
+
}
|
|
233
|
+
catch (err) {
|
|
234
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
235
|
+
return { isError: true, content: [{ type: 'text', text: `Path error: ${msg}` }] };
|
|
236
|
+
}
|
|
237
|
+
let content;
|
|
238
|
+
try {
|
|
239
|
+
content = await fs.readFile(safePath, 'utf8');
|
|
240
|
+
}
|
|
241
|
+
catch (err) {
|
|
242
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
243
|
+
return { isError: true, content: [{ type: 'text', text: `File read error: ${msg}` }] };
|
|
244
|
+
}
|
|
245
|
+
const result = parseCppFile(content);
|
|
246
|
+
if (!result.success) {
|
|
247
|
+
return { isError: true, content: [{ type: 'text', text: `Parse error: ${result.error}` }] };
|
|
248
|
+
}
|
|
249
|
+
const members = [];
|
|
250
|
+
for (const cls of result.data.classes) {
|
|
251
|
+
for (const prop of cls.properties) {
|
|
252
|
+
const bpSpecs = prop.specifiers.filter(s => BLUEPRINT_SPECIFIERS.has(s.split('=')[0].trim()));
|
|
253
|
+
if (bpSpecs.length > 0) {
|
|
254
|
+
members.push({ kind: 'property', name: prop.name, type: prop.type, specifiers: prop.specifiers, meta: prop.meta, line: prop.line, blueprintSpecifiers: bpSpecs });
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
for (const fn of cls.functions) {
|
|
258
|
+
const bpSpecs = fn.specifiers.filter(s => BLUEPRINT_SPECIFIERS.has(s.split('=')[0].trim()));
|
|
259
|
+
if (bpSpecs.length > 0) {
|
|
260
|
+
members.push({ kind: 'function', name: fn.name, returnType: fn.returnType, specifiers: fn.specifiers, meta: fn.meta, line: fn.line, blueprintSpecifiers: bpSpecs });
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
return { content: [{ type: 'text', text: JSON.stringify(members, null, 2) }] };
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* ue_find_blueprint_subclasses handler — finds all Blueprint assets subclassing
|
|
268
|
+
* a given C++ class via the UE Editor plugin bridge.
|
|
269
|
+
* BPC-02: requires plugin; returns plugin_not_connected when editor is not running.
|
|
270
|
+
*/
|
|
271
|
+
export async function handleFindBlueprintSubclasses(args) {
|
|
272
|
+
try {
|
|
273
|
+
const response = await bridge.sendCommand({
|
|
274
|
+
type: 'blueprint.subclasses',
|
|
275
|
+
correlationId: '',
|
|
276
|
+
payload: { class_name: args.class_name },
|
|
277
|
+
});
|
|
278
|
+
if (!response.success) {
|
|
279
|
+
return { isError: true, content: [{ type: 'text', text: JSON.stringify({ error: response.error ?? 'unknown_error' }) }] };
|
|
280
|
+
}
|
|
281
|
+
return { content: [{ type: 'text', text: JSON.stringify(response.data, null, 2) }] };
|
|
282
|
+
}
|
|
283
|
+
catch (err) {
|
|
284
|
+
if (err instanceof PluginNotConnectedError) {
|
|
285
|
+
return { isError: true, content: [{ type: 'text', text: JSON.stringify(err.bridgeError) }] };
|
|
286
|
+
}
|
|
287
|
+
throw err;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* ue_trace_cpp_in_blueprints handler — finds all Blueprint graph nodes that
|
|
292
|
+
* call or access a specific C++ member via the UE Editor plugin bridge.
|
|
293
|
+
* BPC-03: requires plugin; returns plugin_not_connected when editor is not running.
|
|
294
|
+
*/
|
|
295
|
+
export async function handleTraceCppInBlueprints(args) {
|
|
296
|
+
try {
|
|
297
|
+
const response = await bridge.sendCommand({
|
|
298
|
+
type: 'blueprint.cppUsage',
|
|
299
|
+
correlationId: '',
|
|
300
|
+
payload: { class_name: args.class_name, member_name: args.member_name },
|
|
301
|
+
});
|
|
302
|
+
if (!response.success) {
|
|
303
|
+
return { isError: true, content: [{ type: 'text', text: JSON.stringify({ error: response.error ?? 'unknown_error' }) }] };
|
|
304
|
+
}
|
|
305
|
+
return { content: [{ type: 'text', text: JSON.stringify(response.data, null, 2) }] };
|
|
306
|
+
}
|
|
307
|
+
catch (err) {
|
|
308
|
+
if (err instanceof PluginNotConnectedError) {
|
|
309
|
+
return { isError: true, content: [{ type: 'text', text: JSON.stringify(err.bridgeError) }] };
|
|
310
|
+
}
|
|
311
|
+
throw err;
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* Register Blueprint tools on the MCP server.
|
|
316
|
+
*
|
|
317
|
+
* All tools in this domain require the MCPBridge editor plugin.
|
|
318
|
+
* When the plugin is not connected, each handler returns:
|
|
319
|
+
* { isError: true, content: [{ type: 'text', text: <plugin_not_connected JSON> }] }
|
|
320
|
+
*
|
|
321
|
+
* Tools registered:
|
|
322
|
+
* ue_read_blueprint — Read Blueprint parentClass, variables, and components
|
|
323
|
+
* ue_read_blueprint_graph — Read Blueprint event/function graph nodes and connections
|
|
324
|
+
* ue_list_blueprints — List Blueprint assets in the project
|
|
325
|
+
* ue_create_blueprint — Create a new Blueprint asset (Phase 10 stub)
|
|
326
|
+
* ue_add_blueprint_node — Add a node to a Blueprint graph (Phase 10 stub)
|
|
327
|
+
*
|
|
328
|
+
* @param server The McpServer instance to register tools on.
|
|
329
|
+
* @param injectedBridge Optional bridge instance for unit testing (Plan 10-03).
|
|
330
|
+
*/
|
|
331
|
+
export function registerBlueprintTools(server, injectedBridge) {
|
|
332
|
+
const b = injectedBridge ?? bridge;
|
|
333
|
+
// --------------------------------------------------------------------------
|
|
334
|
+
// ue_read_blueprint
|
|
335
|
+
// --------------------------------------------------------------------------
|
|
336
|
+
server.registerTool('ue_read_blueprint', {
|
|
337
|
+
title: 'Read Blueprint',
|
|
338
|
+
description: '[requires_plugin] Read a Blueprint asset\'s parentClass, variables, and components via the UE Editor plugin.',
|
|
339
|
+
inputSchema: z.object({
|
|
340
|
+
asset_path: z.string().describe('Asset path to the Blueprint (e.g., /Game/Blueprints/BP_MyActor)'),
|
|
341
|
+
}),
|
|
342
|
+
annotations: {
|
|
343
|
+
readOnlyHint: true,
|
|
344
|
+
destructiveHint: false,
|
|
345
|
+
},
|
|
346
|
+
}, withKnownIssues('ue_read_blueprint', handleReadBlueprint));
|
|
347
|
+
// --------------------------------------------------------------------------
|
|
348
|
+
// ue_list_blueprints
|
|
349
|
+
// --------------------------------------------------------------------------
|
|
350
|
+
server.registerTool('ue_list_blueprints', {
|
|
351
|
+
title: 'List Blueprints',
|
|
352
|
+
description: '[requires_plugin] List Blueprint assets in the project, optionally filtered by path prefix.',
|
|
353
|
+
inputSchema: z.object({
|
|
354
|
+
path_prefix: z
|
|
355
|
+
.string()
|
|
356
|
+
.optional()
|
|
357
|
+
.describe('Optional asset path prefix to filter results (e.g., /Game/Blueprints/)'),
|
|
358
|
+
}),
|
|
359
|
+
annotations: {
|
|
360
|
+
readOnlyHint: true,
|
|
361
|
+
destructiveHint: false,
|
|
362
|
+
},
|
|
363
|
+
}, withKnownIssues('ue_list_blueprints', handleListBlueprints));
|
|
364
|
+
// --------------------------------------------------------------------------
|
|
365
|
+
// ue_read_blueprint_graph
|
|
366
|
+
// --------------------------------------------------------------------------
|
|
367
|
+
server.registerTool('ue_read_blueprint_graph', {
|
|
368
|
+
title: 'Read Blueprint Graph',
|
|
369
|
+
description: '[requires_plugin] Read the nodes and connections in a Blueprint event graph or custom function graph.',
|
|
370
|
+
inputSchema: z.object({
|
|
371
|
+
asset_path: z.string().describe('Asset path to the Blueprint (e.g., /Game/Blueprints/BP_MyActor)'),
|
|
372
|
+
graph_name: z
|
|
373
|
+
.string()
|
|
374
|
+
.optional()
|
|
375
|
+
.describe('Graph name to read (e.g., "EventGraph" or a custom function name). Defaults to "EventGraph".'),
|
|
376
|
+
}),
|
|
377
|
+
annotations: {
|
|
378
|
+
readOnlyHint: true,
|
|
379
|
+
destructiveHint: false,
|
|
380
|
+
},
|
|
381
|
+
}, withKnownIssues('ue_read_blueprint_graph', handleReadBlueprintGraph));
|
|
382
|
+
// --------------------------------------------------------------------------
|
|
383
|
+
// ue_create_blueprint — BPW-01
|
|
384
|
+
// --------------------------------------------------------------------------
|
|
385
|
+
server.registerTool('ue_create_blueprint', {
|
|
386
|
+
title: 'Create Blueprint',
|
|
387
|
+
description: '[requires_plugin] Create a new Blueprint asset in the UE project via the UE Editor plugin.',
|
|
388
|
+
inputSchema: z.object({
|
|
389
|
+
parent_class: z.string().describe('The parent C++ or Blueprint class (e.g., AActor)'),
|
|
390
|
+
asset_path: z.string().describe('Asset path for the new Blueprint (e.g., /Game/Blueprints/BP_NewActor)'),
|
|
391
|
+
}),
|
|
392
|
+
annotations: {
|
|
393
|
+
readOnlyHint: false,
|
|
394
|
+
destructiveHint: false,
|
|
395
|
+
},
|
|
396
|
+
}, withKnownIssues('ue_create_blueprint', (args) => handleCreateBlueprint(args, b)));
|
|
397
|
+
// --------------------------------------------------------------------------
|
|
398
|
+
// ue_add_blueprint_node — BPW-02
|
|
399
|
+
// --------------------------------------------------------------------------
|
|
400
|
+
server.registerTool('ue_add_blueprint_node', {
|
|
401
|
+
title: 'Add Blueprint Node',
|
|
402
|
+
description: '[requires_plugin] Add a node to a Blueprint graph via the UE Editor plugin.',
|
|
403
|
+
inputSchema: z.object({
|
|
404
|
+
asset_path: z.string().describe('Asset path to the Blueprint (e.g., /Game/Blueprints/BP_MyActor)'),
|
|
405
|
+
graph_name: z.string().describe('The graph to add the node to (e.g., EventGraph)'),
|
|
406
|
+
node_type: z.string().describe('The node type to add (e.g., K2Node_CallFunction)'),
|
|
407
|
+
pos_x: z.number().optional().describe('X position in the graph (default: 0)'),
|
|
408
|
+
pos_y: z.number().optional().describe('Y position in the graph (default: 0)'),
|
|
409
|
+
}),
|
|
410
|
+
annotations: {
|
|
411
|
+
readOnlyHint: false,
|
|
412
|
+
destructiveHint: false,
|
|
413
|
+
},
|
|
414
|
+
}, withKnownIssues('ue_add_blueprint_node', (args) => handleAddBlueprintNode(args, b)));
|
|
415
|
+
// --------------------------------------------------------------------------
|
|
416
|
+
// ue_connect_blueprint_pins — BPW-03
|
|
417
|
+
// --------------------------------------------------------------------------
|
|
418
|
+
server.registerTool('ue_connect_blueprint_pins', {
|
|
419
|
+
title: 'Connect Blueprint Pins',
|
|
420
|
+
description: '[requires_plugin] Connect two pins in a Blueprint graph by node GUID and pin name.',
|
|
421
|
+
inputSchema: z.object({
|
|
422
|
+
asset_path: z.string().describe('Asset path to the Blueprint (e.g., /Game/Blueprints/BP_MyActor)'),
|
|
423
|
+
graph_name: z.string().optional().describe('Graph name (default: "EventGraph")'),
|
|
424
|
+
from_node_guid: z.string().describe('GUID of the source node'),
|
|
425
|
+
from_pin_name: z.string().describe('Name of the output pin on the source node'),
|
|
426
|
+
to_node_guid: z.string().describe('GUID of the destination node'),
|
|
427
|
+
to_pin_name: z.string().describe('Name of the input pin on the destination node'),
|
|
428
|
+
}),
|
|
429
|
+
annotations: { readOnlyHint: false, destructiveHint: false },
|
|
430
|
+
}, withKnownIssues('ue_connect_blueprint_pins', (args) => handleConnectBlueprintPins(args, b)));
|
|
431
|
+
// --------------------------------------------------------------------------
|
|
432
|
+
// ue_add_blueprint_variable — BPW-04
|
|
433
|
+
// --------------------------------------------------------------------------
|
|
434
|
+
server.registerTool('ue_add_blueprint_variable', {
|
|
435
|
+
title: 'Add Blueprint Variable',
|
|
436
|
+
description: '[requires_plugin] Add a new typed variable to a Blueprint via the UE Editor plugin.',
|
|
437
|
+
inputSchema: z.object({
|
|
438
|
+
asset_path: z.string().describe('Asset path to the Blueprint'),
|
|
439
|
+
variable_name: z.string().describe('Name for the new variable (e.g., Health)'),
|
|
440
|
+
variable_type: z.string().describe('Type category for the variable. Supported: bool, int, int64, float, double, string, name, text, object, class, struct, vector, rotator, transform'),
|
|
441
|
+
}),
|
|
442
|
+
annotations: { readOnlyHint: false, destructiveHint: false },
|
|
443
|
+
}, withKnownIssues('ue_add_blueprint_variable', (args) => handleAddBlueprintVariable(args, b)));
|
|
444
|
+
// --------------------------------------------------------------------------
|
|
445
|
+
// ue_set_blueprint_default — BPW-05
|
|
446
|
+
// --------------------------------------------------------------------------
|
|
447
|
+
server.registerTool('ue_set_blueprint_default', {
|
|
448
|
+
title: 'Set Blueprint Default Value',
|
|
449
|
+
description: '[requires_plugin] Set the default value on a Blueprint variable or node pin.',
|
|
450
|
+
inputSchema: z.object({
|
|
451
|
+
asset_path: z.string().describe('Asset path to the Blueprint'),
|
|
452
|
+
target_type: z.enum(['variable', 'pin']).describe('"variable" to set a variable default, "pin" to set a node pin default'),
|
|
453
|
+
target_name: z.string().optional().describe('Variable name (when target_type is "variable")'),
|
|
454
|
+
graph_name: z.string().optional().describe('Graph name (when target_type is "pin", default: "EventGraph")'),
|
|
455
|
+
node_guid: z.string().optional().describe('Node GUID (when target_type is "pin")'),
|
|
456
|
+
pin_name: z.string().optional().describe('Pin name (when target_type is "pin")'),
|
|
457
|
+
default_value: z.string().describe('The default value to set (as a string)'),
|
|
458
|
+
}),
|
|
459
|
+
annotations: { readOnlyHint: false, destructiveHint: false },
|
|
460
|
+
}, withKnownIssues('ue_set_blueprint_default', (args) => handleSetBlueprintDefault(args, b)));
|
|
461
|
+
// --------------------------------------------------------------------------
|
|
462
|
+
// ue_cpp_exposed_members — Phase 11, BPC-01 (pure parser, no plugin needed)
|
|
463
|
+
// --------------------------------------------------------------------------
|
|
464
|
+
server.registerTool('ue_cpp_exposed_members', {
|
|
465
|
+
title: 'Get Blueprint-Exposed C++ Members',
|
|
466
|
+
description: 'Parse a UE C++ header file and return all UFUNCTION/UPROPERTY members flagged as BlueprintCallable, BlueprintReadWrite, BlueprintReadOnly, BlueprintPure, BlueprintImplementableEvent, or BlueprintNativeEvent.',
|
|
467
|
+
inputSchema: z.object({
|
|
468
|
+
file_path: z.string().describe('Absolute path to the .h file to parse'),
|
|
469
|
+
}),
|
|
470
|
+
annotations: { readOnlyHint: true, destructiveHint: false },
|
|
471
|
+
}, withKnownIssues('ue_cpp_exposed_members', handleCppExposedMembers));
|
|
472
|
+
// --------------------------------------------------------------------------
|
|
473
|
+
// ue_find_blueprint_subclasses — Phase 11, BPC-02 (requires plugin)
|
|
474
|
+
// --------------------------------------------------------------------------
|
|
475
|
+
server.registerTool('ue_find_blueprint_subclasses', {
|
|
476
|
+
title: 'Find Blueprint Subclasses of C++ Class',
|
|
477
|
+
description: '[requires_plugin] Find all Blueprint assets in the project that subclass a given C++ class name.',
|
|
478
|
+
inputSchema: z.object({
|
|
479
|
+
class_name: z.string().describe('C++ class name to search for (e.g., "AMyActor")'),
|
|
480
|
+
}),
|
|
481
|
+
annotations: { readOnlyHint: true, destructiveHint: false },
|
|
482
|
+
}, withKnownIssues('ue_find_blueprint_subclasses', handleFindBlueprintSubclasses));
|
|
483
|
+
// --------------------------------------------------------------------------
|
|
484
|
+
// ue_trace_cpp_in_blueprints — Phase 11, BPC-03 (requires plugin)
|
|
485
|
+
// --------------------------------------------------------------------------
|
|
486
|
+
server.registerTool('ue_trace_cpp_in_blueprints', {
|
|
487
|
+
title: 'Trace C++ Member Usage in Blueprints',
|
|
488
|
+
description: '[requires_plugin] Find all Blueprint graphs that call or access a specific C++ UFUNCTION or UPROPERTY by class name and member name.',
|
|
489
|
+
inputSchema: z.object({
|
|
490
|
+
class_name: z.string().describe('C++ class name that owns the member (e.g., "AMyActor")'),
|
|
491
|
+
member_name: z.string().describe('Member name to search for (e.g., "Attack", "Health")'),
|
|
492
|
+
}),
|
|
493
|
+
annotations: { readOnlyHint: true, destructiveHint: false },
|
|
494
|
+
}, withKnownIssues('ue_trace_cpp_in_blueprints', handleTraceCppInBlueprints));
|
|
495
|
+
}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
// src/tools/build/index.ts
|
|
2
|
+
// Registers UE build tools on the MCP server with real implementations.
|
|
3
|
+
// Wires ue_build and ue_get_build_errors to runUbt, parseErrors, and suggestFix.
|
|
4
|
+
// Module-level state (lastBuildErrors) stores parsed results for ue_get_build_errors.
|
|
5
|
+
import { z } from 'zod';
|
|
6
|
+
import { withKnownIssues } from '../known-issues/middleware.js';
|
|
7
|
+
import { runUbt } from '../../build/ubt-runner.js';
|
|
8
|
+
import { parseErrors } from '../../build/error-parser.js';
|
|
9
|
+
import { suggestFix } from '../../build/fix-suggester.js';
|
|
10
|
+
import { validatePath } from '../../utils/path-guard.js';
|
|
11
|
+
import { PROJECT_ROOT } from '../../config.js';
|
|
12
|
+
import { DocIndex } from '../../docs/doc-index.js';
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
// Shared DocIndex instance (no records loaded by default; provides include hints
|
|
15
|
+
// when the doc data has been loaded externally via a shared instance).
|
|
16
|
+
// ---------------------------------------------------------------------------
|
|
17
|
+
const docIndex = new DocIndex();
|
|
18
|
+
let lastBuildErrors = [];
|
|
19
|
+
// ---------------------------------------------------------------------------
|
|
20
|
+
// registerBuildTools
|
|
21
|
+
// ---------------------------------------------------------------------------
|
|
22
|
+
/**
|
|
23
|
+
* Register UE build tools on the MCP server.
|
|
24
|
+
*
|
|
25
|
+
* Tools registered:
|
|
26
|
+
* ue_build — Trigger an Unreal Build Tool (UBT) build
|
|
27
|
+
* ue_get_build_errors — Retrieve the last build error list with fix suggestions
|
|
28
|
+
*
|
|
29
|
+
* @param server The McpServer instance to register tools on.
|
|
30
|
+
*/
|
|
31
|
+
export function registerBuildTools(server) {
|
|
32
|
+
// --------------------------------------------------------------------------
|
|
33
|
+
// ue_build
|
|
34
|
+
// --------------------------------------------------------------------------
|
|
35
|
+
server.registerTool('ue_build', {
|
|
36
|
+
title: 'Build UE Project',
|
|
37
|
+
description: 'Trigger an Unreal Build Tool (UBT) build for the specified target and configuration.',
|
|
38
|
+
inputSchema: z.object({
|
|
39
|
+
target: z.string().describe('The UBT build target (e.g., "MyProjectEditor")'),
|
|
40
|
+
configuration: z
|
|
41
|
+
.string()
|
|
42
|
+
.optional()
|
|
43
|
+
.describe('Build configuration (e.g., "Development", "Shipping"). Defaults to "Development".'),
|
|
44
|
+
platform: z
|
|
45
|
+
.string()
|
|
46
|
+
.optional()
|
|
47
|
+
.describe('Target platform (e.g., "Win64", "Linux"). Defaults to "Win64".'),
|
|
48
|
+
uprojectPath: z
|
|
49
|
+
.string()
|
|
50
|
+
.optional()
|
|
51
|
+
.describe('Absolute path to the .uproject file. Auto-discovered from PROJECT_ROOT when omitted.'),
|
|
52
|
+
}),
|
|
53
|
+
annotations: {
|
|
54
|
+
readOnlyHint: false,
|
|
55
|
+
destructiveHint: false,
|
|
56
|
+
},
|
|
57
|
+
}, withKnownIssues('ue_build', async (args) => {
|
|
58
|
+
// Validate uprojectPath before passing to runUbt (T-06-09 path traversal mitigation)
|
|
59
|
+
let validatedUprojectPath;
|
|
60
|
+
if (args.uprojectPath !== undefined) {
|
|
61
|
+
try {
|
|
62
|
+
validatedUprojectPath = validatePath(args.uprojectPath, PROJECT_ROOT);
|
|
63
|
+
}
|
|
64
|
+
catch (err) {
|
|
65
|
+
return {
|
|
66
|
+
isError: true,
|
|
67
|
+
content: [
|
|
68
|
+
{
|
|
69
|
+
type: 'text',
|
|
70
|
+
text: `Error: ${err instanceof Error ? err.message : String(err)}`,
|
|
71
|
+
},
|
|
72
|
+
],
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
// Invoke UBT — T-06-10: runUbt raises "Build already in progress" error
|
|
77
|
+
// which withKnownIssues catches and returns as isError. T-06-08: target
|
|
78
|
+
// is passed as an array argument, no shell interpolation.
|
|
79
|
+
let result;
|
|
80
|
+
try {
|
|
81
|
+
result = await runUbt({
|
|
82
|
+
target: args.target,
|
|
83
|
+
configuration: args.configuration,
|
|
84
|
+
platform: args.platform,
|
|
85
|
+
uprojectPath: validatedUprojectPath,
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
catch (err) {
|
|
89
|
+
return {
|
|
90
|
+
isError: true,
|
|
91
|
+
content: [
|
|
92
|
+
{
|
|
93
|
+
type: 'text',
|
|
94
|
+
text: `Error: ${err instanceof Error ? err.message : String(err)}`,
|
|
95
|
+
},
|
|
96
|
+
],
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
// Parse stdout + stderr for compiler diagnostics
|
|
100
|
+
const allLines = [
|
|
101
|
+
...result.stdout.split('\n'),
|
|
102
|
+
...result.stderr.split('\n'),
|
|
103
|
+
];
|
|
104
|
+
const errors = parseErrors(allLines);
|
|
105
|
+
// Attach fix suggestions and store in module-level state
|
|
106
|
+
lastBuildErrors = errors.map((e) => ({
|
|
107
|
+
error: e,
|
|
108
|
+
suggestions: suggestFix(e, docIndex),
|
|
109
|
+
}));
|
|
110
|
+
// Classify errors vs warnings
|
|
111
|
+
const errorCount = errors.filter((e) => e.severity === 'error').length;
|
|
112
|
+
const warningCount = errors.filter((e) => e.severity === 'warning').length;
|
|
113
|
+
// Format first 5 errors for the summary
|
|
114
|
+
const firstFiveErrors = errors
|
|
115
|
+
.filter((e) => e.severity === 'error')
|
|
116
|
+
.slice(0, 5)
|
|
117
|
+
.map((e) => ` ${e.file}(${e.line}): ${e.message}`)
|
|
118
|
+
.join('\n');
|
|
119
|
+
const summary = [
|
|
120
|
+
`Build completed in ${result.durationMs}ms. Exit code: ${result.exitCode}.`,
|
|
121
|
+
`Errors: ${errorCount} Warnings: ${warningCount}`,
|
|
122
|
+
firstFiveErrors.length > 0 ? firstFiveErrors : '',
|
|
123
|
+
'Run ue_get_build_errors for full structured output with fix suggestions.',
|
|
124
|
+
]
|
|
125
|
+
.filter((line) => line !== '')
|
|
126
|
+
.join('\n');
|
|
127
|
+
return {
|
|
128
|
+
isError: result.exitCode !== 0 && result.exitCode !== null,
|
|
129
|
+
content: [{ type: 'text', text: summary }],
|
|
130
|
+
};
|
|
131
|
+
}));
|
|
132
|
+
// --------------------------------------------------------------------------
|
|
133
|
+
// ue_get_build_errors
|
|
134
|
+
// --------------------------------------------------------------------------
|
|
135
|
+
server.registerTool('ue_get_build_errors', {
|
|
136
|
+
title: 'Get UE Build Errors',
|
|
137
|
+
description: 'Retrieve the error and warning list from the most recent Unreal Build Tool build, with fix suggestions.',
|
|
138
|
+
inputSchema: z.object({}),
|
|
139
|
+
annotations: {
|
|
140
|
+
readOnlyHint: true,
|
|
141
|
+
destructiveHint: false,
|
|
142
|
+
},
|
|
143
|
+
}, withKnownIssues('ue_get_build_errors', async (_args) => {
|
|
144
|
+
if (lastBuildErrors.length === 0) {
|
|
145
|
+
return {
|
|
146
|
+
content: [
|
|
147
|
+
{
|
|
148
|
+
type: 'text',
|
|
149
|
+
text: 'No build has been run yet. Call ue_build first.',
|
|
150
|
+
},
|
|
151
|
+
],
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
return {
|
|
155
|
+
content: [
|
|
156
|
+
{
|
|
157
|
+
type: 'text',
|
|
158
|
+
text: JSON.stringify(lastBuildErrors, null, 2),
|
|
159
|
+
},
|
|
160
|
+
],
|
|
161
|
+
};
|
|
162
|
+
}));
|
|
163
|
+
}
|