blueprint-extractor-mcp 3.0.1 → 3.2.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/dist/helpers/project-resolution.js +51 -2
- package/dist/helpers/subsystem.d.ts +18 -2
- package/dist/helpers/subsystem.js +74 -3
- package/dist/helpers/tool-results.js +36 -1
- package/dist/register-server-tools.d.ts +3 -1
- package/dist/register-server-tools.js +2 -1
- package/dist/resources/static-doc-resources.js +1 -1
- package/dist/schemas/tool-inputs.d.ts +17 -1
- package/dist/schemas/tool-inputs.js +7 -0
- package/dist/server-config.js +45 -0
- package/dist/server-factory.js +2 -2
- package/dist/tool-context.d.ts +1 -1
- package/dist/tools/project-control.js +286 -79
- package/dist/tools/schema-and-ai-authoring.d.ts +5 -2
- package/dist/tools/schema-and-ai-authoring.js +207 -10
- package/dist/ue-client.d.ts +3 -1
- package/dist/ue-client.js +26 -14
- package/package.json +2 -2
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { access } from 'node:fs/promises';
|
|
2
|
+
import { constants as fsConstants } from 'node:fs';
|
|
3
|
+
import { resolve } from 'node:path';
|
|
1
4
|
export function rememberExternalBuild(result) {
|
|
2
5
|
return {
|
|
3
6
|
success: result.success === true,
|
|
@@ -27,6 +30,31 @@ export async function getProjectAutomationContext(deps) {
|
|
|
27
30
|
setCachedContext(nextContext);
|
|
28
31
|
return nextContext;
|
|
29
32
|
}
|
|
33
|
+
let cachedHeuristicEngineRoot;
|
|
34
|
+
const HEURISTIC_ENGINE_CANDIDATES = [
|
|
35
|
+
'C:/Program Files/Epic Games/UE_5.6',
|
|
36
|
+
'C:/Program Files/Epic Games/UE_5.5',
|
|
37
|
+
'C:/Program Files/Epic Games/UE_5.4',
|
|
38
|
+
'C:/Program Files/Epic Games/UE_5.3',
|
|
39
|
+
];
|
|
40
|
+
const ENGINE_MARKER = 'Engine/Build/BatchFiles/Build.bat';
|
|
41
|
+
async function probeEngineRootHeuristic() {
|
|
42
|
+
if (cachedHeuristicEngineRoot !== undefined) {
|
|
43
|
+
return cachedHeuristicEngineRoot || undefined;
|
|
44
|
+
}
|
|
45
|
+
for (const candidate of HEURISTIC_ENGINE_CANDIDATES) {
|
|
46
|
+
try {
|
|
47
|
+
await access(resolve(candidate, ENGINE_MARKER), fsConstants.F_OK);
|
|
48
|
+
cachedHeuristicEngineRoot = candidate;
|
|
49
|
+
return candidate;
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
// not found, try next
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
cachedHeuristicEngineRoot = '';
|
|
56
|
+
return undefined;
|
|
57
|
+
}
|
|
30
58
|
export async function resolveProjectInputs(request, deps) {
|
|
31
59
|
const { getProjectAutomationContext, firstDefinedString, env = process.env, } = deps;
|
|
32
60
|
let context = null;
|
|
@@ -45,7 +73,28 @@ export async function resolveProjectInputs(request, deps) {
|
|
|
45
73
|
const engineRootFromEnv = firstDefinedString(env.UE_ENGINE_ROOT);
|
|
46
74
|
const projectPathFromEnv = firstDefinedString(env.UE_PROJECT_PATH);
|
|
47
75
|
const targetFromEnv = firstDefinedString(env.UE_PROJECT_TARGET, env.UE_EDITOR_TARGET);
|
|
48
|
-
|
|
76
|
+
let engineRoot = firstDefinedString(request.engine_root, engineRootFromContext, engineRootFromEnv);
|
|
77
|
+
let engineRootSource;
|
|
78
|
+
if (request.engine_root) {
|
|
79
|
+
engineRootSource = 'explicit';
|
|
80
|
+
}
|
|
81
|
+
else if (engineRootFromContext) {
|
|
82
|
+
engineRootSource = 'editor_context';
|
|
83
|
+
}
|
|
84
|
+
else if (engineRootFromEnv) {
|
|
85
|
+
engineRootSource = 'environment';
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
// Filesystem heuristic: probe common UE installation paths
|
|
89
|
+
const heuristicRoot = await probeEngineRootHeuristic();
|
|
90
|
+
if (heuristicRoot) {
|
|
91
|
+
engineRoot = heuristicRoot;
|
|
92
|
+
engineRootSource = 'filesystem_heuristic';
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
engineRootSource = 'missing';
|
|
96
|
+
}
|
|
97
|
+
}
|
|
49
98
|
const projectPath = firstDefinedString(request.project_path, projectPathFromContext, projectPathFromEnv);
|
|
50
99
|
const target = firstDefinedString(request.target, targetFromContext, targetFromEnv);
|
|
51
100
|
return {
|
|
@@ -55,7 +104,7 @@ export async function resolveProjectInputs(request, deps) {
|
|
|
55
104
|
context,
|
|
56
105
|
contextError,
|
|
57
106
|
sources: {
|
|
58
|
-
engineRoot:
|
|
107
|
+
engineRoot: engineRootSource,
|
|
59
108
|
projectPath: request.project_path ? 'explicit' : projectPathFromContext ? 'editor_context' : projectPathFromEnv ? 'environment' : 'missing',
|
|
60
109
|
target: request.target ? 'explicit' : targetFromContext ? 'editor_context' : targetFromEnv ? 'environment' : 'missing',
|
|
61
110
|
},
|
|
@@ -1,13 +1,29 @@
|
|
|
1
1
|
import type { CallToolResult, ContentBlock } from '@modelcontextprotocol/sdk/types.js';
|
|
2
|
+
export interface SubsystemCallOptions {
|
|
3
|
+
timeoutMs?: number;
|
|
4
|
+
}
|
|
2
5
|
type SubsystemClientLike = {
|
|
3
|
-
callSubsystem(method: string, params: Record<string, unknown
|
|
6
|
+
callSubsystem(method: string, params: Record<string, unknown>, options?: SubsystemCallOptions): Promise<string>;
|
|
4
7
|
};
|
|
5
|
-
export declare function callSubsystemJson(client: SubsystemClientLike, method: string, params: Record<string, unknown
|
|
8
|
+
export declare function callSubsystemJson(client: SubsystemClientLike, method: string, params: Record<string, unknown>, options?: SubsystemCallOptions): Promise<Record<string, unknown>>;
|
|
6
9
|
export declare function jsonToolSuccess(parsed: unknown, options?: {
|
|
7
10
|
extraContent?: ContentBlock[];
|
|
8
11
|
}): CallToolResult & {
|
|
9
12
|
structuredContent: Record<string, unknown>;
|
|
10
13
|
};
|
|
14
|
+
/**
|
|
15
|
+
* Strips the C++ 'F' prefix from USTRUCT script paths.
|
|
16
|
+
* UE registers USTRUCTs without the F prefix in script paths.
|
|
17
|
+
* e.g., /Script/Module.FSTCFoo → /Script/Module.STCFoo
|
|
18
|
+
*
|
|
19
|
+
* Only strips when the class name starts with F followed by an uppercase letter,
|
|
20
|
+
* matching the UE USTRUCT naming convention.
|
|
21
|
+
*/
|
|
22
|
+
export declare function normalizeUStructPath(path: string): string;
|
|
23
|
+
export declare function normalizeUStructPaths(paths: string[]): {
|
|
24
|
+
normalized: string[];
|
|
25
|
+
warnings: string[];
|
|
26
|
+
};
|
|
11
27
|
export declare function jsonToolError(e: unknown): {
|
|
12
28
|
content: {
|
|
13
29
|
type: "text";
|
|
@@ -1,19 +1,90 @@
|
|
|
1
1
|
import { isRecord } from './formatting.js';
|
|
2
|
-
export async function callSubsystemJson(client, method, params) {
|
|
3
|
-
const result = await client.callSubsystem(method, params);
|
|
2
|
+
export async function callSubsystemJson(client, method, params, options) {
|
|
3
|
+
const result = await client.callSubsystem(method, params, options);
|
|
4
|
+
if (process.env.MCP_DEBUG_RESPONSES) {
|
|
5
|
+
process.stderr.write(`[MCP_DEBUG] ${method} raw response: ${result}\n`);
|
|
6
|
+
}
|
|
4
7
|
const parsed = JSON.parse(result);
|
|
5
8
|
if (typeof parsed.error === 'string' && parsed.error.length > 0) {
|
|
6
|
-
|
|
9
|
+
const err = new Error(parsed.error);
|
|
10
|
+
err.ueResponse = parsed;
|
|
11
|
+
throw err;
|
|
12
|
+
}
|
|
13
|
+
// Check for error-only failure responses (success: false with an explicit error message
|
|
14
|
+
// but no business-level fields). Structured responses with success: false are passed
|
|
15
|
+
// through so tool code can inspect them for orchestration (e.g., fallback strategies).
|
|
16
|
+
if (parsed.success === false) {
|
|
17
|
+
const explicitMessage = parsed.message ?? parsed.errorMessage;
|
|
18
|
+
if (typeof explicitMessage === 'string' && explicitMessage.length > 0) {
|
|
19
|
+
const err = new Error(explicitMessage);
|
|
20
|
+
err.ueResponse = parsed;
|
|
21
|
+
throw err;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
// Catch structured error responses with diagnostics but no explicit message.
|
|
25
|
+
// These come from FAssetMutationContext.BuildResult(false) in the C++ plugin.
|
|
26
|
+
if (parsed.success === false
|
|
27
|
+
&& Array.isArray(parsed.diagnostics)
|
|
28
|
+
&& parsed.diagnostics.length > 0) {
|
|
29
|
+
const messages = parsed.diagnostics
|
|
30
|
+
.filter((d) => typeof d === 'object' && d !== null && typeof d.message === 'string')
|
|
31
|
+
.map((d) => d.message);
|
|
32
|
+
const synthesized = messages.length > 0
|
|
33
|
+
? messages.join('; ')
|
|
34
|
+
: `Operation failed with ${parsed.diagnostics.length} diagnostic(s)`;
|
|
35
|
+
const err = new Error(synthesized);
|
|
36
|
+
err.ueResponse = parsed;
|
|
37
|
+
throw err;
|
|
38
|
+
}
|
|
39
|
+
if (Array.isArray(parsed.errors) && parsed.errors.length > 0) {
|
|
40
|
+
const firstError = parsed.errors[0];
|
|
41
|
+
const err = new Error(typeof firstError === 'string' ? firstError : JSON.stringify(firstError));
|
|
42
|
+
err.ueResponse = parsed;
|
|
43
|
+
throw err;
|
|
44
|
+
}
|
|
45
|
+
if (Object.keys(parsed).length === 0) {
|
|
46
|
+
throw new Error('Empty response from subsystem');
|
|
7
47
|
}
|
|
8
48
|
return parsed;
|
|
9
49
|
}
|
|
10
50
|
export function jsonToolSuccess(parsed, options = {}) {
|
|
11
51
|
const structuredContent = isRecord(parsed) ? parsed : { data: parsed };
|
|
52
|
+
// Guard: if the UE response indicates failure, route through error path.
|
|
53
|
+
// This prevents tool handlers from accidentally passing error payloads as successes.
|
|
54
|
+
if (isRecord(parsed) && parsed.success === false) {
|
|
55
|
+
return {
|
|
56
|
+
content: [{ type: 'text', text: `Error: ${typeof parsed.message === 'string' ? parsed.message : 'Operation failed'}` }],
|
|
57
|
+
structuredContent,
|
|
58
|
+
isError: true,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
12
61
|
return {
|
|
13
62
|
content: options.extraContent ? [...options.extraContent] : [],
|
|
14
63
|
structuredContent,
|
|
15
64
|
};
|
|
16
65
|
}
|
|
66
|
+
/**
|
|
67
|
+
* Strips the C++ 'F' prefix from USTRUCT script paths.
|
|
68
|
+
* UE registers USTRUCTs without the F prefix in script paths.
|
|
69
|
+
* e.g., /Script/Module.FSTCFoo → /Script/Module.STCFoo
|
|
70
|
+
*
|
|
71
|
+
* Only strips when the class name starts with F followed by an uppercase letter,
|
|
72
|
+
* matching the UE USTRUCT naming convention.
|
|
73
|
+
*/
|
|
74
|
+
export function normalizeUStructPath(path) {
|
|
75
|
+
return path.replace(/^(\/Script\/[^.]+\.)F([A-Z])/, '$1$2');
|
|
76
|
+
}
|
|
77
|
+
export function normalizeUStructPaths(paths) {
|
|
78
|
+
const warnings = [];
|
|
79
|
+
const normalized = paths.map(p => {
|
|
80
|
+
const result = normalizeUStructPath(p);
|
|
81
|
+
if (result !== p) {
|
|
82
|
+
warnings.push(`Auto-normalized F-prefix: "${p}" → "${result}"`);
|
|
83
|
+
}
|
|
84
|
+
return result;
|
|
85
|
+
});
|
|
86
|
+
return { normalized, warnings };
|
|
87
|
+
}
|
|
17
88
|
export function jsonToolError(e) {
|
|
18
89
|
return {
|
|
19
90
|
content: [{ type: 'text', text: `Error: ${e instanceof Error ? e.message : String(e)}` }],
|
|
@@ -65,9 +65,25 @@ export function createToolResultNormalizers({ taskAwareTools, classifyRecoverabl
|
|
|
65
65
|
const diagnostics = Array.isArray(payload.diagnostics)
|
|
66
66
|
? payload.diagnostics
|
|
67
67
|
: [];
|
|
68
|
+
// Merge diagnostics from ueResponse if the error carries one (set by callSubsystemJson).
|
|
69
|
+
if (diagnostics.length === 0
|
|
70
|
+
&& payloadOrError instanceof Error
|
|
71
|
+
&& isRecord(payloadOrError.ueResponse)) {
|
|
72
|
+
const ueResp = payloadOrError.ueResponse;
|
|
73
|
+
if (Array.isArray(ueResp.diagnostics)) {
|
|
74
|
+
diagnostics.push(...ueResp.diagnostics);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
68
77
|
const firstDiagnostic = diagnostics.find((candidate) => (isRecord(candidate)
|
|
69
78
|
&& typeof candidate.message === 'string'
|
|
70
79
|
&& candidate.message.length > 0));
|
|
80
|
+
const existingContentText = existingResult
|
|
81
|
+
&& Array.isArray(existingResult.content)
|
|
82
|
+
&& isRecord(existingResult.content[0])
|
|
83
|
+
&& existingResult.content[0].type === 'text'
|
|
84
|
+
&& typeof existingResult.content[0].text === 'string'
|
|
85
|
+
? existingResult.content[0].text.replace(/^Error:\s*/, '')
|
|
86
|
+
: undefined;
|
|
71
87
|
const message = typeof payload.message === 'string'
|
|
72
88
|
? payload.message.replace(/^Error:\s*/, '')
|
|
73
89
|
: typeof payload.error === 'string'
|
|
@@ -78,7 +94,26 @@ export function createToolResultNormalizers({ taskAwareTools, classifyRecoverabl
|
|
|
78
94
|
? payloadOrError.message
|
|
79
95
|
: typeof payloadOrError === 'string'
|
|
80
96
|
? payloadOrError.replace(/^Error:\s*/, '')
|
|
81
|
-
:
|
|
97
|
+
: typeof existingContentText === 'string'
|
|
98
|
+
? existingContentText
|
|
99
|
+
: payloadOrError == null
|
|
100
|
+
? `Tool '${toolName}' failed with no error details (received ${String(payloadOrError)})`
|
|
101
|
+
: (() => {
|
|
102
|
+
const type = payloadOrError?.constructor?.name ?? typeof payloadOrError;
|
|
103
|
+
const keys = isRecord(payloadOrError) ? Object.keys(payloadOrError).join(', ') : '';
|
|
104
|
+
const truncatedJson = (() => {
|
|
105
|
+
try {
|
|
106
|
+
const s = JSON.stringify(payloadOrError);
|
|
107
|
+
return s.length > 500 ? s.slice(0, 500) + '…' : s;
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
return '[unserializable]';
|
|
111
|
+
}
|
|
112
|
+
})();
|
|
113
|
+
return keys
|
|
114
|
+
? `Tool '${toolName}' failed — received ${type} with keys [${keys}]: ${truncatedJson}`
|
|
115
|
+
: `Tool '${toolName}' failed — received ${type}: ${truncatedJson}`;
|
|
116
|
+
})();
|
|
82
117
|
const classification = classifyRecoverableToolFailure(toolName, message);
|
|
83
118
|
const envelope = {
|
|
84
119
|
...payload,
|
|
@@ -4,7 +4,9 @@ import { type ToolHelpEntry } from './helpers/tool-help.js';
|
|
|
4
4
|
import type { ProjectControllerLike, CompileProjectCodeResult } from './project-controller.js';
|
|
5
5
|
import type { ProjectAutomationContext, ResolvedProjectInputs } from './tool-context.js';
|
|
6
6
|
import { UEClient } from './ue-client.js';
|
|
7
|
-
type JsonSubsystemCaller = (method: string, params: Record<string, unknown
|
|
7
|
+
type JsonSubsystemCaller = (method: string, params: Record<string, unknown>, options?: {
|
|
8
|
+
timeoutMs?: number;
|
|
9
|
+
}) => Promise<Record<string, unknown>>;
|
|
8
10
|
type UEClientLike = Pick<UEClient, 'callSubsystem'> & Partial<Pick<UEClient, 'checkConnection'>>;
|
|
9
11
|
type ResolveProjectInputsFn = (request: {
|
|
10
12
|
engine_root?: string;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { exampleCatalog } from './catalogs/example-catalog.js';
|
|
3
3
|
import { collectRelatedResources, collectToolExampleFamilies as collectToolExampleFamiliesFromCatalog, summarizeOutputSchema, summarizeSchemaFields, } from './helpers/tool-help.js';
|
|
4
|
-
import { AnimMontageMutationOperationSchema, AnimationNotifySelectorSchema, AnimSequenceMutationOperationSchema, BehaviorTreeMutationOperationSchema, BehaviorTreeNodeSelectorSchema, BlackboardKeySchema, BlackboardMutationOperationSchema, BlendParameterSchema, BlendSpaceMutationOperationSchema, BlendSpaceSampleSchema, BlueprintGraphMutationOperationSchema, BlueprintMemberMutationOperationSchema, BuildConfigurationSchema, BuildPlatformSchema, CurveChannelSchema, CurveKeyDeleteSchema, CurveKeyUpsertSchema, CurveTableModeSchema, CurveTableRowSchema, CurveTypeSchema, DataTableRowSchema, ExtractAssetTypeSchema, EnhancedInputValueTypeSchema, FontImportItemSchema, ImportJobListSchema, ImportJobSchema, ImportPayloadSchema, InputMappingSchema, JsonObjectSchema, MaterialConnectionSelectorFieldsSchema, MaterialFontParameterSchema, MaterialFunctionAssetKindSchema, MaterialGraphOperationKindSchema, MaterialGraphOperationSchema, MaterialGraphPayloadSchema, MaterialLayerStackSchema, MaterialNodePositionSchema, MaterialScalarParameterSchema, MaterialStaticSwitchParameterSchema, MaterialTextureParameterSchema, MaterialVectorParameterSchema, MeshImportPayloadSchema, StateTreeEditorNodeSelectorSchema, StateTreeMutationOperationSchema, StateTreeStateSelectorSchema, StateTreeTransitionSelectorSchema, TextureImportPayloadSchema, UserDefinedEnumEntrySchema, UserDefinedEnumMutationOperationSchema, UserDefinedStructFieldSchema, UserDefinedStructMutationOperationSchema, WidgetBlueprintMutationOperationSchema, WidgetNodeSchema, WidgetSelectorFieldsSchema, WindowFontApplicationSchema, } from './schemas/tool-inputs.js';
|
|
4
|
+
import { AnimMontageMutationOperationSchema, AnimationNotifySelectorSchema, AnimSequenceMutationOperationSchema, BehaviorTreeMutationOperationSchema, BehaviorTreeNodeSelectorSchema, BlackboardKeySchema, BlackboardMutationOperationSchema, BlendParameterSchema, BlendSpaceMutationOperationSchema, BlendSpaceSampleSchema, BlueprintGraphMutationOperationSchema, BlueprintMemberMutationOperationSchema, BuildConfigurationSchema, BuildPlatformSchema, CurveChannelSchema, CurveKeyDeleteSchema, CurveKeyUpsertSchema, CurveTableModeSchema, CurveTableRowSchema, CurveTypeSchema, DataTableRowSchema, ExtractAssetTypeSchema, EnhancedInputValueTypeSchema, FontImportItemSchema, ImportJobListSchema, ImportJobSchema, ImportPayloadSchema, InputMappingSchema, JsonObjectSchema, MaterialConnectionSelectorFieldsSchema, MaterialFontParameterSchema, MaterialFunctionAssetKindSchema, MaterialGraphOperationKindSchema, MaterialGraphOperationSchema, MaterialGraphPayloadSchema, MaterialLayerStackSchema, MaterialNodePositionSchema, MaterialScalarParameterSchema, MaterialStaticSwitchParameterSchema, MaterialTextureParameterSchema, MaterialVectorParameterSchema, MeshImportPayloadSchema, StateTreeEditorNodeSelectorSchema, StateTreeMutationOperationSchema, StateTreeStateSelectorSchema, StateTreeTransitionSelectorSchema, StateTreeBindingSchema, TextureImportPayloadSchema, UserDefinedEnumEntrySchema, UserDefinedEnumMutationOperationSchema, UserDefinedStructFieldSchema, UserDefinedStructMutationOperationSchema, WidgetBlueprintMutationOperationSchema, WidgetNodeSchema, WidgetSelectorFieldsSchema, WindowFontApplicationSchema, } from './schemas/tool-inputs.js';
|
|
5
5
|
import { applyWindowUiChangesResultSchema, AutomationRunListSchema, automationRunSchema, CaptureResultSchema, CascadeResultSchema, CleanupCapturesResultSchema, CompareCaptureResultSchema, CompareMotionCaptureBundleResultSchema, CreateModifyWidgetAnimationResultSchema, ExtractWidgetAnimationResultSchema, ListCapturesResultSchema, motionCaptureModeSchema, MotionCaptureBundleResultSchema, widgetAnimationCheckpointSchema, } from './schemas/tool-results.js';
|
|
6
6
|
import { registerAnimationAuthoringTools } from './tools/animation-authoring.js';
|
|
7
7
|
import { registerAutomationRunTools } from './tools/automation-runs.js';
|
|
@@ -166,6 +166,7 @@ export function registerServerTools({ server, client, projectController, automat
|
|
|
166
166
|
stateTreeStateSelectorSchema: StateTreeStateSelectorSchema,
|
|
167
167
|
stateTreeEditorNodeSelectorSchema: StateTreeEditorNodeSelectorSchema,
|
|
168
168
|
stateTreeTransitionSelectorSchema: StateTreeTransitionSelectorSchema,
|
|
169
|
+
stateTreeBindingSchema: StateTreeBindingSchema,
|
|
169
170
|
});
|
|
170
171
|
registerAnimationAuthoringTools({
|
|
171
172
|
server,
|
|
@@ -68,7 +68,7 @@ export function registerStaticDocResources(server) {
|
|
|
68
68
|
'- AnimSequence: notify selector by notifyId/notifyGuid with notifyIndex or track metadata as fallback; operations replace_notifies, patch_notify, replace_sync_markers, replace_curve_metadata.',
|
|
69
69
|
'- AnimMontage: notify selector by notifyId/notifyGuid with notifyIndex or track metadata as fallback; operations replace_notifies, patch_notify, replace_sections, replace_slots.',
|
|
70
70
|
'- BlendSpace: sample selector by sampleIndex; operations replace_samples, patch_sample, set_axes.',
|
|
71
|
-
'- Blueprint members: selectors by variableName, componentName, and functionName; operations replace_variables, patch_variable, replace_components, patch_component, replace_function_stubs, patch_class_defaults, compile.',
|
|
71
|
+
'- Blueprint members: selectors by variableName, componentName, and functionName; operations replace_variables, patch_variable, replace_components, patch_component, add_component, replace_function_stubs, patch_class_defaults, compile.',
|
|
72
72
|
'- Blueprint graphs: operation upsert_function_graphs preserves unrelated graphs; append_function_call_to_sequence patches an existing sequence-style initializer without replacing the whole graph.',
|
|
73
73
|
'',
|
|
74
74
|
'WidgetBlueprint guidance:',
|
|
@@ -3038,7 +3038,7 @@ export declare const StateTreeMutationOperationSchema: z.ZodEnum<["replace_tree"
|
|
|
3038
3038
|
export declare const AnimSequenceMutationOperationSchema: z.ZodEnum<["replace_notifies", "patch_notify", "replace_sync_markers", "replace_curve_metadata"]>;
|
|
3039
3039
|
export declare const AnimMontageMutationOperationSchema: z.ZodEnum<["replace_notifies", "patch_notify", "replace_sections", "replace_slots"]>;
|
|
3040
3040
|
export declare const BlendSpaceMutationOperationSchema: z.ZodEnum<["replace_samples", "patch_sample", "set_axes"]>;
|
|
3041
|
-
export declare const BlueprintMemberMutationOperationSchema: z.ZodEnum<["replace_variables", "patch_variable", "replace_components", "patch_component", "replace_function_stubs", "patch_class_defaults", "compile"]>;
|
|
3041
|
+
export declare const BlueprintMemberMutationOperationSchema: z.ZodEnum<["replace_variables", "patch_variable", "replace_components", "patch_component", "add_component", "replace_function_stubs", "patch_class_defaults", "compile"]>;
|
|
3042
3042
|
export declare const BlueprintGraphMutationOperationSchema: z.ZodEnum<["upsert_function_graphs", "append_function_call_to_sequence", "compile"]>;
|
|
3043
3043
|
export declare const UserDefinedStructFieldSchema: z.ZodObject<{
|
|
3044
3044
|
guid: z.ZodOptional<z.ZodString>;
|
|
@@ -3146,6 +3146,22 @@ export declare const StateTreeTransitionSelectorSchema: z.ZodObject<{
|
|
|
3146
3146
|
transitionId: z.ZodOptional<z.ZodString>;
|
|
3147
3147
|
id: z.ZodOptional<z.ZodString>;
|
|
3148
3148
|
}, z.ZodTypeAny, "passthrough">>;
|
|
3149
|
+
export declare const StateTreeBindingSchema: z.ZodObject<{
|
|
3150
|
+
sourceTask: z.ZodString;
|
|
3151
|
+
sourceProperty: z.ZodString;
|
|
3152
|
+
targetTask: z.ZodString;
|
|
3153
|
+
targetProperty: z.ZodString;
|
|
3154
|
+
}, "strip", z.ZodTypeAny, {
|
|
3155
|
+
sourceTask: string;
|
|
3156
|
+
sourceProperty: string;
|
|
3157
|
+
targetTask: string;
|
|
3158
|
+
targetProperty: string;
|
|
3159
|
+
}, {
|
|
3160
|
+
sourceTask: string;
|
|
3161
|
+
sourceProperty: string;
|
|
3162
|
+
targetTask: string;
|
|
3163
|
+
targetProperty: string;
|
|
3164
|
+
}>;
|
|
3149
3165
|
export declare const AnimationNotifySelectorSchema: z.ZodObject<{
|
|
3150
3166
|
notifyId: z.ZodOptional<z.ZodString>;
|
|
3151
3167
|
notifyGuid: z.ZodOptional<z.ZodString>;
|
|
@@ -359,6 +359,7 @@ export const BlueprintMemberMutationOperationSchema = z.enum([
|
|
|
359
359
|
'patch_variable',
|
|
360
360
|
'replace_components',
|
|
361
361
|
'patch_component',
|
|
362
|
+
'add_component',
|
|
362
363
|
'replace_function_stubs',
|
|
363
364
|
'patch_class_defaults',
|
|
364
365
|
'compile',
|
|
@@ -408,6 +409,12 @@ export const StateTreeTransitionSelectorSchema = z.object({
|
|
|
408
409
|
transitionId: z.string().optional(),
|
|
409
410
|
id: z.string().optional(),
|
|
410
411
|
}).passthrough();
|
|
412
|
+
export const StateTreeBindingSchema = z.object({
|
|
413
|
+
sourceTask: z.string().describe('Name of the source task whose output provides the value'),
|
|
414
|
+
sourceProperty: z.string().describe('Property name on the source task to read from'),
|
|
415
|
+
targetTask: z.string().describe('Name of the target task whose input receives the value'),
|
|
416
|
+
targetProperty: z.string().describe('Property name on the target task to write to'),
|
|
417
|
+
}).describe('Task output-to-input binding (requires C++ plugin support — not yet implemented)');
|
|
411
418
|
export const AnimationNotifySelectorSchema = z.object({
|
|
412
419
|
notifyId: z.string().optional(),
|
|
413
420
|
notifyGuid: z.string().optional(),
|
package/dist/server-config.js
CHANGED
|
@@ -69,5 +69,50 @@ export function classifyRecoverableToolFailure(toolName, message) {
|
|
|
69
69
|
],
|
|
70
70
|
};
|
|
71
71
|
}
|
|
72
|
+
if (message.includes('timed out') || message.includes('timeout') || message.includes('ETIMEDOUT') || message.includes('ESOCKETTIMEDOUT')) {
|
|
73
|
+
return {
|
|
74
|
+
code: 'timeout',
|
|
75
|
+
recoverable: true,
|
|
76
|
+
retry_after_ms: 5000,
|
|
77
|
+
next_steps: [
|
|
78
|
+
'Retry with simpler payload or increase timeout',
|
|
79
|
+
'Check if UE editor is responding (call wait_for_editor)',
|
|
80
|
+
'For StateTree tools, try splitting complex payloads into multiple calls',
|
|
81
|
+
],
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
if (message.includes('JSON') || message.includes('Unexpected token') || message.includes('SyntaxError')) {
|
|
85
|
+
return {
|
|
86
|
+
code: 'invalid_response',
|
|
87
|
+
recoverable: true,
|
|
88
|
+
next_steps: [
|
|
89
|
+
'Check UE editor output log for errors',
|
|
90
|
+
'The editor may have returned an HTML error page instead of JSON',
|
|
91
|
+
'Retry the operation — this may be a transient serialization issue',
|
|
92
|
+
],
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
if (message.includes('locked by another process') || message.includes('locked file') || message.includes('cannot access the file')) {
|
|
96
|
+
return {
|
|
97
|
+
code: 'locked_file',
|
|
98
|
+
recoverable: true,
|
|
99
|
+
next_steps: [
|
|
100
|
+
'Close UE editor to release DLL locks',
|
|
101
|
+
'Call restart_editor, then retry the build',
|
|
102
|
+
'If editor was just restarted, the cached build may apply automatically',
|
|
103
|
+
],
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
if (message.includes('Empty response') || message.includes('empty response') || message === '') {
|
|
107
|
+
return {
|
|
108
|
+
code: 'empty_response',
|
|
109
|
+
recoverable: true,
|
|
110
|
+
next_steps: [
|
|
111
|
+
'Verify the asset path exists',
|
|
112
|
+
'Check editor connection with wait_for_editor',
|
|
113
|
+
'The UE subsystem may have crashed — check editor logs',
|
|
114
|
+
],
|
|
115
|
+
};
|
|
116
|
+
}
|
|
72
117
|
return null;
|
|
73
118
|
}
|
package/dist/server-factory.js
CHANGED
|
@@ -17,7 +17,7 @@ export function createBlueprintExtractorServer(client = new UEClient(), projectC
|
|
|
17
17
|
const toolHelpRegistry = new Map();
|
|
18
18
|
const server = new McpServer({
|
|
19
19
|
name: 'blueprint-extractor',
|
|
20
|
-
version: '3.0
|
|
20
|
+
version: '3.1.0',
|
|
21
21
|
}, {
|
|
22
22
|
instructions: serverInstructions,
|
|
23
23
|
});
|
|
@@ -32,7 +32,7 @@ export function createBlueprintExtractorServer(client = new UEClient(), projectC
|
|
|
32
32
|
normalizeToolError,
|
|
33
33
|
normalizeToolSuccess,
|
|
34
34
|
});
|
|
35
|
-
const callSubsystemJson = (method, params) => (callSubsystemJsonWithClient(client, method, params));
|
|
35
|
+
const callSubsystemJson = (method, params, options) => (callSubsystemJsonWithClient(client, method, params, options));
|
|
36
36
|
function rememberExternalBuild(result) {
|
|
37
37
|
lastExternalBuildContext = buildExternalBuildContext(result);
|
|
38
38
|
}
|
package/dist/tool-context.d.ts
CHANGED
|
@@ -14,7 +14,7 @@ export type ProjectAutomationContext = {
|
|
|
14
14
|
liveCodingStarted?: boolean;
|
|
15
15
|
liveCodingError?: string;
|
|
16
16
|
};
|
|
17
|
-
export type ProjectInputSource = 'explicit' | 'editor_context' | 'environment' | 'missing';
|
|
17
|
+
export type ProjectInputSource = 'explicit' | 'editor_context' | 'environment' | 'filesystem_heuristic' | 'missing';
|
|
18
18
|
export type ResolvedProjectInputs = {
|
|
19
19
|
engineRoot?: string;
|
|
20
20
|
projectPath?: string;
|