ue5-gameplay-mcp
Allows interaction with a running Unreal Engine 5 game, providing virtual gamepad/keyboard/mouse input injection, screen capture, live logs, UI inspection and clicking, game state queries, and console command execution.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@ue5-gameplay-mcpMove the character forward with the gamepad, then observe what’s on screen."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
ue5-gameplay-mcp
An MCP server that plays a running Unreal Engine 5 game. It accepts virtual gamepad, keyboard, and mouse input and returns screen capture, log lines, and UMG status.
This is not an engine plugin; it is a client. Two plugins already handle the in-engine work, and each holds its own port. This server dials into both and exposes them as a single tool interface.
Plugin | Port | Features |
RemoteConsole2 | 10101 | Gamepad/keyboard/mouse injection via |
RemoteCapturePlugin | 10102 | JPEG/PNG screen capture (works in PIE and packaged builds) ships with |
A small amount of C++ was added to both plugins specifically for this server. They remain independent and keep their own protocols. The additions are backward compatible, so even older clients can still communicate with a rebuilt game:
FImageMeta.SourceSize— the game's back-buffer size. It is packed into a previously reserved area to keep the struct at 24 bytes, so the client can map a specific point on a downscaled capture back to actual window pixels.CMD_GET_GAME_STATE(520) andIRemoteGameStateProvider— more on this below.
Setup
cd ue5_gameplay_mcp
uv syncMCP Python SDK v2 (mcp.server.MCPServer) is required.
Related MCP server: VERA MCP Server
How to run
Start the game first. In this project, a standalone game is run from the editor binary because the Game target exits immediately in a project that has not been cooked:
"C:/Program Files/Epic Games/UE_5.8/Engine/Binaries/Win64/UnrealEditor.exe" "<PATH>/MyProject.uproject" -game -windowed -resx=1280 -resy=720 -log -nosplashNext, register the server. The .mcp.json in the project root already does this, so Claude Code will pick it up automatically. The manual command equivalent is:
claude mcp add ue5-gameplay -- uv run --directory <PATH>/ue5_gameplay_mcp -m ue5_gameplay_mcpThe server uses a lazy connection, so the actual startup order does not matter. If it starts before the game does, it will connect on the first tool call.
Options: --host, --console-port, --capture-port, --format, --quality, --max-size, --grid-step, --transport streamable-http --mcp-port 14102.
Tools
Session — game_connect, game_status, game_reset_input
Observation — game_observe, game_state, game_log, game_wait_for_log
Actions — game_pad, game_pad_sequence, game_key, game_mouse, game_console, game_time_scale
UMG — game_ui_dump, game_ui_click, game_ui_focus
API design and the reason for it
An agent round trip takes several seconds, but the game runs at 60 Hz. Since frame-by-frame actions are unrealistic, the design works as follows:
All action tools take a
durationand perform a press / hold / release sequence locally, paced to the communication speed. One round trip carries one intent, not one frame.Action tools observe by default.
game_pad(ly=1.0, duration=0.5)moves forward and returns the resulting frame. This takes half as many round trips as doing the action and the observation separately.game_pad_sequencepacks an entire combo into one call when the timing of the inputs matters more than checking between them.game_time_scale(0.2)buys in-game time when precision at a particular moment is required.hold=Truekeeps the input applied between turns so the character keeps moving while the agent is thinking.game_reset_inputclears it.
Numbers, not pixels
game_state returns the level, world time, pause/time dilation, player pawn transform, velocity, movement mode, camera, and the distance and normalized screen position of the nearest actor. These are the same 0–1 coordinates game_mouse receives, so you can immediately aim at a target you find in the status report. The cost is a fraction of image processing, and it will not misread HUD numbers.
game_observe(state=True) folds this into what an observation, and `game_pad(..., state=True)' folds it into an action, so movement and verification still take only one round trip.
On a real map, most nearest actors are background objects, so the report also includes class_counts (a survey of all objects within the radius). Read it once, and you can narrow it down with class_filter="Enemy".
Adding game-specific numbers
The built-in report needs no game-side query. For anything only that project knows — health, score, quest flags, etc. — implement IRemoteGameStateProvider (Plugins/RemoteConsole2/Source/RemoteConsole2/RemoteGameState.h) on any actor and return the string of a JSON object:
FString AMyGameMode::GetRemoteGameState_Implementation()
{
return FString::Printf( TEXT("{\"score\":%d,\"wave\":%d}"), Score, Wave );
}Since it's a BlueprintNativeEvent, it can be overridden even in Blueprint-only projects. All returned values are stored under custom, keyed by actor name. Providers are collected regardless of the distance filter, so even a scorekeeper handled at the origin will send a report. Text that is not valid JSON is not discarded; it is passed through as its raw string, so even simple Printf debugging while starting up is helpful.
Three ways to drive the menu (recommended order)
game_ui_dump+game_ui_click— exact and fast, but only knows widgets registered through UMG. Games with a custom Slate UI get nothing back, and the tool explicitly says so instead of hanging.Pad navigation —
game_pad(buttons=["DOWN"]),game_pad(buttons=["A"]). Works with almost any game.Look & click —
game_observe(grid=True)overlays a labeled 0–1 coordinate grid on the capture. Read the target from the image and pass the same numbers togame_mouse(x=..., y=...). It is independent of user resolution and works no matter how the UI is built.
Conventions
Sticks follow UE's specification:
ly=+1is forward. (The protocol flips the Y axis, but our code flips it back, so the tool API matches what the game's own axis mapping means.)Mouse coordinates are normalized to 0–1 with the top-left as origin, and are translated to pixels using the game's actual back-buffer size. Since the capture reports its resized dimensions, this source size is probed separately.
game_observereturns only new log lines since the previous observation, so the same output is never resent, even during a long session.
Known issues and unfinished parts
When hosting the game from the editor binary, console commands are routed through Python.
FGameAppInterface::ExecConsoleCommanddispatches to the implementation ofIConsoleCommandExecutor[0]; if the editor's Python plugin is loaded, that slot is Python instead of Cmd. So a plainstat fpscomes back as aSyntaxError. On first use the server probes this, and if it detects the problem, it wraps the command withunreal.SystemLibrary.execute_console_command. Packaged builds have no Python executor, so this solution is not needed. You can also override it withgame_console(via="cmd")`.Screen clicks assume the capture fills the entire game window. This is true with
-game -windowed. In a letterboxed fullscreen mode, the reported source size includes the black bars, so the mapping is off.game_statetraverses every actor in the level on each call. At normal map scale this is fine, but a streaming open world would probably need a spatial query instead ofTActorIterator.
Tests
uv run test/smoke_test.pyCommunicates directly with the game and outputs smoke_*.jpg, allowing you to check the capture and grid overlays visually.
uv run test/mcp_client_test.pyStarts the server via standard input/output (stdio) as a real MCP client, and runs and tests all tools, including error paths.
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- AlicenseBqualityAmaintenanceEnables AI assistants to control Unreal Engine via Remote Control API for game development automation, including asset management, actor control, level editing, animation, physics, visual effects, and cinematics creation through natural language.1336830MIT
- AlicenseNot gradedqualityBmaintenanceEnables AI clients like Claude Code, Cursor, or VS Code to drive the Unreal Editor: execute Python, capture screenshots, tail logs, check status, and run VERA commands.13MIT
- AlicenseNot gradedqualityAmaintenanceEnables AI agents to interact with a running Roblox game client to execute Lua code, inspect scripts, spy on remotes, and more.143216MIT
- AlicenseAqualityDmaintenanceEnables AI assistants to interact with Unreal Engine via Remote Control API for actor, asset, level, and editor operations.2215MIT
Related MCP Connectors
Control Unreal Engine to browse assets, import content, and manage levels and sequences. Automate…
A comprehensive Model Context Protocol (MCP) server that enables AI assistants to control Unreal E…
Drive a live Cinevva game session: edit game files, import CC0 assets, preview changes.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/hiroog/ue5_gameplay_mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server