Skip to content

UEVR MCP Discovery Process

letmein edited this page Jun 18, 2026 · 1 revision

UEVR MCP Discovery Process — Complete Reference

Documented from live session on Outer Worlds 2 (Indiana-Win64-Shipping), June 2026. Applies to any UE4/UE5 game running under UEVR with uevr_mcp.dll loaded.


1. What UEVR MCP Is

UEVR MCP (uevr_mcp.dll) is a UEVR plugin that runs an embedded HTTP server inside the game process. It exposes a REST API for:

  • Executing Lua code in the game thread
  • Exploring live UObjects by address, class, field, and method
  • Calling Blueprint functions with arguments
  • Reading properties, arrays, and singletons

The plugin source lives at: C:\Users\xaero\.gemini\antigravity-ide\scratch\uevr-mcp-1.1.0\


2. Architecture — What Runs Where

Component Port Purpose
uevr_mcp.dll 8899 The HTTP server inside the game process — this is what you talk to
UevrMcpServer (dotnet) 54320 An MCP-over-stdio bridge for AI tool calls — NOT a general REST API

Critical: Always use port 8899 directly for REST calls. Port 54320 is the dotnet stdio bridge and cannot be called with raw HTTP.


3. Prerequisites

  1. UEVR injected into the game
  2. uevr_mcp.dll present in the game's UEVR plugins folder: %APPDATA%\UnrealVRMod\<GameName>\plugins\uevr_mcp.dll
  3. Game loaded to a playable state (not at the main menu)
  4. Verify server is running: Invoke-RestMethod -Uri "http://localhost:8899/api/status"

4. The Lua Executor — Primary Tool

Endpoint

POST http://localhost:8899/api/lua/exec
Content-Type: application/json
Body: { "code": "<lua code here>" }

PowerShell Pattern (use here-strings to avoid quote escaping hell)

$lua = @'
local pawn = uevr.api.get_local_pawn(0)
return pawn:get_full_name()
'@
$body = @{ code = $lua } | ConvertTo-Json -Compress
Invoke-RestMethod -Uri "http://localhost:8899/api/lua/exec" -Method POST -Body $body -ContentType "application/json"

Response format

{ "result": "...", "execTime_ms": 1.23, "output": {}, "success": true }

On error: { "error": "..." }

Lua sandbox notes

  • The sandbox is separate from the game's own Lua mod state
  • uevr.api is a table (not a userdata), accessed with dot notation: uevr.api.get_local_pawn(0) not uevr.api:get_local_pawn(0)
  • get_fname() returns a string directly (not an object with :to_string())
  • pairs() does NOT work on UObject userdata — use REST explorer routes instead
  • call_function(name) works for zero-parameter UE functions only

5. Key Lua API Methods

-- Get local player pawn
local pawn = uevr.api.get_local_pawn(0)

-- Find a UObject by full name (slow — scans all objects)
local obj = uevr.api.find_uobject("BlueprintGeneratedClass /Game/Path/To/Class.Class_C")
-- Returns nil if not found. Takes ~400ms for a full scan.

-- Get full name of any object
obj:get_full_name()  -- "ClassName /Full/Path.ObjectName"
obj:get_fname()      -- "ObjectName" (string directly, NOT userdata)

-- Get address as number
obj:get_address()    -- returns integer

-- Get class and walk hierarchy
local cls = obj:get_class()
while cls ~= nil do
    print(cls:get_fname())
    cls = cls:get_super()
end

-- Get objects of a class (UObjectHook)
local pawnClass = pawn:get_class()
local instances = uevr.uobject_hook.get_objects_by_class(pawnClass, false)
-- NOTE: class must be a UClass userdata from get_class(), not from find_uobject()

-- Read typed properties
local boolVal = obj:get_bool_property("SomeFlag")  -- returns bool
-- Object properties require the explorer REST route, not Lua get_property in this SDK version

-- Call zero-parameter functions
obj:call_function("SomeFunctionName")  -- no return value capture in Lua

-- List available Lua methods on any UObject
local mt = getmetatable(obj)
for k, v in pairs(mt) do print(k, type(v)) end
-- Useful methods found: get_full_name, get_address, get_fname, get_class,
--   get_bool_property, get_property_data, call_function, class_cast

6. REST Explorer Routes — The Workhorse

All routes are GET unless noted. Base: http://localhost:8899

6.1 Find live instances of a class

GET /api/explorer/objects_by_class?className=<fullClassName>
  • className = full UObject name e.g. BlueprintGeneratedClass /Game/.../Weapon_Base.Weapon_Base_C
  • Response: { "className": "...", "count": 50, "results": [ { "address": "0x...", "className": "...", "fullName": "..." } ] }

6.2 Get all fields and methods of a class (type info / CDO)

GET /api/explorer/type?typeName=<fullClassName>
  • Returns { "name": "...", "super": "...", "fields": [...], "methods": [...], "address": "0x..." }
  • fields = array of { "name": "FieldName", "type": "NameProperty" }
  • methods = array of { "name": "FuncName", "owner": "ClassName", "params": [...], "returnType": "..." }
  • The address here is the CDO (Class Default Object), NOT a live instance

6.3 Inspect a live object's properties

GET /api/explorer/summary?address=0x<address>
  • Returns { "fullName": "...", "className": "...", "fields": { "FieldName": "TypeInfo -> Value" } }
  • Field values shown as strings, e.g. "ObjectProperty -> SkeletalMeshComponent @ 0x..."
  • Very useful for navigating object graphs

6.4 Read a specific field value

GET /api/explorer/field?address=0x<address>&fieldName=<name>
  • Returns { "field": "...", "type": "ObjectProperty", "value": { "address": "0x...", ... } }

6.5 Call a zero-parameter method (getter)

GET /api/explorer/method?address=0x<address>&methodName=<name>
  • Only works if the function has no input parameters
  • Returns { "result": <value> } — vectors returned as { "x": ..., "y": ..., "z": ... }
  • Error if function has params: "Method 'X' has parameters — use invoke_function instead"

6.6 Call a method WITH parameters

POST /api/explorer/method
Body: { "address": "0x...", "methodName": "FuncName", "args": { "ParamName": value } }
  • args can be an object (keyed by param name) or an array (positional)
  • Example calling GetSocketLocation:
{
  "address": "0x1E3E1F4BBC0",
  "methodName": "GetSocketLocation",
  "args": { "InSocketName": "MuzzleFlashSocket" }
}
  • Returns { "result": { "x": ..., "y": ..., "z": ... }, "outParams": {} }

6.7 Read an array property

GET /api/explorer/array?address=0x<address>&fieldName=<name>&limit=20
  • Returns elements with their addresses and class names
  • For object arrays, elements have { "address": "0x...", "className": "...", "index": 0 }

6.8 Search all live objects by name substring

GET /api/explorer/search?query=<substring>&limit=10
  • Scans all 580k+ objects — slow but useful
  • Returns { "count": N, "results": [...], "total_scanned": 583306 }

6.9 Get player data (shortcut)

GET /api/player
  • Returns { "pawn": { "address": "0x...", "class": "..." }, "controller": { ... } }
  • Use this as the entry point instead of Lua for getting pawn address

7. Discovery Workflow — Step by Step

Step 1: Verify connection

Invoke-RestMethod -Uri "http://localhost:8899/api/status"

Step 2: Get player pawn address

$player = Invoke-RestMethod -Uri "http://localhost:8899/api/player"
$pawnAddr = $player.pawn.address   # e.g. "0x1E76ECA3340"
$pawnClass = $player.pawn.class    # e.g. "IndianaPlayerCharacter_BP_C"

Step 3: Inspect the pawn — find component references

$summary = Invoke-RestMethod -Uri "http://localhost:8899/api/explorer/summary?address=$pawnAddr"
# Filter for what you need:
$summary.fields.PSObject.Properties | Where-Object { $_.Name -match "Weapon|Equip|Inventory" } |
    ForEach-Object { "$($_.Name): $($_.Value)" }

Step 4: Navigate the object graph

  • Each ObjectProperty -> SomeClass @ 0xADDR in the summary gives you the next address to inspect
  • Follow the chain: pawn → PlayerEquipmentComponent → EquippedWeapon → GetFPVMeshComponent()

Step 5: Find the class type info

# Get all methods on a class (use URL-encoded full name)
$typeName = [System.Uri]::EscapeDataString("BlueprintGeneratedClass /Game/Blueprints/WEAP/Weapon_Base.Weapon_Base_C")
$result = Invoke-RestMethod -Uri "http://localhost:8899/api/explorer/type?typeName=$typeName"
$result.methods | ForEach-Object { $_.name }

Step 6: Find live instances of a class

$className = [System.Uri]::EscapeDataString("BlueprintGeneratedClass /Game/Blueprints/WEAP/Weapon_Base.Weapon_Base_C")
$result = Invoke-RestMethod -Uri "http://localhost:8899/api/explorer/objects_by_class?className=$className"
Write-Host "$($result.count) instances"
$result.results | Select-Object -First 5 | ForEach-Object { $_.fullName }

Step 7: Call methods on live instances

# Zero-param getter:
$r = Invoke-RestMethod -Uri "http://localhost:8899/api/explorer/method?address=0xADDR&methodName=GetShotOrigin"
$r.result  # { x, y, z }

# With params:
$body = @{ address = "0xADDR"; methodName = "GetSocketLocation"; args = @{ InSocketName = "MuzzleFlashSocket" } } | ConvertTo-Json -Compress
$r = Invoke-RestMethod -Uri "http://localhost:8899/api/explorer/method" -Method POST -Body $body -ContentType "application/json"

Step 8: Read array elements (e.g. skeleton sockets)

# Get the sockets array from a Skeleton asset
$r = Invoke-RestMethod -Uri "http://localhost:8899/api/explorer/array?address=0xSKELADDR&fieldName=Sockets&limit=20"
foreach ($socket in $r.elements) {
    $s = Invoke-RestMethod -Uri "http://localhost:8899/api/explorer/summary?address=$($socket.address)"
    $name = $s.fields.PSObject.Properties | Where-Object { $_.Name -eq "SocketName" }
    Write-Host "$($socket.address): $($name.Value)"
}

8. Outer Worlds 2 — Specific Discovery Results

Object navigation path to player weapon

/api/player → pawn.address (IndianaPlayerCharacter_BP_C)
  → summary → PlayerEquipmentComponent (ObjectProperty → PlayerEquipmentComponent @ 0x...)
    → summary → EquippedWeapon (ObjectProperty → Weapon_PI_Standard_Unique_C @ 0x...)
      → method GET GetFPVMeshComponent → SkeletalMeshComponent @ 0x...
        → summary → SkeletalMesh (ObjectProperty → SkeletalMesh @ 0x...)
          → summary → Skeleton (ObjectProperty → Skeleton @ 0x...)
            → array Sockets → [ SkeletalMeshSocket objects ]
              → summary each socket → SocketName, BoneName

Key class paths

Object Full UObject Name
Weapon base class BlueprintGeneratedClass /Game/Blueprints/WEAP/Weapon_Base.Weapon_Base_C
FireMode base BlueprintGeneratedClass /Game/Blueprints/WEAP/WeaponModes/FireMode_Base.FireMode_Base_C
Player character IndianaPlayerCharacter_BP_C

FireMode functions of interest (returned by /api/explorer/type)

Function Owner Params Returns
GetShotOrigin RangedMode none StructProperty (FVector)
GetAimingDirection RangedMode bIsForShotSpawnTransform (bool) StructProperty
GetMuzzleLocation RangedMode multiple StructProperty
GetShootSocketName RangedMode mesh component NameProperty
GetLastShotEndLocation FireMode none StructProperty

Weapon socket names (from Skeleton Sockets array on w_ED_LightPistol / AC_AutoPistol skeleton)

Socket Name Bone Purpose
MuzzleFlashSocket barrel_JNT Primary muzzle — use this for trace fix
MuzzleFLashSocketSilencer barrel_JNT Silencer variant (note: game typo in name)
Barrel_Socket h_weapon Weapon barrel attach point
VFX_CasingEject h_weapon Shell eject VFX
PickupSocket h_weapon Pickup interaction
Mod_Socket h_weapon Weapon mod attachment
Magazine_Socket Magazine_JNT Magazine mesh

Equipment component attach socket

WeaponAttachSocket = "WeaponPoint" — socket on the player arm mesh where the weapon attaches


9. Common Gotchas

Problem Cause Fix
find_uobject returns nil Wrong name format Must include full path: "BlueprintGeneratedClass /Game/..."
get_objects_by_class errors Passing UObject* not UClass* Use pawn:get_class() result, not find_uobject() result
get_fname():to_string() errors get_fname() already returns a string Just use obj:get_fname() directly
/api/lua/exec errors with escaping PowerShell quote escaping Use PowerShell here-strings @' ... '@
uevr.api:method() nil error Wrong colon vs dot Use uevr.api.method() (dot), not colon
call_function with params crashes call_function only handles zero-param Use POST /api/explorer/method with args
400ms find_uobject calls Full object table scan Cache results; call once not per-frame
Sockets array empty on SkeletalMesh Sockets live on Skeleton asset Navigate to SkeletalMesh → Skeleton → Sockets
pairs() on UObject fails sol container restriction Use REST explorer routes to enumerate

10. All Available REST Routes (from source)

GET  /api/status
GET  /api/game_info
GET  /api/player
GET  /api/camera
GET  /api/vr/status
GET  /api/vr/poses
GET  /api/vr/settings
POST /api/vr/settings
POST /api/vr/recenter
POST /api/vr/config/save
POST /api/vr/config/reload
GET  /api/lua/state
POST /api/lua/exec          ← primary tool
POST /api/lua/reset
GET  /api/console/cvars
GET  /api/explorer/search
GET  /api/explorer/classes
GET  /api/explorer/type
GET  /api/explorer/object
GET  /api/explorer/summary
GET  /api/explorer/field
GET  /api/explorer/method
GET  /api/explorer/objects_by_class
POST /api/explorer/field
POST /api/explorer/method   ← for functions with params
POST /api/explorer/chain
GET  /api/explorer/singletons
GET  /api/explorer/singleton
GET  /api/explorer/array
GET  /api/explorer/memory
GET  /api/explorer/typed
POST /api/explorer/batch
GET  /api/discovery/subclasses
GET  /api/discovery/names
GET  /api/discovery/delegates
GET  /api/discovery/vtable
POST /api/discovery/pattern_scan
GET  /api/discovery/all_children
POST /api/hook/add
GET  /api/hook/list
GET  /api/hook/log
POST /api/hook/clear
GET  /api/animation/state
POST /api/animation/play_montage
POST /api/animation/stop_montage
POST /api/animation/set_variable
GET  /api/animation/montages

Clone this wiki locally