Skip to main content

MCP server for Unreal Editor for Fortnite (UEFN) — lets Claude / Cursor drive UEFN via Python

Project description

uefn-mcp

MCP server for Unreal Editor for Fortnite — let Claude / Cursor drive UEFN through Python, the same way rbxstudio-mcp drives Roblox Studio.

Now at v1.6 — Verse digest tooling + a human-in-the-loop coordination primitive. The LLM can now (a) ask "what devices exist in Fortnite?" and get a parsed answer from Fortnite.digest.verse without dumping 50K lines into context, and (b) block on wait_for_events(...) until the user does something — press Ctrl+Shift+B to build, click an actor in the viewport — instead of asking and re-asking. Transport is HTTP long-poll, not literal WebSockets (UEFN's embedded Python is painful to pip-install into; the UX is identical for the events that actually fire). 47 tools total (was 43). See §v1.6 highlights below.

Honest receipt on wait_for_events: today the events that fire are log.error / log.warning (mostly echoes of the LLM's own execute_python errors), verse.file_written (circular — the LLM emits it itself), and the two genuinely useful ones: verse.build (user pressed Ctrl+Shift+B) and selection.changed (user clicked an actor). There are no gameplay hooks wired in — no player.spawned or device.triggered from PIE — and the MCP tool surface can't start a play session anyway. Treat this as "wait for the human at the keyboard to do X", not as autonomous reactivity.

v1.5 (previous) — audit fixup release. v1.4 shipped MVVM notes that contained a handful of errors (phantom set_*_conversion_function methods, wrong type on override_execution_mode, an undercount of MVVMBlueprintView properties, two fabricated quotes). v1.5 rewrites MVVM_API_NOTES.md from the actual Python 5.7 docs, fixes a real runtime bug where the conversion-function parameter on add_view_binding silently no-op'd, and acknowledges that the entire conversion-function surface is Read-Only in 5.7 Python (set it in the editor UI). See §v1.5 audit fixup below.


Architecture

┌──────────────┐   stdio MCP    ┌──────────────┐   HTTP   ┌────────────────────┐
│ Claude/Cursor│ ◄────────────► │  uefn-mcp    │ ◄──────► │ UEFN listener      │
│              │                │ (this server)│  :8766   │ (embedded Python)  │
└──────────────┘                └──────────────┘          └────────────────────┘
                                                                   │
                                                                   ▼
                                                           unreal.* on game thread
  • The MCP server runs outside UEFN (talks stdio to your IDE).
  • The listener lives inside UEFN's embedded Python 3.11 interpreter and serves an HTTP API on 127.0.0.1:8766. Every command is parked on a queue and executed on the game thread via register_slate_post_tick_callback — because all unreal.* calls have to happen there.
  • Mutating tools wrap their snippet in unreal.ScopedEditorTransaction so each tool call is a single Ctrl+Z step.

Install

1. Install the UEFN plugin

Copy the two files in uefn_plugin/ into your UEFN project:

[YourUEFNProject]/Content/Python/init_unreal.py
[YourUEFNProject]/Content/Python/uefn_listener.py

If the Python/ folder doesn't exist, create it. UEFN's embedded interpreter auto-runs init_unreal.py on project open.

Make sure UEFN's Python plugin is enabled (Edit ▸ Plugins ▸ search "Python"). For MVVM tools you also need the Model View Viewmodel plugin enabled (Edit ▸ Plugins ▸ search "MVVM").

Open your project. You should see in the Output Log:

[uefn-mcp] ✅ Listener started on http://127.0.0.1:8766

Sanity check from a terminal:

curl http://127.0.0.1:8766/health
# {"ok": true, "service": "uefn-mcp-listener", "queue_depth": 0, ...}

2. Install the MCP server

From inside this repo:

pip install -e .
# or, if you're a uv person:
uv pip install -e .

That gives you a uefn-mcp console script.

3. Wire it into your IDE

Claude Desktop~/Library/Application Support/Claude/claude_desktop_config.json (mac) or %APPDATA%\Claude\claude_desktop_config.json (windows):

{
  "mcpServers": {
    "uefn": {
      "command": "uefn-mcp"
    }
  }
}

Cursor — Settings ▸ MCP ▸ Add new MCP Server:

{
  "uefn": { "command": "uefn-mcp" }
}

Restart your IDE. You should see uefn show up as a connected MCP server.


Project layout (v1.5)

src/uefn_mcp/
├── server.py        ~70 lines: entry point — imports tools/ and runs FastMCP
├── _bridge.py       HTTP transport + transaction wrapper + shared mcp instance
├── _snippets.py     reusable Python text snippets (ACTOR/MVVM/FRAME/VERSE/WIDGET)
└── tools/
    ├── system.py        ping, execute_python, get_output_log
    ├── actors.py        query, property access, mutation
    ├── navigation.py    select_actors, focus_viewport_on
    ├── discovery.py     class distribution, tags, device catalog
    ├── level.py         level info / save / undo / redo
    ├── verse.py         list / read / write / restore Verse files
    ├── assets.py        list_assets
    ├── screenshots.py   viewport / actor screenshots
    ├── widgets.py       WBP create / duplicate / compile / inspect
    └── mvvm.py          view bindings, viewmodel contexts, conversions

MVVM_API_NOTES.md documents the verified Read-Only / Read-Write surface map per UE Python 5.7 docs — read it before touching tools/mvvm.py or _snippets.MVVM_HELPERS.


Tools (v1.6 — 47 total)

System

Tool What it does
ping Health check on the listener
execute_python Run arbitrary Python on the game thread
get_output_log Read recent UEFN log messages

Actor — query

Tool What it does
get_all_actors List actors in the level (summary view, paginated)
get_selected_actors Actors selected in the viewport
get_actor_details One actor with summary/detailed/full verbosity
find_actors Filter by name regex, class, or tag
get_actor_components List components on an actor
get_actor_property Read any editor property (supports nested paths)
get_class_distribution Count actors per class
get_all_tags List every tag in use across the level
get_device_catalog List runtime UE class names (e.g. TriggerDevice_C) — for spawning into the level via Python. Distinct from v1.6's list_verse_devices, which returns Verse-language names for writing .verse code

Actor — mutate (transaction-wrapped)

Tool What it does
set_actor_property Write an editor property (with type coercion)
spawn_actor Spawn an actor from an asset path
delete_actor Delete an actor by label
set_actor_transform Move/rotate/scale an actor
select_actors Select a list of actors
focus_viewport_on Frame the viewport on an actor (F-key equivalent)

Level

Tool What it does
get_level_info World name + actor count
save_current_level Save the open level
undo Undo N steps
redo Redo N steps

Verse

Tool What it does
list_verse_modules List .verse files (scans VerseDevices, Verse, plugin Verse)
read_verse_file Read a Verse file
write_verse_file Write a Verse file (auto-snapshots prior content)
list_verse_snapshots List recent snapshots of a Verse file
restore_verse_file Restore from a snapshot (still hit Ctrl+Shift+B to build)

Assets

Tool What it does
list_assets List asset paths under a directory

Screenshots

Tool What it does
screenshot_viewport Take a viewport screenshot (returns inline MCP image — Claude can SEE it)
screenshot_actor Frame an actor first, then screenshot it

UMG / Widget Blueprint

Tool What it does
create_widget_blueprint Create a new WBP at a path
duplicate_widget_blueprint Duplicate a WBP
compile_widget_blueprint Compile + save a WBP
inspect_widget Read class, slots, viewmodels, bindings count
get_widget_tree 🆕 Read-only widget hierarchy (5.7 Python doesn't expose authoring; design in the UMG Designer)

MVVM (v1.5 — re-verified against UE Python 5.7 docs)

Tool What it does
inspect_viewmodel List a ViewModel's bindable fields and types
list_view_bindings Existing MVVM bindings on a WBP
list_available_conversions 🆕 Conversion functions valid for a specific source→dest pair
add_viewmodel_context Add a viewmodel context to a WBP
add_view_binding Bind viewmodel field → widget property (with optional conversion + mode)
remove_view_binding Remove a binding by index
remove_viewmodel_context Remove a viewmodel context

Verse digests (v1.6 — new)

The Verse *.digest.verse files are the canonical API surface for Fortnite devices, UnrealEngine types, and core Verse types. These tools parse them server-side so the LLM gets targeted answers instead of 50K-line file dumps.

Tool What it does
list_verse_digests 🆕 Find every *.digest.verse file in the project (Fortnite, UnrealEngine, Verse, …)
list_verse_devices 🆕 Top-level classes from a digest, optional name-substring filter
get_verse_device_api 🆕 Full parsed API of one class — header, methods, events, fields
search_verse_digest 🆕 Regex grep across digests — find anything by line

Typical workflow: "Create a system that uses a trigger and a prop_mover"list_verse_devices(filter_substring="trigger")get_verse_device_api("trigger_device")get_verse_device_api("prop_mover_device") → draft Verse → write_verse_file.

Reactive events — wait_for_events (v1.6 — new)

The listener gained an event buffer + HTTP long-poll endpoint. The LLM can block on wait_for_events instead of asking the user "did the build finish yet?" in a loop.

Tool What it does
wait_for_events 🆕 Block up to 60s until matching events arrive. timeout_s=0 peeks the buffer without blocking (max_count caps the slice).

Single tool, two modes — peek (timeout 0) was previously a separate get_recent_events; that was just wait_for_events(timeout_s=0) under the hood, so it folded in.

Built-in event kinds: log.error, log.warning, verse.build (heuristic), selection.changed, verse.file_written. Custom kinds can be emitted from any snippet via the pre-injected push_event(kind, data) callable (e.g. execute_python("push_event('build.done', {'ok': True})")). The listener also exposes raw POST /events/push for external clients.

Realistic use cases (be honest about what fires):

# 1. You wrote a Verse file, ask the user to build, wait for the result
write_verse_file("MyDevice.verse", code)
# tell the user: "Press Ctrl+Shift+B"
out = wait_for_events(kinds=["verse.build"], timeout_s=60)
if out["events"]:
    status = out["events"][0]["data"]["status"]   # "ok" or "fail"

# 2. Coordinate with the user via viewport selection
# tell the user: "Click the wall you want me to align to"
out = wait_for_events(kinds=["selection.changed"], timeout_s=120)

What it's not good for: autonomous LLM-only reactivity. log.error and log.warning mostly echo what execute_python already returns synchronously. There are no game-event hooks (no player.spawned, no device.triggered), and the MCP surface can't start a play session anyway. If gameplay hooks ever land, the primitive is ready for them.

Why long-poll instead of WebSockets? UEFN's embedded Python is painful to pip-install into, and stdlib has no WS support. Long-poll gives the same "wake immediately when events arrive" UX with zero new deps. The bridge's HTTP timeout for these calls is server_timeout + 10s (default 35s total).

execute_python is the escape hatch — anything not exposed as a tool can still be done with raw Python. Pre-injected names: unreal, actor_sub, asset_sub, level_sub, editor_sub, mvvm_sub, push_event, result. Assign to result to return a value. (mvvm_sub is None if the MVVM plugin isn't enabled.)

Example prompt: "Spawn a cube at (100, 0, 50), name it Hello, screenshot it, then read it back."


A note on MVVM

UEFN's Python surface for MVVM (MVVMEditorSubsystem, MVVMBlueprintView, MVVMBlueprintPropertyPath) varies a bit between UE 5.5 / 5.6 / 5.7. The v1.5 implementation has been re-verified against the canonical UE Python 5.7 docs after a second-pass audit caught errors in the v1.4 notes (see MVVM_API_NOTES.md §9 "Audit fixup" for the full diff).

Verified facts baked into the code:

  • unreal.get_editor_subsystem(unreal.MVVMEditorSubsystem) is the right accessor (the runtime MVVMSubsystem CDO has none of the editor verbs).
  • MVVMBlueprintView.bindings and available_view_models are Read-Write arrays — accessed via view.get_editor_property(...). (The full property set is 5: also compiled_binding_library_id, conditions, events.)
  • MVVMBindingMode enum: ONE_TIME_TO_DESTINATION=0, ONE_WAY_TO_DESTINATION=1, TWO_WAY=2, ONE_WAY_TO_SOURCE=4 — note the gap at value 3.
  • MVVMEditorSubsystem.remove_view_model takes Name, not Guid.
  • MVVMBlueprintViewBinding.override_execution_mode is an MVVMExecutionMode enum (not bool).
  • ⚠️ ALL MVVMBlueprintPropertyPath properties are Read-Only per docs, and there are no documented set_widget_name / set_view_model_id / set_property_path UFUNCTIONs. The path setters in _snippets.MVVM_HELPERS use a multi-strategy fallback (typed UFUNCTION → set_editor_property → direct paths array writes via MVVMBlueprintFieldPath) and stamp the source enum (WIDGET / VIEW_MODEL) for editor-UI sync.
  • 🚧 The conversion-function surface is fully Read-Only in 5.7 Python: MVVMBlueprintViewBinding.conversion, both directions on MVVMBlueprintViewConversionPath, and all 6 fields on MVVMBlueprintViewConversionFunction. There are no documented set_*_conversion_function methods on MVVMEditorSubsystem (v1.4 claimed there were — they're phantom). v1.5 attempts a best-effort in-place mutation when add_view_binding is called with conversion_function, but it returns a clear note when the engine refuses, in which case set the conversion in the editor UI (Widget Designer → ViewModels panel → click the binding → choose conversion).

If a binding tool fails, the fast diagnostic is one execute_python call — e.g. execute_python("result = sorted(dir(unreal.MVVMEditorSubsystem))") — to see exactly which methods exist on MVVMEditorSubsystem / MVVMBlueprintView / MVVMBlueprintPropertyPath / MVVMBlueprintViewBinding in your specific install. (v1.4–v1.5 shipped a dedicated probe_mvvm_api tool for this; v1.6 dropped it — the bundled dir() walk is one line via execute_python, and MVVM_API_NOTES.md is the documented baseline.)

The widget tree itself stays in your hands. There is no UEFN-specific "lock" — what's actually happening is lock by omission in UE 5.7's Python bindings:

  • WidgetTree (5.7 docs page): stub. Bases: Object, zero methods, zero properties. No construct_widget, no root_widget.
  • BaseWidgetBlueprint / UserWidgetBlueprint / WidgetBlueprint: all stubs. Only blueprint metadata (compile_mode, blueprint_category, etc.). No widget_tree editor property accessor anywhere in the chain.
  • C++ UWidgetTree::ConstructWidget<T> is a templated method, which Unreal's reflection system doesn't bind to Python (UnrealHeaderTool can't UFUNCTION- expose templates).
  • WidgetLibrary / WidgetLayoutLibrary / UserWidgetFunctionLibrary / WidgetReferenceBlueprintFunctionLibrary / WidgetAnimationHandleFunctionLibrary: all runtime-mutation helpers. Zero authoring methods across all five.
  • PanelWidget.add_child() / clear_children() / remove_child() etc. are exposed — but only for runtime mutation of already-instantiated widgets at play time. They don't help author the persisted WBP at editor time.

This matches Epic's design intent: author UMG in the Designer → attach bindings/conditions/events via MVVMEditorSubsystem Python verbs → consume at runtime from Verse. Editor-time UMG hierarchy authoring routes through the Designer; runtime widget creation in cooked builds routes through Verse, not Python. (Conversion functions are also Designer-set, see above.)

This MCP automates everything around the widget tree — viewmodels, bindings, compilation, save, screenshots, MVVM conversions where the engine permits.

Per Epic's official UEFN docs, MCP is a sanctioned use case:

"Remote execution of well made scripts or tools, such as a MCP integration with an Agentic AI" — Python Tools in UEFN, dev.epicgames.com (line 18 of the scrape)


v1.5 audit fixup

A second-pass audit against the firecrawl scrape of dev.epicgames.com/python-api caught the following errors in v1.4. v1.5 fixes them all:

Issue (v1.4) Fix (v1.5)
tools/mvvm.py called phantom sub.set_source_to_destination_conversion_function() Removed phantom calls; replaced with best-effort in-place mutation on binding.conversion
MVVM_API_NOTES.md claimed MVVMEditorSubsystem has ~9 methods Documented all 21 (added add_condition, add_event, rename_view_model, reparent_view_model, etc.)
MVVMBlueprintView listed as 2 properties Now lists all 5 (compiled_binding_library_id, conditions, events were missing)
override_execution_mode typed as bool Corrected to MVVMExecutionMode enum
Restrictions section quoted uefn-vs-ue-in-unreal-editor-for-fortnite.md Quote doesn't exist in source — section now only cites python-tools-in-uefn.md with line nums
MVVMBindingMode listed without flagging the value-3 gap Now explicitly noted: values are [0, 1, 2, 4]

No new tools added — the audit's "missing methods" list (add_condition, add_event, rename_view_model, get_child_view_models, etc.) was deliberately left out of the tool surface to avoid count inflation. Use execute_python with the pre-injected mvvm_sub to call them directly.


v1.6 highlights

Two big features. Both shipped together because they're complementary — digest tooling tells the LLM what to build, reactive events tell it when something happened.

1. Verse digest tooling — 4 new tools (tools/verse_digest.py)

The problem v1.5 left open: the LLM's "what devices exist?" mental model. Without digest awareness, the LLM falls back to its training data, which is stale and incomplete for UEFN Verse. With it, you get:

list_verse_devices(filter_substring="trigger")
  → [{"name": "trigger_device", ...}, {"name": "billboard_trigger_device", ...}]

get_verse_device_api("trigger_device")
  → {
      "header": "trigger_device := class<concrete>(creative_device_base):",
      "members": [
        {"kind": "event",  "name": "Triggered", "signature": "..."},
        {"kind": "method", "name": "Trigger",   "signature": "..."},
        {"kind": "method", "name": "Reset",     "signature": "..."},
        ...
      ]
    }

Parsing happens server-side in the listener — the bridge never receives the 50K-line digest, only the targeted slice. search_verse_digest adds a regex grep across all digests in case the structured tools miss something.

The fix to _verse_search_roots is small but important: digest files live at Plugins/<X>/Content/<X>.digest.verse, NOT in Plugins/<X>/Content/Verse/. Pre-v1.6 list_verse_modules missed them entirely.

2. Human-in-the-loop coordination — wait_for_events (1 new tool)

The roadmap entry said "WebSocket transport for reactive workflows". The ship reality: HTTP long-poll with the same UX. The transport tradeoff:

Aspect True WebSockets HTTP long-poll (shipped)
Wake latency < 10 ms < 10 ms (cond var notify)
Listener deps Needs websockets lib in UEFN Python Stdlib only
Code size ~400 LoC (server + client + framing) ~150 LoC
Persistent connection Yes No (one connection per wait call)
LLM-facing API Identical Identical

UEFN's embedded Python is painful to pip-install into. Until that changes, long-poll is the right call. The True WebSocket transport roadmap entry is still there if/when a use case actually needs the persistent connection (e.g. a separate web dashboard mirroring editor state in real time).

What this tool actually is (post-audit, fixed up from the v1.6 launch narrative): a human-in-the-loop coordination primitive, not autonomous reactivity. The events that fire today are mostly user-driven (verse.build on Ctrl+Shift+B, selection.changed on click) or self-echoing (log.error / log.warning from the LLM's own execute_python errors, verse.file_written from its own writes). There are no gameplay-event hooks; the MCP tool surface can't start a play session anyway. So the realistic value is "block until the user does the thing", not "react to the game".

get_recent_events was originally shipped as a separate peek tool; it was literally wait_for_events(timeout_s=0) under the hood. Folded back in. Set timeout_s=0 to peek; max_count caps the slice (default 100, server buffer holds 500).

What you can do today:

# Wait for the user to press Ctrl+Shift+B after you wrote Verse code
out = wait_for_events(kinds=["verse.build"], timeout_s=60)
if out["events"]:
    status = out["events"][0]["data"]["status"]   # "ok" or "fail"

# Coordinate with the user via viewport selection
out = wait_for_events(kinds=["selection.changed"], timeout_s=120)

# Peek for recent errors without blocking
out = wait_for_events(kinds=["log.error"], timeout_s=0, max_count=20)

# Cursor across multiple polls
out = wait_for_events(since_id=out["last_id"], timeout_s=25)

Built-in event sources:

  • log.error / log.warning — anything passed to unreal.log_error/_warning
  • verse.build — heuristic: matches "Verse compilation succeeded" / "...failed" patterns in LogVerse. Tweak _maybe_emit_verse_build_event in uefn_listener.py if your UEFN version uses different strings.
  • selection.changed — actor selection in viewport (polled in the tick callback because UEFN doesn't expose a Python selection delegate)
  • verse.file_written — emitted by write_verse_file after a successful write

Custom kinds: any tool can call push_event(kind, data) (pre-injected) to emit its own events.


Limitations

  • Verse builds are manual. UEFN doesn't expose a programmatic build trigger. After write_verse_file, you (or the user) hit Ctrl+Shift+B in UEFN. Mitigated in v1.6: wait_for_events(kinds=["verse.build"]) blocks until the build finishes so the LLM can react without spin-polling.
  • Game thread only (for unreal.* calls). Long-running snippets block the editor for up to 30s (the listener timeout). The new /events/wait endpoint runs in the HTTP worker thread, not the game thread — long-polling for events does not block the editor.
  • verse.build event detection is heuristic. The listener pattern-matches "Verse compilation succeeded/failed" strings out of LogVerse. If a future UEFN version changes the wording, _maybe_emit_verse_build_event in uefn_listener.py needs a one-line tweak. (Polling LogVerse text is the only path; UEFN doesn't expose a build delegate to Python.)
  • Local only. Listener binds to 127.0.0.1. No auth — don't expose port 8766.
  • Widget-tree authoring is not exposed in 5.7 Python (lock-by-omission, not a UEFN-specific policy). Design the visual layout in the UMG Designer. Bindings/conditions/events around the tree are scriptable. See "A note on MVVM" above for the full receipts.
  • MVVM plugin required for the MVVM tool family. The listener still starts fine without it; just mvvm_sub will be None and the MVVM tools will tell you to enable the plugin.

Documentation provenance

Two pools of source material drive the implementation, kept out of this repo (in a sibling chat workspace) but referenced when building each version:

  • Verse API docs (Fortnite.com, UnrealEngine.com, Verse.org modules, scraped from dev.epicgames.com) — drive the Verse tool family (list_verse_modules, read_verse_file, etc.) and inform device-catalog / Verse-template work on the roadmap.
  • UE Python 5.7 API docs (unreal.MVVMEditorSubsystem, unreal.MVVMBlueprintView, unreal.MVVMBlueprintPropertyPath, unreal.MVVMBlueprintViewBinding, unreal.MVVMBlueprintViewConversionPath, unreal.MVVMBlueprintViewConversionFunction, unreal.MVVMBlueprintFieldPath, unreal.MVVMBindingMode, unreal.MVVMExecutionMode, unreal.MVVMBlueprintFieldPathSource, unreal.MVVMBlueprintViewModelContextCreationType, plus the Python Tools in UEFN guide that explicitly endorses MCP) — drive the v1.5 MVVM verification. The full Read-Only / Read-Write surface map plus enum values is captured in MVVM_API_NOTES.md (re-verified line-by-line in v1.5 after a second-pass audit).

If a binding tool ever fails on a UEFN install whose MVVM plugin diverges from those docs, the diagnostic is one execute_python call — e.g. execute_python("result = sorted(dir(unreal.MVVMEditorSubsystem))") — to dump the actual API surface in your install for diff'ing against the notes. (v1.4–v1.5 wrapped this in a probe_mvvm_api tool; v1.6 dropped the wrapper because it was a packaged dir() walk competing with execute_python for the LLM's routing slot.)


Roadmap

See UEFN_MCP_BUILD_PLAN.md for the full vision. Short list:

  • ScopedEditorTransaction undo wrapping
  • Device catalog scan
  • Screenshots (viewport + framed actor)
  • MVVM tool family (v1.3 actually works)
  • Modular refactor — split the 2k-line server.py into focused modules (v1.4)
  • MVVM verification against canonical UE Python 5.7 docs (v1.4)
  • MVVM audit fixup — corrected docs + fixed phantom-method bug in conversion path (v1.5)
  • Visual widget authoring — investigated, closed: not feasible at design time in 5.7 Python. BaseWidgetBlueprint, UserWidgetBlueprint, WidgetBlueprint, WidgetTree, UserWidgetExtension all docs-stubbed by Epic (only metadata exposed, no widget_tree accessor, no construct_widget). PanelWidget.add_child() etc. are exposed but runtime-only — once instantiated. UMG hierarchy authoring routes through the Designer; runtime widget creation in cooked builds routes through Verse. See "A note on MVVM" §widget-tree below.
  • Verse digest tooling (v1.6)list_verse_digests / list_verse_devices / get_verse_device_api / search_verse_digest. The LLM can now answer "what devices exist?" / "what's the API of trigger_device?" without dumping 50K-line digests into context.
  • HITL coordination primitive (v1.6)wait_for_events blocks up to 60s for editor events (verse.build on Ctrl+Shift+B, selection.changed on click, plus log.error / log.warning / verse.file_written for completeness). Transport is HTTP long-poll, not WebSockets — UEFN's embedded Python has no stdlib WS support; long-poll gives identical UX. Honest framing: the events that fire today are user-driven or self-echoing, not gameplay-reactive (no PIE hooks shipped).
  • Semantic actor/asset search — embed-based "find the boss spawner" lookup that beats regex-on-name (find_actors today is literal-pattern only)
  • World-state JSON export (Toolbelt-style)
  • Verse templates / scaffolding (next logical step after digest tooling — pre-canned device wirings)
  • MCP resources & prompts (not just tools)
  • uvx uefn-mcp distribution via PyPI
  • True WebSocket transport (rather than long-poll) — would require either a vendored websockets lib in the listener or a hand-rolled stdlib WS implementation (~250 LoC for handshake + framing). Punted because long-poll already delivers the reactive UX; revisit if/when a use case actually needs persistent push (e.g. mirroring editor state to a web dashboard).

Credits

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

uefn_mcp-0.1.6.tar.gz (67.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

uefn_mcp-0.1.6-py3-none-any.whl (55.4 kB view details)

Uploaded Python 3

File details

Details for the file uefn_mcp-0.1.6.tar.gz.

File metadata

  • Download URL: uefn_mcp-0.1.6.tar.gz
  • Upload date:
  • Size: 67.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for uefn_mcp-0.1.6.tar.gz
Algorithm Hash digest
SHA256 dfb0357ff5bdfc64eb6628cfba6698cf06de7b9012ae2725e4d88cfd1b5acd0b
MD5 df2a86210da064721e4ada3b8341b7a4
BLAKE2b-256 160f7a6a21c7e39d9d41fecaa38a9662506adf5c41c98a61cb6fd7c3ee7e0efb

See more details on using hashes here.

Provenance

The following attestation bundles were made for uefn_mcp-0.1.6.tar.gz:

Publisher: publish.yml on missatjuhvdk1/uefn-mcp

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file uefn_mcp-0.1.6-py3-none-any.whl.

File metadata

  • Download URL: uefn_mcp-0.1.6-py3-none-any.whl
  • Upload date:
  • Size: 55.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for uefn_mcp-0.1.6-py3-none-any.whl
Algorithm Hash digest
SHA256 771ea828e7746eab4a3d12ee67ab96935098d4807d0e848237ce89e1bdb7d099
MD5 2f7a9bbc5b34890e746f232b8ed24f9e
BLAKE2b-256 a12ead9fed95552e8e895dca7d607422ff42336179a7ef5d23df0cee1a3fdf12

See more details on using hashes here.

Provenance

The following attestation bundles were made for uefn_mcp-0.1.6-py3-none-any.whl:

Publisher: publish.yml on missatjuhvdk1/uefn-mcp

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page