Skip to content

feat: UE 5.8 plugin fixes (validate_niagara_system, transactional spawn, ListenPorts warning, MCP_NATIVE_PORT env)#479

Merged
ChiR24 merged 6 commits into
ChiR24:devfrom
alecray:pr/mcp-58-fixes
Jul 7, 2026
Merged

feat: UE 5.8 plugin fixes (validate_niagara_system, transactional spawn, ListenPorts warning, MCP_NATIVE_PORT env)#479
ChiR24 merged 6 commits into
ChiR24:devfrom
alecray:pr/mcp-58-fixes

Conversation

@alecray

@alecray alecray commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Hello! I'm working in Unreal 5.8 and I've been using your Unreal MCP plugin. I wanted to contribute some fixes I've done for it to be less error prone. I'm not a UE developer and these were done by Claude Opus on xHigh. I've vetted the work as best I can and the decisions made. I hope this is useful!

Five small, independent fixes for the McpAutomationBridge plugin on UE 5.8 — each is its own commit, so feel free to take any subset. All were built and HTTP-verified in an isolated UE 5.8 C++ project.

1. Build on UE 5.8 (FJsonObject::Values key type)

UE 5.8 changed FJsonObject::Values' key type to UE::TSharedString<TCHAR>, so Settings->Values.Contains(Field) (FString) no longer compiles in the Render console handler. Switched to the public HasField() accessor — the only 5.8 compile break in the plugin.

2. validate_niagara_system detects real errors

Previously hard-coded isValid=true with only soft structural warnings. Now builds a full Niagara system view model and harvests UNiagaraStackEntry::GetIssues() (Error/Warning) across the system + emitter stacks — the same issues the editor shows, including "The module has unmet dependencies." A data-processing-only VM can't be used (UNiagaraStackModuleItem::RefreshIssues() returns nothing there). Kept lightweight: bCanSimulate=false (no preview component), compile off; SetupSequencer only builds a detached transient Sequencer.
Verified: deleted Emitter State module → isValid:false + unmet-dependency error; clean system → isValid:true.

3. control_actor spawn is transactional

A requested mesh that couldn't be applied used to still report success, leaving a misconfigured actor in the level. Now: MESH_NOT_FOUND before spawning if an explicit meshPath can't load; and rollback (Destroy() + MESH_APPLY_FAILED) if a resolved mesh can't be applied. A failed request leaves the world unchanged.

4. Warn when ListenPorts drops a default bridge port

A partial ListenPorts override replaces the 8090,8091 default wholesale (UE config semantics), silently dropping a port clients expect. Keeps the user's ports authoritative but logs a clear warning (multi-listen) when a default is missing.

5. MCP_NATIVE_PORT env override

Pick the native MCP port via env without editing committed ini — handy for running several editors at once on distinct ports. Mirrors the existing MCP_MAX_* env overrides; additive and non-breaking, falls back to the NativeMCPPort setting.

🤖 Generated with Claude Code

alecray and others added 5 commits June 16, 2026 12:57
UE 5.8 changed FJsonObject::Values' key type to UE::TSharedString<TCHAR>, so Values.Contains(FString) no longer compiles. Use the public HasField() accessor. Only 5.8 compile break in the plugin.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Previously hard-coded isValid=true. Build a full (non-data-processing) Niagara system view model and harvest UNiagaraStackEntry::GetIssues() Error/Warning across the system + emitter stacks. Full mode is required: UNiagaraStackModuleItem::RefreshIssues() returns no issues in data-processing mode, so per-module errors (incl. unmet dependencies) never surface there. bCanSimulate=false avoids the preview component; SetupSequencer builds only a detached transient Sequencer.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Pre-spawn: fail MESH_NOT_FOUND if an explicit meshPath can't load. Post-spawn: if a resolved mesh can't be applied, Destroy() the just-spawned actor and return MESH_APPLY_FAILED, so a failed request leaves the world unchanged instead of leaking a half-configured actor.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A partial ListenPorts ini override replaces the default wholesale (UE config semantics), silently dropping a default port clients may expect. Keep the user's ports authoritative but log a clear warning when multi-listen is on and a default is missing.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Lets a project select a per-instance native MCP port via env without editing committed ini (multi-editor workflow). Mirrors the existing MCP_MAX_* env overrides; additive and non-breaking, falls back to the NativeMCPPort setting.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

👋 Thanks for your first Pull Request! We love contributions. Please ensure you have signed off your commits and followed the contribution guidelines.

@coderabbitai

coderabbitai Bot commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 4c95ce18-c875-48ed-8121-57530c7fc6d8

📥 Commits

Reviewing files that changed from the base of the PR and between c2c4527 and bc35e20.

📒 Files selected for processing (2)
  • plugins/McpAutomationBridge/CHANGELOG.md
  • plugins/McpAutomationBridge/README.md
✅ Files skipped from review due to trivial changes (2)
  • plugins/McpAutomationBridge/README.md
  • plugins/McpAutomationBridge/CHANGELOG.md

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Added MCP_NATIVE_PORT environment variable to override the native MCP port at startup.
    • Control actor spawning now includes transactional behavior with automatic rollback on mesh application failures.
    • Niagara system validation now reports actual stack and module issues instead of hardcoded results.
  • Bug Fixes

    • Fixed JSON field detection for UE 5.8 compatibility.
    • Added warning when ListenPorts configuration omits default ports, which may prevent client connections.
  • Documentation

    • Updated README and CHANGELOG with new environment variable and validation improvements.

Walkthrough

Five independent hardening changes to the MCP Automation Bridge plugin: native transport startup now reads MCP_NATIVE_PORT env var with range validation; connection manager warns when a ListenPorts override omits default ports 8090/8091; actor spawn adds early mesh-not-found check and a rollback-on-failure mechanism; Niagara system validation now harvests real stack issues from a throwaway view model; and a JSON field presence check is fixed for UE 5.8. Documentation updates reflect all changes.

Changes

MCP Automation Bridge Plugin Hardening

Layer / File(s) Summary
Native port env-var override and multi-listen warning
plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/Core/Subsystem/McpAutomationBridgeSubsystemLifecycle.cpp, plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/Transport/Connection/McpConnectionManager.cpp
StartNativeTransport reads and validates MCP_NATIVE_PORT env var (1–65535), uses the computed NativePort for FMcpNativeTransport startup and failure logging. FMcpConnectionManager::Initialize emits a warning when a bMultiListen ListenPorts override omits default bridge ports 8090 or 8091.
Actor spawn early mesh validation and rollback
plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/Domains/ControlActor/McpAutomationBridge_ControlActorSpawn.cpp
HandleControlActorSpawn returns MESH_NOT_FOUND before spawning if meshPath resolves to neither UStaticMesh nor USkeletalMesh. After spawning, adds IsValid guard returning SPAWN_FAILED. Introduces rollback lambda that destroys the spawned actor if mesh component assignment fails, returning MESH_APPLY_FAILED. Transform is applied before mesh assignment.
Niagara system validation via stack-issue harvesting
plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/Domains/NiagaraAuthoring/McpAutomationBridge_NiagaraAuthoringHandlersInfoValidation.cpp
Adds editor-only includes for FNiagaraSystemViewModel and stack entry types. Introduces CollectStackIssues recursive helper that splits UNiagaraStackEntry issues into errors/warnings by severity. ValidateNiagaraSystem now constructs a throwaway FNiagaraSystemViewModel in full validation mode, refreshes stack children, collects issues, and sets validationResult.isValid, errors, warnings, and message from actual stack state instead of a hard-coded valid result.
UE 5.8 JSON HasField fix
plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/Domains/Render/McpAutomationBridge_RenderConsole.cpp
ReadBoundedNumberSetting replaces Settings->Values.Contains(Field) with Settings->HasField(Field) to correctly detect JSON field presence under UE 5.8's changed FJsonObject::Values key type.
Documentation updates
plugins/McpAutomationBridge/CHANGELOG.md, plugins/McpAutomationBridge/README.md
CHANGELOG entries added for MCP_NATIVE_PORT env-var override, UE 5.8 JSON field fix, ListenPorts override warning, real Niagara stack validation, and actor spawn transactional rollback. README documents the new MCP_NATIVE_PORT environment variable and its fallback behavior, and updates the Native MCP Port setting description to reference the env-var override and confirm default port 3000.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • ChiR24/Unreal_mcp#363: Introduced FMcpNativeTransport and the native HTTP flow that this PR extends with env-var port override support in StartNativeTransport.

Suggested labels

area/server, area/docs, size/m

Suggested reviewers

  • ChiR24

Poem

🐇 A rabbit checks the port with care,
MCP_NATIVE_PORT floats in the air.
If meshes are missing, roll it back neat,
Niagara's stack issues now real and complete.
HasField replaces old Contains ways—
The bridge hops forward through 5.8's maze! 🌉

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes all five independent fixes in the PR with specific technical details (UE 5.8, validate_niagara_system, transactional spawn, ListenPorts warning, MCP_NATIVE_PORT env).
Description check ✅ Passed The description comprehensively covers all changes with clear explanations of each fix, includes testing details, and documents the impact and rationale for each change.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot added bug Something isn't working enhancement New feature or request area/server size/m labels Jun 16, 2026
@alecray alecray marked this pull request as draft June 16, 2026 17:15
// which Destroy() the new actor when component setup fails).
auto RollbackSpawn = [&Spawned]() {
if (IsValid(Spawned)) {
Spawned->Destroy();

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nit] Rollback uses Spawned->Destroy(). Other control_actor paths delete editor-world actors via UEditorActorSubsystem::DestroyActor(...) (undo/editor-integrated). Destroy() matches the spline handlers so it's not wrong — just flagging the inconsistency if you'd prefer transaction-aware cleanup here.

Options.bCanModifyEmittersFromTimeline = false;
Options.bCanSimulate = false;
Options.bCompileForEdit = false;
Options.bIsForDataProcessingOnly = false;

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[question] Full (bIsForDataProcessingOnly=false) view model is required to get per-module stack issues (data-processing mode early-outs in UNiagaraStackModuleItem::RefreshIssues), but two costs are worth confirming: (1) it's heavyweight per call — Initialize()->RefreshAll() compiles/resets the system and builds a sequencer; (2) if the same UNiagaraSystem is already open in a Niagara editor, this spins a second full VM for it (both register undo / reset), which could disturb the open session. Should validate guard on UAssetEditorSubsystem::FindEditorsForAsset (reuse/skip if open), or is a transient second VM acceptable?

@alecray alecray left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Self-review as a skeptical maintainer (I authored this). Reviewed all 5 changed files in full.

Checks run

  • npm run build (tsc) — ✅ PASS (TS unaffected; this is a C++-only PR)
  • npm run test:native-parity — ✅ PASS (23/23 tools, 0 action mismatches; the new error codes + env var did not desync the native↔TS tool catalog)
  • npm run test:unit (vitest) — 17/594 fail, but all pre-existing on dev and in files this PR doesn't touch (14 are parity-parser self-tests; the rest are manage_effect routing, environment asset-name, and pipeline-dotnet tests). Not introduced here.
  • cpplint not available in this environment. C++ instead compile-verified via two clean UE 5.8 builds (isolated bench + a host project) and behavior HTTP-verified (validate detects unmet-dependency errors; spawn returns MESH_NOT_FOUND/MESH_APPLY_FAILED and leaves the world unchanged; env override binds the override port; ListenPorts warning fires).

Security — no new input surface: meshPath still routes through SanitizeProjectRelativePath; MCP_NATIVE_PORT is integer-parsed + range-checked (1–65535); the env override changes only the port, not the host/loopback policy. No shell/path is built. Does not touch the TS safety layer.

No blockers. Items to address (left inline):

  • [should-fix] Document MCP_NATIVE_PORT and CHANGELOG the behavior changes (and consider a .uplugin bump).
  • [should-fix] Stricter spawn-on-bad-meshPath is potentially breaking for existing callers — call it out.
  • [question] Confirm the full-VM validate_niagara_system cost / already-open-asset case is acceptable, or guard via FindEditorsForAsset.
  • [nit] Rollback Destroy() vs UEditorActorSubsystem::DestroyActor consistency.

Note: this bundles 5 independent fixes — happy to split into separate PRs if you'd prefer to merge piecemeal.

@alecray alecray changed the title UE 5.8 fixes: build, validate_niagara_system, transactional spawn, ListenPorts warning, MCP_NATIVE_PORT env feat: UE 5.8 plugin fixes (validate_niagara_system, transactional spawn, ListenPorts warning, MCP_NATIVE_PORT env) Jun 16, 2026
Addresses review feedback on PR ChiR24#479: add a CHANGELOG [Unreleased] section covering all the changes, document the new MCP_NATIVE_PORT env var in the plugin README env-var table + Native MCP Port setting, and explicitly flag the stricter control_actor spawn (bad meshPath now returns MESH_NOT_FOUND) as potentially breaking.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@alecray alecray marked this pull request as ready for review June 16, 2026 17:45
alecray added a commit to alecray/Unreal_mcp that referenced this pull request Jun 16, 2026
…iewed, WPF ported, next-improvement backlog

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@ChiR24 ChiR24 merged commit b3d15af into ChiR24:dev Jul 7, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants