Unreal Engine MCP server: C++ PDB symbols, Blueprint and .uasset analysis, build-error fixes
Runs on your machine from its package; the steps are below.

At most: creates or changes data: records, files, settings.
Odel charges nothing per call. The publisher may charge for its own service.
Runs locally
This server runs on your machine over stdio, but its source registry didn't list a distribution package. Check the source repository for setup instructions.
NarshaMCP is an Unreal Engine MCP server. It is distributed on Fab as NarshaADK.
It parses C++ source, PDB symbols and binary .uasset files and serves the result over MCP. It is tested with
Claude Code and Codex. Most reads work from disk with the Unreal Editor closed; edits need the Editor.
Get it on Fab · Latest release · Documentation
UE 5.7 UE 5.8 Early Access
Early Access. Tool names, parameters and output shapes may change between releases.
The Fab product is named NarshaADK. The installed plugin folder, code module and runtime executable are named NarshaMCP.
The runtime is a prebuilt Windows 64-bit executable inside the plugin, and it runs on your machine. There is no hosted MCP endpoint. Python and Node.js are not required.
YourProject/Plugins/.{
"mcpServers": {
"narshamcp": {
"command": "<Project>/Plugins/NarshaMCP/Source/ThirdParty/bin/narshamcp.exe",
"args": ["connect", "--project-path", "<Project>"],
"env": { "RUST_LOG": "error" }
}
}
}
Fab installs the plugin under the engine's Plugins folder (<UE>/Engine/Plugins/Marketplace/NarshaMCP or <UE>/Engine/Plugins/Fab/NarshaMCP, where <UE> is your engine install folder), not in the project. For a Fab install, replace <Project>/Plugins/NarshaMCP in the command with that plugin folder. Clients that launch the server as a direct process, such as Cursor, use --stdio in place of connect.
The full steps are in Requirements, Install and Connect your MCP client.
Most tools take an operation argument. The table lists common read operations. ue_tool_docs returns every operation and its parameters, and your client lists the tools under tools/list.
| Tool | Returns | Read operations | Editor closed | Maturity |
|---|---|---|---|---|
ue_analyze_symbols | Symbols, callers, callees and class hierarchy from the project's PDBs; C++/Blueprint cross-references matched against the Blueprint packages | search_symbols, find_callers, find_callees, trace_hierarchy, find_cpp_to_bp, find_bp_to_cpp, impact_analysis | yes | Production |
ue_manage_blueprint | Events, nodes, variables and defaults, parent class and AnimGraph of a Blueprint asset | get_event_graph, get_raw_nodes, search_variables, get_variable_default, get_blueprint_metadata, list_blueprints, get_animgraph | yes; edits need the Editor | Beta |
ue_fix_errors | Build-log errors matched to a fix: the missing #include, the missing Build.cs module | scan_build_log, preflight, preview | yes; build_and_fix runs a build, get_compiler_results needs the Editor | Beta |
ue_manage_ai | StateTree and Behavior Tree states, tasks, transitions and bindings | get_summary, get_structure, find_transitions, get_bindings | yes; edits need the Editor | Production |
ue_manage_material | Material node topology, graph summary and instance hierarchy | get_graph_summary, get_nodes, get_hierarchy, search_materials | yes; name-based edges need the Editor | Experimental |
ue_manage_niagara | Niagara systems, emitters, renderers and parameters | get_emitter_details, get_structure, get_parameters, search_systems | yes | Experimental |
ue_manage_pcg | PCG graph nodes and flow | get_structure, trace_flow, find_nodes, search_graphs | yes | Experimental |
ue_search_assets | Asset search and DataTable rows; a cold load of the reference index may persist a cache in the project | search, get_table, find_dependencies, find_references, find_impact | yes | Beta |
ue_analyze_config | Config values across engine and project layers; console-variable declarations | search_config, explain_config, explore_cvar | yes | Beta |
ue_trace_execution | An execution path across input, abilities, Blueprint and C++ | trace_execution_flow, trace_from_input, trace_ability_flow, trace_gameplay_tag | yes | Beta |
ue_generate_code | C++ class scaffolds with Unreal macros and module setup | generate_class | yes; returns the file content for you to save | Beta |
ue_grep, ue_glob, ue_read | Text and name search across source, assets and config | a query, pattern or identifier; no operation | yes | Experimental |
ue_check_health reports the runtime version and whether the indexes are ready.
Each example shows the request, the MCP tool call and the JSON response. Captured from NarshaMCP v0.13.7 on Epic's Lyra Starter Game (UE 5.8.1) with the Editor closed. Values are as returned; removed keys and array elements are marked in the block.
Request. Which Blueprints call StartRangedWeaponTargeting, which C++ does GA_Weapon_Fire call, and what derives from ALyraCharacter?
Before. grep -rn StartRangedWeaponTargeting finds the C++ declaration and definition. The Blueprint call sites are inside binary .uasset packages.
Call. Editor closed.
{"name": "ue_analyze_symbols", "arguments": {"operation": "find_cpp_to_bp", "function_name": "ULyraGameplayAbility_RangedWeapon::StartRangedWeaponTargeting", "limit": 5}}
Output. As returned; cuts are marked.
{
"function_name": "ULyraGameplayAbility_RangedWeapon::StartRangedWeaponTargeting",
"total_callers": 2,
"truncated": false,
"blueprint_callers": [
{
"blueprint_name": "GA_Weapon_Fire",
"blueprint_path": "/Game/Weapons/GA_Weapon_Fire",
"owning_function": "K2_ActivateAbility",
"node_name": "K2Node_CallFunction_31",
"match_tier": "qualified",
"confidence": 0.75
},
{
"blueprint_name": "GA_WeaponNetShooter",
"blueprint_path": "/ShooterCore/Weapons/NetShooter_PROTO/GA_WeaponNetShooter",
"owning_function": "K2_ActivateAbility",
"node_name": "K2Node_CallFunction_31",
"match_tier": "qualified",
"confidence": 0.75
}
]
// [truncated] blueprint_callers[] fields omitted: call_type, is_pure; keys omitted: operation, skip_dedup, success
}
Call. Editor closed.
{"name": "ue_analyze_symbols", "arguments": {"operation": "find_bp_to_cpp", "blueprint_name": "GA_Weapon_Fire", "limit": 2, "offset": 18}}
Output. As returned; cuts are marked.
{
"blueprint_name": "GA_Weapon_Fire",
"total_calls": 33,
"offset": 18,
"truncated": true,
"cpp_calls": [
{
"full_name": "LyraGameplayAbility_RangedWeapon::StartRangedWeaponTargeting",
"owning_function": "K2_ActivateAbility",
"node_name": "K2Node_CallFunction_31",
"is_pure": false
},
{
"full_name": "KismetSystemLibrary::SetTimerDelegate",
"owning_function": "K2_ActivateAbility",
"node_name": "K2Node_CallFunction_4",
"is_pure": false
}
]
// [truncated] cpp_calls[] fields omitted: function_name, owner_class; keys omitted: operation, returned, success, total_count
}
Call. Editor closed.
{"name": "ue_analyze_symbols", "arguments": {"operation": "trace_hierarchy", "class_name": "ALyraCharacter", "direction": "down"}}
Output. As returned; cuts are marked.
{
"class_name": "ALyraCharacter",
"cpp_descendants_count": 1,
"bp_descendants_count": 10,
"descendants": [
{"depth": 1, "name": "ALyraCharacterWithAbilities", "relation": "child", "source": "pdb"},
{"depth": 1, "name": "Character_Default", "relation": "child_blueprint", "source": "blueprint"},
{"depth": 2, "name": "B_Hero_Default", "relation": "child_blueprint", "source": "blueprint"},
{"depth": 2, "name": "B_ShootingTarget", "relation": "child_blueprint", "source": "blueprint"}
],
"interface_parents": ["IAbilitySystemInterface", "IGameplayCueInterface", "IGameplayTagAssetInterface", "ILyraTeamAgentInterface"]
// [truncated] descendants: 4 of 11 elements; descendants[] fields omitted: parent; keys omitted: 13 of 18
}
Result. owning_function is the Blueprint event that contains the call, and match_tier with confidence records how the symbol was matched to the node. descendants[].source is pdb for a C++ subclass and blueprint for a Blueprint one.
Request. What events does GA_Weapon_Fire handle, what is its fire delay, and how is a node wired?
Before. Content/Weapons/GA_Weapon_Fire.uasset is binary, and grep -rn FireDelayTimeSecs over the source finds nothing: the variable exists only in the asset.
Call. Editor closed.
{"name": "ue_manage_blueprint", "arguments": {"operation": "get_event_graph", "blueprint_name": "GA_Weapon_Fire"}}
Output. As returned; cuts are marked.
{
"blueprint_name": "GA_Weapon_Fire",
"count": 5,
"events": [
{"node_title": "FireComplete", "node_class": "K2Node_CustomEvent"},
{"node_title": "FailureMontage Delay Complete", "node_class": "K2Node_CustomEvent"}
]
// [truncated] events: 2 of 5 elements; events[] fields omitted: node_id, owning_function; keys omitted: operation, success
}
Call. Editor closed.
{"name": "ue_manage_blueprint", "arguments": {"operation": "search_variables", "blueprint_name": "GA_Weapon_Fire", "pattern": "*Fire*"}}
Output. As returned; cuts are marked.
{
"parent_class": "LyraGameplayAbility_RangedWeapon",
"total_count": 2,
"results": [
{
"name": "CharacterFireMontage",
"default_value": "AM_MM_Rifle_Fire",
"default_value_type": "Object",
"edit_condition": "EditDefaultsOnly"
},
{
"name": "FireDelayTimeSecs",
"default_value": "0.1",
"default_value_type": "Double",
"edit_condition": "EditDefaultsOnly"
}
]
// [truncated] results[] fields omitted: 9 of 13; keys omitted: 14 of 17
}
Call. Editor closed.
{"name": "ue_manage_blueprint", "arguments": {"operation": "get_raw_nodes", "blueprint_name": "GA_Weapon_Fire", "page": 1, "page_size": 1}}
Output. As returned; cuts are marked.
{
"total_nodes": 98,
"has_more": true,
"nodes": [
{
"id": "K2Node_AsyncAction_ListenForGameplayMessages_0",
"node_class": "K2Node_AsyncAction_ListenForGameplayMessages",
"owning_function": "K2_OnAbilityAdded",
"pins": [
{
"name": "execute",
"category": "exec",
"direction": "input",
"linked_to": [
{"node_id": "K2Node_Event_1", "pin_name": "then", "export_index": 70}
]
},
{"name": "then", "category": "exec", "direction": "output", "linked_to": []}
]
}
]
// [truncated] nodes[].pins: 2 of 12 elements; nodes[].pins[].linked_to[] fields omitted: owning_function; nodes[].pins[] fields omitted: container_type, default_value, pin_id, sub_category; nodes[] fields omitted: 5 of 9; keys omitted: 10 of 13
}
Result. parent_class, events[].node_title and results[].default_value are read from the .uasset. pins[].linked_to names the node and pin each pin connects to; where a node id repeats inside an asset, export_index identifies the endpoint.
Request. How is M_TeamColorBasic built?
Before. M_TeamColorBasic.uasset is binary; the expression graph is not in any text file.
Call. Editor closed.
{"name": "ue_manage_material", "arguments": {"operation": "get_graph_summary", "material_path": "/Game/Characters/Cosmetics/M_TeamColorBasic"}}
Output. As returned; cuts are marked.
{
"material_name": "M_TeamColorBasic",
"source": "uasset_metadata_cache",
"node_count": 4,
"connection_count": 3,
"stage_count": 3,
"output_chains": [
{"output_pin": "Material", "root_node": "MaterialExpressionVectorParameter_3", "upstream_node_count": 1},
{"output_pin": "Material", "root_node": "MaterialExpressionAdd_0", "upstream_node_count": 4}
]
// [truncated] output_chains: 2 of 3 elements; output_chains[] fields omitted: exclusive_node_count, role, top_node_types; keys omitted: 6 of 12
}
Result. With the Editor closed the response has the node count, the connection count and the root node of each output chain. ue_manage_material is Experimental; with the Editor running, its get_nodes operation adds node names and name-based edges.
Request. What does the L_STT_FollowPlayer StateTree do?
Before. L_STT_FollowPlayer.uasset is binary, and grep -rn L_STT_FollowPlayer over the source finds nothing: no code describes this tree.
Call. Editor closed.
{"name": "ue_manage_ai", "arguments": {"operation": "get_summary", "ai_type": "statetree", "asset_name": "L_STT_FollowPlayer"}}
Output. As returned; cuts are marked.
{
"asset_name": "L_STT_FollowPlayer",
"root_state": "Root",
"state_count": 9,
"property_binding_count": 19,
"states": [
{
"name": "Wait 3s Follow",
"tasks": ["StateTreeDebugTextTask", "StateTreeDelayTask"],
"transitions": [
{"trigger": "OnStateCompleted", "to_state": "Wait 3s Follow TooClose"},
{"trigger": "OnStateCompleted", "to_state": "Follow"}
]
},
{
"name": "Follow",
"tasks": ["STT_Follow"],
"transitions": [
{"trigger": "OnStateSucceeded", "to_state": "Root"},
{"trigger": "OnStateFailed", "to_state": "Wait 3s FailFollow"}
]
}
]
// [truncated] states: 2 of 9 elements; states[] fields omitted: conditions, enabled, state_type; keys omitted: 11 of 16
}
Result. states[].tasks lists each state's tasks and states[].transitions[].to_state lists its outgoing transitions.
Request. What does the NE_ImpactCore emitter of NS_ImpactGlass render?
Before. NS_ImpactGlass.uasset is binary.
Call. Editor closed.
{"name": "ue_manage_niagara", "arguments": {"operation": "get_emitter_details", "asset_name": "NS_ImpactGlass", "emitter_name": "NE_ImpactCore"}}
Output. As returned; cuts are marked.
{
"system_name": "NS_ImpactGlass",
"emitter_name": "NE_ImpactCore",
"emitter_data": {
"loop_behavior": "Once",
"renderer_count": 2,
"renderers": [
{"renderer_type": "NiagaraSpriteRendererProperties", "facing_mode": "FaceCamera"},
{"renderer_type": "NiagaraSpriteRendererProperties", "facing_mode": "FaceCamera"}
],
"data_interface_count": 2,
"data_interfaces": [
{"di_type": "NiagaraDataInterfaceArrayFloat3"},
{"di_type": "NiagaraDataInterfaceArrayPosition"}
]
}
// [truncated] emitter_data.renderers[] fields omitted: 5 of 7; emitter_data.data_interfaces[] fields omitted: name; emitter_data fields omitted: 21 of 26; keys omitted: mode, operation, requested_path, success
}
Result. renderers[].renderer_type is the renderer class and data_interfaces[].di_type is the data interface type. ue_manage_niagara is Experimental.
Request. How large is ABP_Mannequin_Base and which skeleton does it target?
Before. ABP_Mannequin_Base.uasset is binary.
Call. Editor closed.
{"name": "ue_manage_blueprint", "arguments": {"operation": "get_animgraph", "blueprint_name": "ABP_Mannequin_Base", "detail_level": "summary"}}
Output. As returned; cuts are marked.
{
"blueprint_name": "ABP_Mannequin_Base",
"target_skeleton": "SK_Mannequin",
"source": "metadata_category:anim_blueprints",
"anim_graph_node_count": 138,
"state_machine_count": 1,
"pose_link_count": 25,
"anim_node_types": {
"anim_state": 10,
"anim_state_transition": 27,
"anim_blend_space": 3,
"anim_linked_layer": 14
}
// [truncated] anim_node_types fields omitted: 15 of 19; keys omitted: 6 of 13
}
Result. target_skeleton names the skeleton and anim_node_types counts the graph's nodes by kind. Raise detail_level to read a single state machine.
Lyra ships no PCG graph, so PCG is not shown here. ue_manage_pcg get_structure reads a PCG graph with the Editor closed and is Experimental; it is listed in the comparison table below.
Mock-up, not a captured session. For C2065: 'UAbilitySystemComponent': undeclared identifier, ue_fix_errors adds the #include, adds GameplayAbilities to Build.cs and switches to IAbilitySystemInterface.
Mock-up of a Claude Code session that calls ue_analyze_symbols, then ue_generate_code, then ue_fix_errors.
From Fab. Install NarshaADK from the Fab listing and enable the NarshaMCP plugin in a C++ project.
From GitHub Releases
YourProject/Plugins/. The ZIP already contains the NarshaMCP folder, so the plugin lands in YourProject/Plugins/NarshaMCP/. When upgrading, remove the previous Plugins/NarshaMCP/ folder first, and keep a copy if you may want to go back.ue_check_health. It returns status and version. The first start indexes the PDBs your build produced. While the index is building, symbol operations return "status": "symbol_index_loading", with a progress object once the total is known; call again when it finishes. symbol_index_degraded_budget means a memory budget capped the index, and waiting does not clear it.The first build writes the project's MCP configuration for you. If you configure a client by hand, point it at the runtime that ships inside the plugin:
{
"mcpServers": {
"narshamcp": {
"command": "<Project>/Plugins/NarshaMCP/Source/ThirdParty/bin/narshamcp.exe",
"args": ["connect", "--project-path", "<Project>"],
"env": { "RUST_LOG": "error" }
}
}
}
claude mcp add narshamcp -- "<Project>/Plugins/NarshaMCP/Source/ThirdParty/bin/narshamcp.exe" connect --project-path "<Project>"~/.codex/config.toml, with forward slashes in the path:[mcp_servers.narshamcp]
command = "<Project>/Plugins/NarshaMCP/Source/ThirdParty/bin/narshamcp.exe"
args = ["connect", "--project-path", "<Project>"]
connect attaches the client to the project's background daemon and starts it when none is running. Clients that launch the server as a direct process, such as Cursor, use --stdio in place of connect.
Fab installs the plugin under the engine's Plugins folder (<UE>/Engine/Plugins/Marketplace/NarshaMCP or <UE>/Engine/Plugins/Fab/NarshaMCP, where <UE> is your engine install folder), not in the project. For a Fab install, replace <Project>/Plugins/NarshaMCP in the commands above with that plugin folder.
| Layer | What NarshaADK reads |
|---|---|
| Source code analysis | C++ source, with macros such as UPROPERTY, UFUNCTION and DOREPLIFETIME resolved |
| Compiler symbol index | The PDB debug data your build produces: class hierarchies, call graphs and symbol lookups |
| Binary asset parsing | .uasset packages, without commandlets or the Editor. Operations that change assets need a running Editor |
The symbol index is built from the PDBs of your own build, so it covers your project's classes, and the engine's when the engine's debug symbols are installed. It needs one successful build.
The Unreal MCP built into UE 5.8 runs inside the Editor. NarshaMCP reads the project from disk, so the Editor can be closed, and it indexes PDBs for a C++ call graph. The table below compares the two read by read.
ue_fix_errors get_compiler_results, and by the node names and name-based edges of ue_manage_material get_nodes. The read operations named in the table above run with the Editor closed.detail_handle to a local file, which ue_cache_control resolve_detail_handle loads. Ask for a narrower read, such as one emitter or a limit, to get the data inline.What each server can read and hand to an agent, and whether that read works with the Editor closed. ✅ reads the project's files; the Editor never has to run · ● in the running Editor (a design choice) · — not provided · ? not confirmed at the pin shown · superscript p = partial.
| What is read | NarshaADK v0.13.7 · 2026-09-13 | Unreal MCP (built into UE 5.8) UE 5.8.0 · 2026-06-27 | VibeUE kevinpbuckley/VibeUE@0ea59b3 · 2026-09-20 (read 2026-09-22) | unreal-mcp (sam-david) sam-david/unreal-mcp@8b88ec3 · 2026-03-28 (read 2026-09-22) | unreal-mcp (ZiggyMar) ZiggyMar/unreal-mcp@d1a8539 · 2026-09-07 (read 2026-09-22) |
|---|---|---|---|---|---|
| Reads with the Editor closed | ✅p | ● | ● | ✅p | ● |
| Blueprint graphs: nodes, pins, exec flow | ✅ | ● | ● | ? | ● |
| Blueprint variables, functions, components, defaults | ✅ | ●p | ● | ●p | ● |
| Material graphs and expressions | ✅p | ● | ● | ●p | ●p |
| Niagara systems, emitters, modules | ✅ | ● | ● | — | ●p |
| PCG graphs | ✅ | ● | — | — | — |
| Animation Blueprints, montages, blend spaces | ✅ | ●p | ●p | — | ●p |
| DataTables, structs, enums | ✅ | ●p | ●p | — | ● |
| Widgets / UMG trees | ✅ | ● | ● | — | ● |
| Config files and console variables | ✅p | ● | ● | — | ●p |
| Class hierarchy: base classes and ancestry | ✅ | ●p | ●p | ●p | ● |
| Call graph: callers and callees | ✅ | — | — | — | ●p |
| Change impact analysis | ✅ | ●p | ●p | ●p | ●p |
| Build errors and logs | ✅p | ●p | ●p | ✅p | ● |
| Unreal Insights traces | ✅ | — | ● | — | — |
| Asset references and dependencies | ✅ | ● | — | ● | ● |
| Create or modify assets (write) | ● | ● | ● | ● | ● |
Capability presence measured from each compared open-source project's public source at the commit and date shown, from a live toolset enumeration for the engine's built-in server at the engine version shown, and for NarshaADK from this product's own tool registry at the version shown. Compared: servers that publish their own comparison with another Unreal MCP server or with the engine's built-in one, plus that built-in server as the baseline; this does not cover every Unreal MCP server. Not a ranking. Where the evidence supports a narrower statement than the mark, a note in the README says so. Not affiliated with or endorsed by Epic Games or the compared projects. Corrections welcome in this repository's Discussions.
| Unreal Engine | Plugin package |
|---|---|
| UE 5.8 | NarshaMCP-v<version>-UE5.8-Release-RustMCP.zip |
| UE 5.7 | NarshaMCP-v<version>-UE5.7-Release-RustMCP.zip |
Each release includes these files:
NarshaMCP-v<version>-UE5.7-Release-RustMCP.zip and NarshaMCP-v<version>-UE5.8-Release-RustMCP.zip are the same plugin ZIPs submitted to Fab. They contain the plugin's Unreal C++ source, which your project builds, and the runtime as a prebuilt executable. The runtime's own source is not included.narshamcp-windows-x64.exe is the standalone Windows runtime, byte-identical to the runtime inside the ZIPs.Each release's notes list the SHA-256 digest of every file. Third-party software notices ship inside the runtime: run narshamcp --licenses (or narshamcp --licenses-json).
NarshaADK is licensed under the Fab End User License Agreement (the "Fab Standard License"). Copies downloaded from this repository are granted the same terms directly by Next Stage Inc.: the Personal tier applies at no charge if you, together with any controlling entity and any entity under common control with you, did not generate more than the Fab revenue threshold from commercial activity in the digital content industry in the last 12 months (USD 100,000 when this was written; the Fab EULA states the current figure). Above it a Professional license acquired through the Fab listing is required. LICENSE.md states the threshold and the full terms.
Documentation and examples are at narshaadk.ai. To ask questions or report issues, use the support channel on the Fab listing.
NarshaADK is built and maintained by Next Stage Inc.