MCP server wrapping the fmodel-cli .NET binary for Unreal Engine asset access
fmodel-mcp has 10 tools with clear verb-noun naming (fmodel_search, fmodel_read, fmodel_export_*). Descriptions are present and substantive (avg ~180 chars), explaining WHAT each tool does and WHEN to use it. However, input schemas lack type constraints: all parameters are bare strings with no enums, min/max bounds, or format specifications. Output schemas are completely undocumented, callers cannot predict the structure of returned JSON. Error handling is minimal: _run() returns {ok: false, error: ...} but provides no recovery guidance or categorization (retryable vs fatal). No tool annotations (readOnlyHint/destructiveHint) despite clear risk distinctions (5 READ_ONLY vs 5 WRITE tools). Parameter descriptions are adequate but lack format/constraint details (e.g., 'pattern' in fmodel_search should document glob syntax more formally). No pagination support despite tools like fmodel_search accepting a 'limit' parameter, no mention of total count or next_cursor.
Export an AnimSequence / AnimMontage as a .ueanim (UEFormat) under Output/Exports/. UEFormat carries translation+rotation+SCALE per bone. ActorX (.psa) drops the per-bone scale tracks (the Blender PSA importer logs "Unrecognized section SCALEKEYS"), which tears characters that animate bone-scale (e.g. the giant Paintress). Import the .ueanim with the UEFormat Blender addon. Mesh + skeleton come from fmodel_export_mesh; this is the animation counterpart.
Export a SkeletalMesh / StaticMesh as PSK/PSKX under Output/Exports/.
Export a SkeletalMesh / StaticMesh as a .uemodel (UEFormat) under Output/Exports/. UEFormat counterpart of fmodel_export_mesh (which writes ActorX .psk). Use this when you need the mesh bind pose to match a .ueanim exported via fmodel_export_anim: importing both with the UEFormat Blender addon guarantees a consistent reference skeleton (the PSK->FBX path can drift). Import via the addon's logic call (the bpy.ops.uf.import_uemodel operator silently no-ops in headless/MCP context; call io_scene_ueformat.importer.logic.UEFormatImport( UEModelOptions(...)).import_file(path) directly).
Dump the full FModel-style JSON for the package (all UObjects, all properties) to Output/Exports/ as a .json file. Use for blueprints, skeletal mesh metadata, anything where the summarized inspect is too thin.
No input schema constraints: all parameters are bare strings with no enums, min/max, regex patterns, or format specs. 'pattern' in fmodel_search should declare glob syntax formally; 'limit' should specify range (1 - 200); 'path' should document expected format (e.g., 'Game/Content/...'). LLMs cannot validate inputs without constraints.
Output schemas completely undocumented. Tools return JSON dicts but callers cannot predict field names, types, or structure. E.g., fmodel_search returns results but no schema shows whether it's {results: [...], total: N} or {packages: [...]} or {ok: true, data: {...}}. LLMs cannot plan downstream calls without knowing output shape.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | F | 47 | 2026-07-28+ | v2 |
Decode a UTexture2D to PNG under Output/Exports/, mirroring the package path. Returns the on-disk path and dimensions.
Summarized view of a material / material instance: parent, blend mode, two-sided, opacity clip, plus the Texture/Scalar/Vector parameter values. Use this instead of `fmodel_read` when you only care about which textures a material wires up and the tweak knobs above it.
List files already on disk under Output/Exports/ matching an optional prefix (e.g. `Game/Content/Characters/Enemies/MyEnemy`).
Return all UObjects in the package as their full JSON form (the same shape FModel writes when you 'Save Properties (.json)').
Find packages by glob or substring. Pattern is a glob over package paths (e.g. `**/MI_Curator*`, `Game/Content/Characters/**/MyCharacter/**/*`). `*` matches a single path component, `**` matches any number of components.
Sanity check the provider: pak directory, mappings loaded, total files indexed.
No tool annotations despite clear risk distinctions. 5 tools are READ_ONLY (fmodel_status, fmodel_search, fmodel_read, fmodel_inspect_material, fmodel_list_exports); 5 are WRITE (fmodel_export_*). Missing readOnlyHint and destructiveHint annotations prevent agents from reasoning about side effects and retry safety.
Error handling provides no recovery guidance. _run() returns {ok: false, error: '...'} but does not categorize errors as retryable, user-fixable, or fatal. No suggestions for next steps (e.g., 'Package not found. Try fmodel_search() to find available packages.'). Agents cannot self-correct.
fmodel_search accepts 'limit' parameter but no pagination support documented. No mention of total count, next_cursor, or offset. If results exceed limit, agent cannot fetch remaining items. Violates paginated-result pattern.