Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/davidbuenov/dbv-mcp-server/llms.txt

Use this file to discover all available pages before exploring further.

The Unreal MCP Web Client is a layered system that bridges browser and AI clients to the Unreal Engine 5.8 MCP server. It consists of a FastAPI proxy (server.py) for HTTP clients, a stdio bridge (bridge.py) for Claude Desktop, a three-tier tool cache keyed by MD5 hash, and a 20-iteration Gemini agent loop — all backed by a local Playwright-crawled knowledge base of ~15,000 Unreal Engine documentation pages.

Stack Overview

The Unreal MCP Web Client is composed of several discrete layers, each chosen to solve a specific constraint. The table below maps each layer to its technology and purpose.
LayerTechnologyPurpose
Frontend CoreHTML5, JavaScript (ES6+)Single-page application with no build step — instant load and native browser debugging
StylesVanilla CSS3 (HSL tokens, glassmorphism dark theme)Full control of animations and custom visual design with zero heavy dependencies
Proxy ServerPython FastAPI + Uvicorn + HTTPXAsync-first: reads Unreal SSE streams in the background without blocking other requests; injects CORS headers automatically
Stream ReaderFetch Streams APINative async text/event-stream reading without external libraries
AI AgentGoogle Gemini API (generateContent)Multi-turn tool calling against Unreal MCP toolsets, up to 20 iterations with intelligent wrap-up
Bridge CLIbridge.py (stdio-to-HTTP-SSE)Allows Claude Desktop and any standard MCP stdio client to consume Unreal tools as if they were native
Knowledge Basedbv-unreal-python-api skillTwo tools under one skill: dbv_python_unreal_api (~11,600 UE 5.8 Python API class pages) and dbv_unreal_dev_guide (~3,600 official UE 5.8 conceptual guide pages)
Guide CrawlerPlaywright + Chromium headlessEpic’s documentation portal is protected by Cloudflare Bot Management — urllib/curl receive 403. The crawler opens a real browser context per page to obtain a valid trust session for every request

System Diagram

The following diagram shows the complete request path from a browser or Claude Desktop client through the proxy layers to the Unreal Engine MCP server.
Browser / Claude Desktop
       │  POST /mcp or stdin

  server.py (FastAPI :5000)     bridge.py (stdio)
  ┌─────────────────────────┐  ┌─────────────────────────┐
  │  tools/list → flatten   │  │  tools/list → flatten   │
  │  tools/call → translate │  │  tools/call → translate │
  │  CORS headers           │  │  JSON-RPC 2.0 stdout    │
  └────────────┬────────────┘  └────────────┬────────────┘
               │ HTTP proxy                  │ HTTP
               ▼                             ▼
       Unreal Engine MCP Server (:8000)
server.py is the path for the browser-based SPA and any HTTP client. It runs on port 5000 and proxies to http://localhost:8000/mcp. bridge.py is the path for Claude Desktop and other MCP stdio clients. It reads JSON-RPC 2.0 messages from stdin, forwards them over HTTP to the same Unreal MCP endpoint, and writes responses to stdout. Log messages are written to stderr so they never pollute the JSON-RPC channel. Both paths share the same flattening and namespace-translation logic described in the sections below.

Tool Cache Architecture

Because building the full toolset list requires one list_toolsets call plus one describe_toolset call per toolset (potentially 10+ concurrent network round-trips to Unreal), the proxies implement a three-tier cache:
1. Hash(list_toolsets) == in-memory hash   →  immediate return (0 ms)
2. Hash(list_toolsets) == disk cache hash  →  load from .mcp_tools_cache.json
3. Neither match                           →  async concurrent rebuild
                                               (asyncio.gather in server.py,
                                               sequential in bridge.py)
                                              → save to both cache layers
The cache key is an MD5 hash of the raw list_toolsets response text. If Unreal’s registered toolsets change (e.g. you recompile a plugin), the hash changes and the cache is automatically invalidated and rebuilt on the next request.
Cache is stored at .mcp_tools_cache.json in the project root. Delete this file manually if you need to force a full rebuild without restarting the server.

Concurrent rebuild in server.py

server.py uses asyncio.gather to describe all toolsets in parallel, which reduces rebuild time dramatically when many toolsets are registered:
tasks = [fetch_toolset_desc(name) for name in toolset_names]
results = await asyncio.gather(*tasks, return_exceptions=True)

Sequential rebuild in bridge.py

bridge.py is a synchronous script running outside an event loop, so it describes toolsets one at a time. The disk cache means this overhead is paid only once per session.

Gemini Agent Loop

The web client’s chat tab runs an autonomous agent loop (runAgentLoop in src/js/app.js) with the following rules:
  • Maximum 20 iterations — accommodates complex multi-tool workflows (spawn actor → set material → position → verify).
  • All flattened Unreal toolsets are exposed as Gemini function declarations on every turn.
  • JSON Schema conversion — Gemini’s FunctionDeclaration format does not support several JSON Schema fields. The convertSchemaToGemini() function strips them recursively before sending:
    • additionalProperties
    • default
    • $schema
    • title
  • Toolset name normalization — Gemini function names cannot contain dots. All dots in toolset-qualified names are replaced with underscores (e.g. SceneTools.add_to_scene_from_classSceneTools_add_to_scene_from_class).
  • Final summary call — if the loop reaches 20 iterations while tool calls are still pending, a final Gemini request is made with no tools exposed, so the model can summarize results and return a coherent answer to the user.

Argument Formats (Critical)

Unreal’s Python toolsets use specific JSON object shapes for certain argument types. Passing a plain string where an object is expected silently fails or produces an invalid argument error from Unreal.

UObject / UClass References

Unreal Python tools expect a refPath wrapper object, not a bare string, for any argument that represents a UObject or UClass reference path.
- // ❌ Incorrect — plain string
- { "actor_type": "/Script/Engine.PointLight" }

+ // ✅ Correct — refPath object
+ { "actor_type": { "refPath": "/Script/Engine.PointLight" } }

ToolsetTransform

The ToolsetTransform struct uses location and scale as keys — not the Blueprint/C++ equivalents translation and scale3d.
- // ❌ Incorrect — Blueprint-style keys
- { "xform": { "translation": { "x": 0, "y": 0, "z": 300 }, "scale3d": { "x": 1, "y": 1, "z": 1 } } }

+ // ✅ Correct — Python toolset keys
+ {
+   "xform": {
+     "location": { "x": 0, "y": 0, "z": 300 },
+     "rotation": { "pitch": 0, "yaw": 0, "roll": 0 },
+     "scale":    { "x": 1, "y": 1, "z": 1 }
+   }
+ }
The Gemini agent will sometimes generate translation / scale3d because those names appear in broader Unreal documentation. Always verify against the actual describe_toolset output for the specific Python toolset you are calling.

Namespace Translation

Unreal MCP exposes toolsets with fully-qualified Python module paths such as editor_toolset.toolsets.scene.SceneTools. When a client (or the Gemini agent) calls a tool using a shortened name like EditorToolset.SceneTools, the proxy translates it at runtime. The translate_toolset_name function in both server.py and bridge.py works as follows:
  1. Exact match — if the provided name already exists in the registered toolset list, return it unchanged.
  2. Case-insensitive suffix match — compare only the last dot-segment (e.g. SceneTools) case-insensitively against all registered suffixes. Return the first match with its full canonical path.
This means you can call tools using friendly short names from the Gemini agent or from direct API calls without memorizing fully-qualified module paths.

Guide Crawler: Cloudflare Bot Management Bypass

The official Unreal Engine documentation portal (dev.epicgames.com/documentation) is a server-side-rendered Angular SPA protected by Cloudflare Bot Management. Standard HTTP clients receive 403 Forbidden even for robots.txt. The crawler in skills/dbv-unreal-python-api/scripts/scrape_ue_guides.py bypasses this by:
  1. Discovery via table_of_content.json — a single internal API call retrieves the full documentation tree (~3,600 pages across ~24 top-level sections) instead of relying on fixed seed URLs.
  2. Per-page browser context — Cloudflare degrades the trust score of a browser session after its first internal API call. Reusing the same Playwright context for multiple pages causes 403 from the second page onward. Opening a fresh browser.new_context() per article resets the trust score:
For each page:
  1. browser.new_context()   ← clean session / cookies
  2. page.goto(url)          → intercepts document.json response
  3. context.close()         ← never reused
  1. Safe parallelization via shards — each crawl process writing --category <x> writes to isolated progress and index files (index_guides__<x>.json, .progress_guides__<x>.json), avoiding race conditions. A --merge command combines all shards into the final index_guides.json.
Running more than ~6 parallel crawl processes simultaneously saturates Cloudflare’s rate limit in a sustained way. Launch parallel batches in groups of 4–6 and wait for each group to finish before starting the next.

Security and CORS

RuleDetail
Origin requirementAll requests must originate from localhost — the browser automatically sends Origin: http://localhost:5000
Proxy CORS headersserver.py injects Access-Control-Allow-Origin: * on all responses, enabling the browser SPA to read them without CORS errors
Unreal MCP origin allowlistThe Unreal MCP server only accepts requests from http://localhost or http://127.0.0.1
Local-only deploymentThe client must run locally. Serving over HTTPS or from an external origin will cause Unreal to reject all requests
Do not expose server.py on a public network interface. The proxy does not implement authentication, and Unreal MCP has no remote-access security layer.

Active Native Toolsets (UE 5.8)

The following plugins and toolsets are enabled by default in the reference project. All toolsets except AgentSkillToolset require explicit registration — see the note on toolset registration below.
PluginToolsetsTools
EditorToolset (C++)EditorAppToolset, LogsToolsetViewport, camera, selection, assets, logs
EditorToolset (Python)BlueprintTools, SceneTools, ActorTools, AssetTools, MaterialTools, + 10 more100+ Python tools
AutomationTestToolsetAutomationTestToolsetDiscoverTests, ListTests, RunTests, GetResults
SlateInspectorToolsetSlateInspectorToolsetClick, Type, Snapshot, Observe, Windows
DBVMCPFirst (custom C++)MyCustomSceneToolsetCountActorsWithMesh, GetActors, RunPython
ToolsetRegistryAgentSkillToolsetListSkills, GetSkills, CreateSkill, UpdateSkill
There is no automatic discovery by reflection. ToolsetRegistrySubsystem::Initialize() (engine, ToolsetRegistry plugin) only registers AgentSkillToolset automatically. Every other UToolsetDefinition — including any custom class like MyCustomSceneToolset — must be registered explicitly with UToolsetRegistry::RegisterToolsetClass(...) in OnPostEngineInit from the project’s primary module (<ProjectName>.cpp). Without this call the class compiles and loads correctly but never appears in list_toolsets — a silent failure easy to confuse with a plugin or compilation problem. See Step 4 of UNREAL_MCP_INTEGRATION_GUIDE.md.

Build docs developers (and LLMs) love