AGENTS.md@mcps/unreal_mcp/plugins/EngineWire/Source/EngineWire/Private/Foundation · git:20261104.ed35fa4 · 2026-11-04 · sha256 2a858928e0daacf9
AGENTS.md@mcps/unreal_mcp/plugins/EngineWire/Source/EngineWire/Private/Foundation git:20261104.ed35fa4A
Immutable. This exact content never changes and is served at /api/v1/blob/2a858928e0daacf9.
# Foundation AGENTS.md
Shared primitives for the EngineWire plugin. If you are writing a
handler in `Private/Domains/`, reuse what lives here. Do not grow a
domain-local copy of reflection, path, JSON, or response helpers.
## STRUCTURE (subdir -> what it gives you)
| Subdir | Count | Gives you |
|--------|-------|-----------|
| `Reflection/` | 3 .h (11 files w/ .cpp) | UE property <-> JSON serialization boundary |
| `HandlerUtils/` | 7 .h | action normalization, JSON/path/response/transform helpers |
| `Blueprint/` | 5 .cpp | BP pin/type introspection (no public .h; pull via subsystem) |
| `Diagnostics/` | 6 files | diagnostics snapshot capture/load/rotation + file-name/schema helpers |
| `GraphLayout/` | 1 file | graph node extent geometry |
| `Solvers/` | 23 files | general algorithms, one per file (a long one split), each with a known-answer test: `McpPratt` (the assertion language of execute's `expect`/`require`), `McpAnneal` (Metropolis annealing over a caller's state), `McpBoxSat` (boxes turned about Z: separation, depth, containment), `McpKMeans` (weighted k-means, fixed seed), `McpWatershed` (basins of a height over a graph, merged across high saddles), `McpBetweenness` (Brandes route shares of weighted nodes and edges), `McpCassowary` (linear constraints, required or preferred by strength, solved by the incremental simplex Kiwi builds) |
| `Optimize/` | 6 files | `McpNelderMead`: the downhill simplex, for a cost of a few variables with no gradient (a camera judged by traces); `McpMinSnap`: the minimum-snap path through points (Richter et al.'s closed form) and a small dense solver; each with a known-answer test |
| `Render/` | 5 files | post-process volume resolution, console variable writes, stat overlay state |
| `BridgeHelpers/` | umbrella + 7 groups | asset/actor/BP/property/response/security facade |
| root | `McpSecureTokenCompare.h` | constant-time token equality |
`Foundation` is split finely (<=25 files/folder, 250 pure-line ceiling) so
`tests/unit/plugin/source_structure*.test.ts` passes. Keep it that way.
## WHERE TO LOOK (Need -> use this header)
| Need | Use this header |
|------|-----------------|
| Serialize a UObject/UProperty to JSON | `Reflection/McpPropertyReflection.h` (`McpPropertyReflection`) |
| Apply JSON onto a property/object | `Reflection/McpPropertyReflection.h` `ApplyJsonValueToProperty` / `ApplyJsonObjectToObject` |
| Property type name / support check | `Reflection/McpPropertyReflection.h` `GetPropertyTypeName` / `IsPropertyTypeSupported` |
| Dispatch an action in a handler | Resolve with `HandlerUtils/McpHandlerUtilsActionsPaths.h` `NormalizeAction`, then an explicit compare chain (see `../Domains/AGENTS.md`) |
| Build an error response | `SendAutomationError(Socket, RequestId, Message, Code)` on the subsystem |
| Normalize/sanitize action + path strings | `HandlerUtils/McpHandlerUtilsActionsPaths.h` |
| Extract/coerce JSON fields | `HandlerUtils/McpHandlerUtilsJson.h` |
| Standard response builders | `HandlerUtils/McpHandlerUtilsResponses.h` |
| Transform / math helpers | `HandlerUtils/McpHandlerUtilsTransforms.h` |
| BP graph node helpers | `HandlerUtils/McpHandlerUtilsBlueprintGraph.h` |
| Resolve / validate `/Game` asset path | `BridgeHelpers/Assets/McpAssetResolve.h` |
| Create assets / dirs / save registry | `BridgeHelpers/Assets/{AssetCreation,AssetDirectories,AssetSaveRegistry}.h` |
| Spawn an actor | `BridgeHelpers/Actors/McpActorSpawnHelpers.h` |
| Load / compile BP, SCS lookup, BP paths | `BridgeHelpers/Blueprints/{BlueprintAssetLoad,BlueprintCompilation,ScsLookup,BlueprintPaths}.h` |
| Read/apply a property (scalar/object/array) | `BridgeHelpers/Properties/{PropertyLookup,NestedPropertyPath,ComponentLookup,PropertyApply*}.h` (export: `Reflection/McpPropertyReflection.h`) |
| Resolve a UClass by name | `BridgeHelpers/Reflection/McpClassResolve.h` |
| Build / verify response, capture output, JSON fields | `BridgeHelpers/Responses/{Responses,ResponseVerification,OutputCapture,JsonFields}.h` |
| Set a console variable and know it took | `Render/McpConsoleVariableWrite.h` `McpSetConsoleVariable` (console priority by default, read-only refused, read back; `IConsoleVariable::Set` alone loses to a console set silently) |
| Show or hide a stat overlay without toggling it twice | `Render/McpViewportStats.h` `McpIsStatShown` (the viewport a Stat command lands on: the running game, else the last level viewport; Stat commands toggle) |
| Give a spawned volume real bounds | `../Domains/Volume/McpVolumeGeometry.h` `VolumeHelpers::CreateBoxBrushForVolume` (a volume from `SpawnActor` has no brush; scaling it leaves zero bounds) |
| Everything at once | `BridgeHelpers/McpHelpers.h` (umbrella) |
`Reflection/McpPropertyReflection.h` is THE UE-property <-> JSON boundary.
Every domain that touches properties funnels through it.
## THE SECURITY PRIMITIVES
- `McpSecureTokenCompare.h` -> `McpConstantTimeTokenEquals(A, B)`: XOR-accumulates
the full UTF-8 span, folds length, no early exit. Called by BOTH the WebSocket
bridge and native `/mcp`. Never replace with `==` / `Equals` (contract test fails).
- `BridgeHelpers/Security/McpProjectPaths.h`: confines paths
to project roots (`/Game/...`, mount points), rejects `..`, `:`, `//`.
- `BridgeHelpers/Security/McpCommandValidate.h`: blocklist
of `&&`, `||`, `;`, `|`, backtick, `<`, `>`, newline, CR for console/UBT args.
- Hazardous editor ops (save/load/delete) live in `../Safety/`; include
`Safety/McpSafeOperations.h`, which also declares the unqualified spellings
(`McpSafeAssetSave`, `ScanPathSynchronous`, ...). See `../Safety/AGENTS.md`.
## CONVENTIONS
- SCS rule: Blueprint component templates must be owned by SCS nodes via
`SCS->CreateNode()` / `SCS->AddNode()`. Relevant to `Blueprint/` and
`BridgeHelpers/Blueprints/ScsLookup`. Do not attach templates ad hoc.
- Adding a handler is a Core/Domains concern; the registration flow lives in
`../Core/AGENTS.md` and `../Domains/AGENTS.md`.
- Every local `Mcp*` include must resolve (contract test). Include the umbrella
`McpHelpers.h` unless you need a single shard.
## ANTI-PATTERNS
- Top one: writing a domain-local copy of a reflection/path/JSON/response helper
that already lives here. Reuse it.
- Reimplementing `McpConstantTimeTokenEquals` with `==` / `FString::Equals`.
- Hand-rolling `/Game` path validation instead of `...ProjectPaths.h`.
- Skipping `...CommandValidation.h` on console-command strings.
- Building responses by hand when `McpHandlerUtilsResponses.h` exists.