blueprint-extractor-mcp 1.0.0 → 1.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.
Files changed (2) hide show
  1. package/dist/index.js +146 -18
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -6,12 +6,72 @@ import { UEClient } from './ue-client.js';
6
6
  const client = new UEClient();
7
7
  const server = new McpServer({
8
8
  name: 'blueprint-extractor',
9
- version: '1.0.0',
9
+ version: '1.2.0',
10
10
  });
11
+ // Shared scope enum with detailed descriptions
12
+ const scopeEnum = z.enum([
13
+ 'ClassLevel',
14
+ 'Variables',
15
+ 'Components',
16
+ 'FunctionsShallow',
17
+ 'Full',
18
+ 'FullWithBytecode',
19
+ ]);
20
+ // Resource: extraction scope reference (static docs — app-controlled read-only context)
21
+ server.resource('extraction-scopes', 'blueprint://scopes', {
22
+ description: 'Reference for Blueprint extraction scopes: what each level includes, typical sizes, and when to use.',
23
+ }, async (uri) => ({
24
+ contents: [{
25
+ uri: uri.href,
26
+ mimeType: 'text/plain',
27
+ text: [
28
+ 'Blueprint Extraction Scopes',
29
+ '',
30
+ 'Each scope includes everything from the previous level:',
31
+ '',
32
+ '| Scope | Adds | Typical Size | Use When |',
33
+ '|-------------------|---------------------------------------------------|---------------|-----------------------------------------------|',
34
+ '| ClassLevel | Parent class, interfaces, class flags, metadata | 1-2 KB | Checking inheritance or interface list |',
35
+ '| Variables | All variables with types, defaults, flags | 2-10 KB | Understanding data model (DEFAULT) |',
36
+ '| Components | SCS component tree with property overrides vs CDO | 5-20 KB | Analyzing component composition |',
37
+ '| FunctionsShallow | Function and event graph names only | 5-25 KB | Listing available functions before deep dive |',
38
+ '| Full | Complete graph nodes, pins, and connections | 20-500+ KB | Understanding graph logic and execution flow |',
39
+ '| FullWithBytecode | Raw bytecode hex dump per function | Largest | Low-level analysis (rarely needed) |',
40
+ '',
41
+ 'Start with the narrowest scope that answers your question.',
42
+ 'Full scope on complex Blueprints can exceed 200KB and will be truncated.',
43
+ ].join('\n'),
44
+ }],
45
+ }));
11
46
  // Tool 1: extract_blueprint
12
- server.tool('extract_blueprint', 'Extract a UE5 Blueprint asset to JSON. Returns the full Blueprint structure including class info, variables, components, and graph data.', {
13
- asset_path: z.string().describe('UE asset path, e.g. /Game/Blueprints/BP_Character'),
14
- scope: z.enum(['ClassLevel', 'Variables', 'Components', 'FunctionsShallow', 'Full', 'FullWithBytecode']).default('Full').describe('Extraction depth'),
47
+ server.registerTool('extract_blueprint', {
48
+ title: 'Extract Blueprint',
49
+ description: `Extract a UE5 Blueprint asset to structured JSON.
50
+
51
+ USAGE GUIDELINES:
52
+ - Use search_assets first to find the correct asset path if you don't already have it.
53
+ - Start with the narrowest scope that answers your question — each level includes everything from the previous:
54
+ * ClassLevel — parent class, interfaces, class flags, metadata (~1-2KB)
55
+ * Variables — + all variables with types, defaults, flags (~2-10KB)
56
+ * Components — + SCS component tree with property overrides (~5-20KB)
57
+ * FunctionsShallow — + function/event graph names only (~5-25KB)
58
+ * Full — + complete graph nodes, pins, and connections (~20-500KB+)
59
+ * FullWithBytecode — + raw bytecode hex dump (largest, rarely needed)
60
+ - Only escalate to Full when you need to understand graph logic (node connections, pin values, execution flow).
61
+ - Full scope on complex Blueprints can exceed 200KB and will be truncated. If truncated, use a narrower scope or inspect specific functions via the graph names from FunctionsShallow.
62
+
63
+ RETURNS: JSON object with the extracted Blueprint data at the requested scope level.`,
64
+ inputSchema: {
65
+ asset_path: z.string().describe('UE content path to the Blueprint asset. Must start with /Game/ (e.g. /Game/Blueprints/BP_Character). Use search_assets to find paths.'),
66
+ scope: scopeEnum.default('Variables').describe('Extraction depth. Start with ClassLevel or Variables — only use Full when you need graph/node details.'),
67
+ },
68
+ annotations: {
69
+ title: 'Extract Blueprint',
70
+ readOnlyHint: true,
71
+ destructiveHint: false,
72
+ idempotentHint: true,
73
+ openWorldHint: false,
74
+ },
15
75
  }, async ({ asset_path, scope }) => {
16
76
  try {
17
77
  const result = await client.callSubsystem('ExtractBlueprint', { AssetPath: asset_path, Scope: scope });
@@ -21,7 +81,7 @@ server.tool('extract_blueprint', 'Extract a UE5 Blueprint asset to JSON. Returns
21
81
  }
22
82
  const text = JSON.stringify(parsed, null, 2);
23
83
  if (text.length > 200_000) {
24
- return { content: [{ type: 'text', text: `Warning: Response is ${(text.length / 1024).toFixed(0)}KB. Consider using a narrower scope.\n\n${text.substring(0, 200_000)}...\n[TRUNCATED]` }] };
84
+ return { content: [{ type: 'text', text: `Warning: Response is ${(text.length / 1024).toFixed(0)}KB consider using a narrower scope (ClassLevel, Variables, or FunctionsShallow).\n\n${text.substring(0, 200_000)}...\n[TRUNCATED]` }] };
25
85
  }
26
86
  return { content: [{ type: 'text', text }] };
27
87
  }
@@ -30,8 +90,26 @@ server.tool('extract_blueprint', 'Extract a UE5 Blueprint asset to JSON. Returns
30
90
  }
31
91
  });
32
92
  // Tool 2: extract_statetree
33
- server.tool('extract_statetree', 'Extract a UE5 StateTree asset to JSON. Returns the full state hierarchy, tasks, conditions, and transitions.', {
34
- asset_path: z.string().describe('UE asset path to a StateTree, e.g. /Game/AI/ST_BotBehavior'),
93
+ server.registerTool('extract_statetree', {
94
+ title: 'Extract StateTree',
95
+ description: `Extract a UE5 StateTree asset to structured JSON.
96
+
97
+ USAGE GUIDELINES:
98
+ - Use search_assets first to find the asset path if needed (filter by class "StateTree").
99
+ - Returns the full state hierarchy: states, tasks, conditions, transitions, evaluators, and linked assets.
100
+ - Response size depends on StateTree complexity — typically 10-100KB.
101
+
102
+ RETURNS: JSON object with schema, state hierarchy, tasks, conditions, transitions, and linked assets.`,
103
+ inputSchema: {
104
+ asset_path: z.string().describe('UE content path to a StateTree asset (e.g. /Game/AI/ST_BotBehavior). Use search_assets with class_filter "StateTree" to find paths.'),
105
+ },
106
+ annotations: {
107
+ title: 'Extract StateTree',
108
+ readOnlyHint: true,
109
+ destructiveHint: false,
110
+ idempotentHint: true,
111
+ openWorldHint: false,
112
+ },
35
113
  }, async ({ asset_path }) => {
36
114
  try {
37
115
  const result = await client.callSubsystem('ExtractStateTree', { AssetPath: asset_path });
@@ -46,10 +124,29 @@ server.tool('extract_statetree', 'Extract a UE5 StateTree asset to JSON. Returns
46
124
  }
47
125
  });
48
126
  // Tool 3: extract_cascade
49
- server.tool('extract_cascade', 'Extract multiple Blueprint/StateTree assets with cascade reference following. Writes results to files on disk.', {
50
- asset_paths: z.array(z.string()).describe('Array of UE asset paths to extract'),
51
- scope: z.enum(['ClassLevel', 'Variables', 'Components', 'FunctionsShallow', 'Full', 'FullWithBytecode']).default('Full').describe('Extraction depth'),
52
- max_depth: z.number().int().min(0).max(10).default(3).describe('How many levels deep to follow references'),
127
+ server.registerTool('extract_cascade', {
128
+ title: 'Extract Cascade',
129
+ description: `Extract multiple Blueprint/StateTree assets with automatic reference following. Follows parent classes, interfaces, component classes, and other Blueprint references up to max_depth levels deep.
130
+
131
+ USAGE GUIDELINES:
132
+ - Use when you need to understand an asset AND its dependencies (parent Blueprints, referenced Blueprints, etc.).
133
+ - Results are written to files on disk (in the project's configured output directory), NOT returned inline — the response only contains a summary with file paths and count.
134
+ - For a single asset without dependencies, prefer extract_blueprint or extract_statetree instead.
135
+ - Cycle-safe: won't extract the same asset twice.
136
+
137
+ RETURNS: Summary with extracted_count and output_directory path. Read the output files to inspect the data.`,
138
+ inputSchema: {
139
+ asset_paths: z.array(z.string()).describe('Array of UE content paths to extract (e.g. ["/Game/Blueprints/BP_Character", "/Game/Blueprints/BP_Weapon"])'),
140
+ scope: scopeEnum.default('Full').describe('Extraction depth applied to all assets. Full is the default since cascade is typically used for deep analysis.'),
141
+ max_depth: z.number().int().min(0).max(10).default(3).describe('How many levels deep to follow references (0 = only the listed assets, 3 = default)'),
142
+ },
143
+ annotations: {
144
+ title: 'Extract Cascade',
145
+ readOnlyHint: false, // writes files to disk
146
+ destructiveHint: false,
147
+ idempotentHint: true,
148
+ openWorldHint: false,
149
+ },
53
150
  }, async ({ asset_paths, scope, max_depth }) => {
54
151
  try {
55
152
  const result = await client.callSubsystem('ExtractCascade', {
@@ -68,9 +165,27 @@ server.tool('extract_cascade', 'Extract multiple Blueprint/StateTree assets with
68
165
  }
69
166
  });
70
167
  // Tool 4: search_assets
71
- server.tool('search_assets', 'Search for UE5 assets by name. Returns matching asset paths, names, and classes.', {
72
- query: z.string().describe('Search query to match against asset names'),
73
- class_filter: z.string().default('Blueprint').describe('Filter by asset class (e.g. Blueprint, StateTree, or empty for all)'),
168
+ server.registerTool('search_assets', {
169
+ title: 'Search Assets',
170
+ description: `Search for UE5 assets by name. This is a lightweight lookup — use it FIRST to find correct asset paths before calling extract_blueprint or extract_statetree.
171
+
172
+ USAGE GUIDELINES:
173
+ - Always call this before extract_blueprint/extract_statetree if you don't already have the exact asset path.
174
+ - Searches asset names (not full paths) — partial matches work (e.g. "Character" finds "BP_Character").
175
+ - Filter by class to narrow results: "Blueprint" (default), "StateTree", "WidgetBlueprint", "DataAsset", or empty string for all.
176
+
177
+ RETURNS: JSON array of objects with path, name, and class for each matching asset.`,
178
+ inputSchema: {
179
+ query: z.string().describe('Search term to match against asset names. Partial matches work (e.g. "Player" finds "BP_PlayerCharacter").'),
180
+ class_filter: z.string().default('Blueprint').describe('Filter by asset class. Common values: "Blueprint", "WidgetBlueprint", "StateTree", "DataAsset", or "" for all asset types.'),
181
+ },
182
+ annotations: {
183
+ title: 'Search Assets',
184
+ readOnlyHint: true,
185
+ destructiveHint: false,
186
+ idempotentHint: true,
187
+ openWorldHint: false,
188
+ },
74
189
  }, async ({ query, class_filter }) => {
75
190
  try {
76
191
  const result = await client.callSubsystem('SearchAssets', { Query: query, ClassFilter: class_filter });
@@ -85,10 +200,23 @@ server.tool('search_assets', 'Search for UE5 assets by name. Returns matching as
85
200
  }
86
201
  });
87
202
  // Tool 5: list_assets
88
- server.tool('list_assets', 'List UE5 assets in a directory. Returns asset paths, names, and classes.', {
89
- package_path: z.string().describe('UE package path, e.g. /Game/Blueprints'),
90
- recursive: z.boolean().default(true).describe('Search subdirectories'),
91
- class_filter: z.string().default('').describe('Filter by asset class (empty for all)'),
203
+ server.registerTool('list_assets', {
204
+ title: 'List Assets',
205
+ description: `List UE5 assets under a package path. Use this to browse directory contents when you don't know asset names. If you know (part of) the asset name, prefer search_assets instead — it's faster and doesn't require knowing the directory.
206
+
207
+ RETURNS: JSON array of objects with path, name, and class for each asset in the directory.`,
208
+ inputSchema: {
209
+ package_path: z.string().describe('UE package path to list (e.g. /Game/Blueprints, /Game/AI). Use /Game to list from the Content root.'),
210
+ recursive: z.boolean().default(true).describe('Whether to include assets in subdirectories.'),
211
+ class_filter: z.string().default('').describe('Filter by asset class (e.g. "Blueprint", "StateTree"). Empty string returns all asset types.'),
212
+ },
213
+ annotations: {
214
+ title: 'List Assets',
215
+ readOnlyHint: true,
216
+ destructiveHint: false,
217
+ idempotentHint: true,
218
+ openWorldHint: false,
219
+ },
92
220
  }, async ({ package_path, recursive, class_filter }) => {
93
221
  try {
94
222
  const result = await client.callSubsystem('ListAssets', {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "blueprint-extractor-mcp",
3
- "version": "1.0.0",
3
+ "version": "1.2.0",
4
4
  "description": "MCP server for UE5 BlueprintExtractor plugin",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",