Development
Development documentation.
Prerequisites
- Node.js 18+
- Unreal Engine 5.4–5.7 (for live testing)
- A UE project to test against
Setup
git clone https://github.com/db-lyon/ue-mcp.git
cd ue-mcp
npm installResolving an Issue with Claude Code
From inside your ue-mcp clone:
npx ue-mcp resolve 16This:
- Fetches issue #16 from
db-lyon/ue-mcpviagh. - Creates a
resolve/16branch fromorigin/mainin your current checkout. - Pipes a generated prompt (issue body + repo conventions) into
claude --print --dangerously-skip-permissions. - Claude reads code, implements the fix, runs
npx tsc --noEmit, and commits. - The script then pushes the branch and opens a PR against
db-lyon/ue-mcp.
Requires gh and claude CLIs, write access to the repo (or a fork to push to), and you must run it from inside a ue-mcp clone — it operates on the working tree, not a temp clone.
Building
npx tsc # TypeScript -> dist/ (what the server ships as)
npm run build # UE C++ plugin build (requires editor closed)npx tsc emits the TypeScript server into dist/. npm run build is the C++ plugin build that runs Unreal's Build.bat against the test project and requires the editor to be closed first. Use npm run up:build to chain stop-build-start during plugin iteration.
Running
# Build and run
npm run up:build
# Run (assumes already built)
npm run up
# Dev mode (tsx, no build step)
npm run dev
# Direct
node dist/index.js C:/path/to/MyGame.uproject
# Interactive setup (also available via npx ue-mcp init)
node dist/index.js init C:/path/to/MyGame.uprojectProject Structure
src/
├── index.ts # Entry point, tool registration, MCP server
├── tools.ts # ALL_TOOLS registry (consumed by index.ts and tests)
├── types.ts # ToolDef, ActionSpec, categoryTool() factory
├── bridge.ts # EditorBridge - WebSocket JSON-RPC client
├── project.ts # ProjectContext - paths, INI, C++ parsing
├── deployer.ts # Plugin deployment
├── editor-control.ts # Editor process management
├── instructions.ts # AI-facing server instructions
├── github-app.ts # GitHub App auth for feedback submission
├── init.ts / update.ts / resolve.ts / hook-handler.ts # CLI subcommands
├── flow/ # Flow engine (registry, loader, task factory, HTTP)
└── tools/ # 19 tool category implementations
├── project.ts
├── asset.ts
├── blueprint.ts
├── level.ts
├── material.ts
├── animation.ts
├── landscape.ts
├── pcg.ts
├── foliage.ts
├── niagara.ts
├── audio.ts
├── widget.ts
├── editor.ts
├── reflection.ts
├── gameplay.ts
├── gas.ts
├── networking.ts
├── demo.ts
└── feedback.ts
plugin/ue_mcp_bridge/ # C++ bridge plugin (deployed to UE projects)
└── Source/UE_MCP_Bridge/
├── UE_MCP_Bridge.Build.cs
└── Private/
├── BridgeServer.cpp/.h
├── HandlerRegistry.cpp/.h
├── GameThreadExecutor.cpp/.h
└── Handlers/ # 22 C++ handler groups
tests/smoke/ # Smoke tests (require live editor)
tests/unit/ # Pure-TypeScript unit tests (no editor needed)
scripts/ # Build and run scripts
docs/ # Documentation (MkDocs Material)Testing
Unit Tests
Pure-TypeScript tests under tests/unit/. No editor required.
npm run test:unitThese also run in CI on every PR.
Smoke Tests
Smoke tests run against a live editor and verify tool functionality end-to-end.
# Specific suite
npm run test:level
npm run test:blueprint
npm run test:material
# ... 16 suites total — see scripts in package.json
# All suites (Vitest)
npm test
# Full smoke test runner — exercises every registered handler
npm run test:smokeSmoke tests require the test project
The smoke runner targets tests/ue_mcp/ue_mcp.uproject only. Real mutations execute against the connected editor (creating blueprints, deleting assets, modifying the level). Never run smoke tests against a real project. The runner aborts if it detects a connection to anything else.
Prerequisites
- Editor running with the test project
- Bridge connected (
project(action="get_status")returnsbridgeConnected: true)
Test Suites
| Suite | What It Tests |
|---|---|
level | Actor CRUD, selection, components, volumes, lights |
asset | Asset listing, search, CRUD, import |
blueprint | BP reading, creation, graph editing, compilation |
material | Material creation, parameters, instances |
editor | Console, PIE, viewport, undo/redo |
reflection | Class/struct/enum reflection, gameplay tags |
animation | Anim BP, montages, skeletons |
landscape | Landscape info, sculpting, painting |
gameplay | Physics, collision, navigation, AI |
audio | Sound listing, playback |
niagara | Niagara system inspection and authoring |
pcg | PCG graph listing and authoring |
foliage | Foliage types |
widget | Widget blueprint creation, tree manipulation, slot properties |
networking | Replication config |
gas | GAS component inspection |
Adding a New Tool
TypeScript Side
- Create
src/tools/myfeature.ts:
import { categoryTool, bp, type ToolDef } from '../types.js';
import { z } from 'zod';
export const myfeatureTool: ToolDef = categoryTool(
'myfeature',
'Description of this tool category',
{
my_action: bp('my_cpp_handler_method'),
local_action: {
handler: async (ctx, params) => {
// local implementation
return { result: 'done' };
},
},
},
'- my_action: Does something. Params: foo, bar\n- local_action: Does something locally.',
{
foo: z.string().optional().describe('Description of foo'),
},
);- Register it in
src/index.ts.
C++ Side
- Create handler files in
plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/ - Register handlers in
BridgeServer.cpp - Each handler receives
TSharedPtr[FJsonObject]params and returnsTSharedPtr[FJsonValue]
C++ Plugin Development
The plugin source lives in plugin/ue_mcp_bridge/. When you modify C++ handler code:
- Edit the source in
plugin/ue_mcp_bridge/ - The deployer copies the plugin to the target project on server start
- In the editor, use Live Coding (Ctrl+Alt+F11) or
editor(action="hot_reload")to reload
For a full editor restart: editor(action="restart_editor")
Dependencies
Runtime
@modelcontextprotocol/sdk— MCP protocol implementationws— WebSocket clientzod— Schema validation
Dev
typescript— Type checkingtsx— TypeScript execution (dev mode)vitest— Test runner