AGENTS.md@mcps/unreal_mcp · git:20260727.48beb34 · 2026-07-27 · sha256 a92edd650efa7962

AGENTS.md@mcps/unreal_mcp git:20260727.48beb34A

Immutable. This exact content is served forever at /api/v1/blob/a92edd650efa7962.

# PROJECT KNOWLEDGE BASE

**Generated:** 2026-06-07 12:38:08 IST
**Commit:** f6c6285e
**Branch:** dev

## OVERVIEW
MCP tooling for Unreal Engine 5.0-5.8 Preview. Server package version `0.5.30`; bridge plugin version `0.5.30`. The repo has three user-facing surfaces: a TypeScript stdio MCP server, the bridge plugin's WebSocket and optional native `/mcp` HTTP/SSE transports, and an experimental UnrealAgent editor panel that drives OpenCode over ACP.

## STRUCTURE
```
./
|-- src/                         # TypeScript MCP server, NodeNext ESM
|   |-- server/                  # MCP tool/resource registration and dynamic filtering
|   |-- tools/                   # 23 parent tool schemas, action enums, TS dispatch
|   |-- automation/              # WebSocket client, handshake, request tracking
|   |-- services/                # health and optional Prometheus metrics
|   `-- utils/                   # path safety, command validation, logging, schemas
|-- plugins/McpAutomationBridge/ # Unreal editor automation bridge + native MCP
|   `-- Source/McpAutomationBridge/
|       |-- Public/              # settings, subsystem, connection manager API
|       `-- Private/             # core routing, domains, shared helpers, safety, transports
|-- plugins/UnrealAgent/         # optional in-editor OpenCode ACP assistant panel
|-- tests/                       # Vitest unit tests and custom MCP integration runner
|-- scripts/                     # plugin packaging, sync, smoke, cleanup helpers
|-- docs/                        # handler maps, testing, and plugin extension notes
`-- .github/workflows/           # pinned CI, release, registry, security workflows
```

## WHERE TO LOOK
| Task | Location | Notes |
|------|----------|-------|
| Start TS MCP server | `src/cli.ts`, `src/index.ts`, `src/server/server-factory.ts`, `src/server/stdio-lifecycle.ts` | CLI shim -> public facade -> construction/lifecycle -> registration |
| Add or change a TS tool contract | `src/tools/catalog/consolidated-tool-definitions.ts`, `src/tools/definitions/` | Source of truth for parent tools, actions, categories, output schemas |
| Register TS tool behavior | `src/tools/orchestration/consolidated-handler-registration.ts`, `src/server/tool-registry.ts` | `consolidated-tool-handlers.ts` is the bootstrap/export facade |
| Implement TS action logic | `src/tools/handlers/<domain>/` | Validate/normalize, then use the shared dispatch helpers |
| Change WebSocket automation | `src/automation/` | Handshake, connection policy, request tracking, token/TLS plumbing |
| Change Unreal request routing | `plugins/McpAutomationBridge/.../Private/Core/` | Queue, game-thread dispatch, handler registration, responses |
| Add Unreal bridge behavior | `plugins/McpAutomationBridge/.../Private/Domains/<Domain>/` | Register through the matching `Private/Core/Subsystem/*Registration.cpp` shard |
| Add native MCP schema/tool metadata | `plugins/McpAutomationBridge/.../Private/MCP/` | Self-register with `MCP_REGISTER_TOOL`; keep canonical names only |
| Change shared Unreal helpers | `plugins/McpAutomationBridge/.../Private/Foundation/` | Reflection, Blueprint helpers, paths, responses, handler utilities |
| Fix UE save/load/delete crashes | `plugins/McpAutomationBridge/.../Private/Safety/` | Use the project wrappers and preserve verification/cleanup |
| Change bridge sockets | `plugins/McpAutomationBridge/.../Private/Transport/` | WebSocket framing/TLS plus connection auth, rate limits, telemetry |
| Change UnrealAgent ACP/UI | `plugins/UnrealAgent/.../Private/Acp/`, `plugins/UnrealAgent/.../Private/UI/` | Keep process/protocol work out of Slate layout code |
| Path and command security | `src/utils/paths/path-security.ts`, `src/utils/commands/command-validator.ts` | Enforce UE roots and console-command block lists |
| Integration tests | `tests/test-runner.mjs`, `tests/mcp-tools/` | Pipe-separated expectations; Unreal-dependent unless mocked |
| Version bump | `.github/workflows/bump-version.yml` | Updates server files; plugin `.uplugin` versions are separate |
| Plugin packaging | `scripts/package-plugin.*`, `scripts/sync-mcp-plugin.js` | RunUAT packaging and Engine/Project plugin sync |

## CODE MAP
| Symbol | Type | Location | Refs | Role |
|--------|------|----------|------|------|
| `createServer()` / `startStdioServer()` | TS functions | `src/server/server-factory.ts`, `src/server/stdio-lifecycle.ts` | high | Server construction, stdio lifecycle, and stdout safety |
| `registerDefaultHandlers()` | TS function | `src/tools/orchestration/consolidated-handler-registration.ts` | medium | Parent tool -> handler map |
| `executeAutomationRequest()` | TS function | `src/tools/handlers/foundation/dispatch/automation-request-dispatch.ts` | very high | Validated TS-to-Unreal request boundary |
| `AutomationBridge` | TS class | `src/automation/bridge.ts` | high | WebSocket connect/handshake/request queue |
| `UMcpAutomationBridgeSubsystem` | C++ class | `plugins/McpAutomationBridge/.../Public/McpAutomationBridgeSubsystem.h` | high | Plugin request queue, native MCP startup, handler map |
| `FMcpNativeTransport` | C++ class | `plugins/McpAutomationBridge/.../Private/MCP/Transport/` | medium | Native `/mcp` HTTP/SSE JSON-RPC endpoint |
| `SUnrealAgentPanel` / `FOpenCodeAcpClient` | C++ classes | `plugins/UnrealAgent/.../Private/UI/Core/`, `Private/Acp/Client/` | high | In-editor ACP chat surface and process/session client |

## CONVENTIONS
### Transport Surfaces
1. **TypeScript stdio MCP**: `src/index.ts` exposes the public API, `src/server/` owns construction/lifecycle, and `src/automation/` connects to Unreal.
2. **WebSocket bridge**: Plugin listen sockets default to loopback ports `8090,8091`; TS sends automation requests through the negotiated bridge.
3. **Native MCP**: Optional plugin HTTP/SSE endpoint under `Private/MCP/`; `GET /mcp` opens SSE, `POST /mcp` handles JSON-RPC, `DELETE /mcp` tears down sessions.
4. **UnrealAgent ACP**: Optional editor panel starts `opencode acp`; it can inject the configured native `unreal-engine` MCP endpoint but does not expose MCP tools itself.

### Security Boundaries
- Loopback-only is the default. Non-loopback requires `MCP_AUTOMATION_ALLOW_NON_LOOPBACK=true` in TS or `bAllowNonLoopback` in plugin settings.
- Capability-token auth uses `X-MCP-Capability-Token` for native MCP and `bridge_hello.capabilityToken` for WebSocket when enabled.
- Metrics are separate: non-loopback metrics require both `MCP_METRICS_ALLOW_NON_LOOPBACK=true` and `MCP_METRICS_TOKEN`.
- Paths are limited to `/Game`, `/Engine`, `/Script`, `/Temp`, `/Niagara`, plus sanitized `MCP_ADDITIONAL_PATH_PREFIXES`.

### UE Safety
- Do not call `UPackage::SavePackage()` directly. Use `McpSafeAssetSave`, `McpSafeLevelSave`, or `McpSafeLoadMap` wrappers.
- Blueprint component templates must be owned by SCS nodes created through `SCS->CreateNode()` and `SCS->AddNode()`.
- Do not introduce `ANY_PACKAGE`; use modern lookup patterns such as `nullptr` or project helper resolution.
- Editor API work enters through the subsystem queue and runs on the game thread; unsafe save/GC/async-load states are deferred.

### TypeScript Standards
- Strict NodeNext TypeScript. Do not add `as any`, `@ts-ignore`, or runtime `console.log`.
- Runtime logs must go through `Logger`; `routeStdoutLogsToStderr()` protects JSON-RPC stdout.
- Output schemas are registered at startup and should stay schema-backed.

## ANTI-PATTERNS (THIS PROJECT)
- Bypassing registry flow: never call handlers directly instead of `toolRegistry.register()` and `handleConsolidatedToolCall()`.
- Raw WebSocket calls from tools: use `executeAutomationRequest()` and the automation bridge queue.
- Unvalidated external input: command strings go through `CommandValidator`; paths go through normalization/security helpers.
- LAN exposure by accident: do not bind to `0.0.0.0` or non-loopback without explicit opt-in and token planning.
- Mixing transports: native `/mcp`, plugin WebSocket, TS stdio, and ACP are separate lifecycles; do not route around their registry/session boundaries.
- Generated knowledge bases: do not place AGENTS files in `dist/`, `build/`, `coverage/`, `tests/reports/`, `tmp/`, plugin `Binaries/`, plugin `Intermediate/`, or uppercase staging mirrors such as `Plugins/`.

## UNIQUE STYLES
- 23 canonical parent tools hide hundreds of actions behind action enums to reduce client context.
- Dynamic tool management exists in both TS and native MCP; `manage_tools` and `inspect` are protected.
- The native plugin has self-describing MCP tool definitions in C++ separate from TS JSON schemas.
- Test expectations use string grammar such as `success|error|timeout`; first token is the primary intent.
- The bridge plugin is responsibility-split: `Core` routes, `Domains` implement, `Foundation` shares primitives, `Safety` wraps hazardous editor operations, and `Transport` owns sockets.

## COMMANDS
```bash
npm run build:core      # Compile TypeScript server
npm run type-check      # Type-check without emitting
npm run test:unit       # Vitest unit tests, no Unreal required
npm run test:smoke      # Mock-mode in-memory MCP smoke test
npm test                # Unreal-dependent MCP integration entry
npm run test:native-parity # Compare TS and native MCP tool surfaces
npm run test:params     # Native parity + strict parameter-combination audit
npm run automation:sync # Copy/sync bridge plugin into a target project
npm run clean:tmp       # Safe cleanup of repo tmp/ artifacts
```

## NOTES
- Engine reference path: `/data/UnrealEngine/Engine/`.
- Server version sources: `package.json`, `package-lock.json`, `server.json`, and the `src/server/server-factory.ts` fallback. Bridge and UnrealAgent versions live in their separate `.uplugin` files.
- External GitHub Actions are expected to be pinned to full commit SHAs.
- `tests/reports/`, root `build/`, root `tmp/`, root `Public/`, uppercase `Plugins/`, `.cache/`, `.opencode/node_modules/`, and package/plugin build outputs are not instruction targets.