L2 Modding MCP
# L2 Modding MCP
MCP Server for **Lineage 2 / Unreal Engine 2.5** asset modding — 25 tools. Extract, modify, repackage textures (.utx), generate procedural meshes (.usx), parse animations (.ukx), sounds (.uax), and maps (.unr).
## Features
### Textures
- Extract/inspect/import textures from `.utx` packages
- Codec: DXT1/DXT3/DXT5/P8/RGBA8/RGB8/G16 (decode + encode)
- Batch process: grayscale, invert, brightness, contrast, resize, blur, sharpen
- Batch import: folder of PNGs → `.utx` in one step
- Normal map, AO map, specular map generation
- Texture atlas builder (grid packing)
- PBR channel packer (metallic/roughness/AO/height → RGBA)
### 3D Meshes
- Procedural castle generator (towers, walls, battlements, gate, keep, floor)
- StaticMesh serializer for `.usx` packages
- Export to OBJ and FBX ASCII
- Import from OBJ back into the pipeline
- LOD generator (vertex decimation, LOD0–LOD3)
- Collision mesh generator (box, cylinder)
- Procedural heightmap terrain (hills, mountains, plains, island, noise)
### Animations (.ukx)
- Parse AnimationSequence data (frames, bones, tracks)
- Export to BVH format (Blender/Maya compatible)
### Sounds (.uax)
- List sound assets
- Extract sounds to WAV (PCM and embedded WAV)
### Maps (.unr)
- Parse level data: brushes, static meshes, lights, player starts
### Package Management
- Package browser: scan directories for mesh↔texture cross-references
- Package optimizer: remove dead exports, reduce size
- Package comparator: diff two packages
## Installation
```bash
pip install -e .
```
## Usage with opencode
Add to `opencode.json`:
```json
{
"mcp": {
"l2-modding": {
"type": "local",
"command": ["python", "-m", "l2_mcp.server"],
"enabled": true
}
}
}
```
## MCP Tools (25)
### Textures
| Tool | Description |
|------|-------------|
| `l2_list_package` | List all assets in .utx/.usx/.ukx |
| `l2_list_names` | List name table entries |
| `l2_texture_info` | Detailed texture info (format, mips, palette) |
| `l2_extract_texture` | Extract single texture to PNG |
| `l2_extract_all_textures` | Extract all textures to directory |
| `l2_import_texture` | Replace texture with PNG (repacks .utx) |
| `l2_batch_process` | Batch transform (grayscale, invert, etc.) |
| `l2_batch_import_textures` | Folder of PNGs → .utx |
| `l2_gen_normal_map` | Generate normal/AO/specular map |
| `l2_build_atlas` | Pack textures into atlas grid |
| `l2_pack_pbr` | Pack metallic/roughness/AO/height → RGBA |
### Meshes & Level Design
| Tool | Description |
|------|-------------|
| `l2_create_castle` | Generate procedural 3D castle |
| `l2_generate_textures` | Generate stone/roof/floor/gate textures |
| `l2_create_usx_package` | Export meshes to .usx |
| `l2_export_obj` | Export meshes to OBJ or FBX |
| `l2_import_obj` | Import OBJ → mesh pipeline |
| `l2_generate_lods` | Generate LOD0–LOD3 by decimation |
| `l2_gen_collision` | Generate collision mesh (box/cylinder) |
| `l2_gen_terrain` | Procedural heightmap terrain |
### Animations
| Tool | Description |
|------|-------------|
| `l2_animation_info` | List animations in .ukx |
| `l2_export_animation` | Export animation to BVH |
### Sounds
| Tool | Description |
|------|-------------|
| `l2_list_sounds` | List sounds in .uax |
| `l2_extract_sound` | Extract sound to WAV |
| `l2_extract_all_sounds` | Extract all sounds to WAV |
### Package Management
| Tool | Description |
|------|-------------|
| `l2_compare_packages` | Diff two packages |
| `l2_scan_directory` | Scan L2 folder for mesh↔texture refs |
| `l2_optimize_package` | Strip dead exports, reduce size |
| `l2_parse_map` | Read .unr maps (brushes, actors, lights) |
## Supported Texture Formats
| ID | Format | Description |
|----|--------|-------------|
| 0 | P8 | 256-color paletted |
| 1 | RGBA8 | 32-bit RGBA |
| 3 | DXT1/BC1 | 4 bpp, optional 1-bit alpha |
| 4 | RGB8 | 24-bit RGB |
| 5 | DXT3/BC2 | 8 bpp, explicit alpha |
| 6 | DXT5/BC3 | 8 bpp, interpolated alpha |
| B | G16 | 16-bit grayscale |
## Project Structure
```
src/l2_mcp/
├── server.py # MCP server (25 tools)
└── upk/
├── reader.py # Binary reader (compact indices, GUIDs)
├── package.py # UPK parser (.utx/.usx/.ukx) + serializer
├── texture.py # DXT codec + texture decode/encode
├── writer.py # Package rebuilder / repacker
├── mesh.py # StaticMesh serializer + primitives
├── castle.py # Procedural castle generator
├── obj_io.py # OBJ/FBX export
├── obj_import.py # OBJ import
├── animation.py # .ukx parser + BVH export
├── normal_map.py # Normal/AO/specular map generator
├── batch_builder.py # Batch import + heightmap terrain
├── lod.py # LOD generator + collision mesh
├── browser.py # Package scanner + optimizer
├── atlas.py # Texture atlas + PBR packer
├── sound.py # .uax sound extractor
└── unr.py # .unr map parser
```
## License
MIT
TDQS
Scored across 18 tools
Each tool targets a distinct operation on L2 package assets (listing, extracting, importing, generating, comparing). No overlapping purposes; even similar tools like l2_extract_texture and l2_extract_all_textures are clearly differentiated by scope.
All tools follow the 'l2_verb_noun' pattern consistently, using snake_case. Verbs like list, compare, extract, import, generate, create are predictably placed, making the set easy to navigate.
With 18 tools covering textures, meshes, animations, packages, and procedural generation, the count fits the modding domain well. Each tool serves a clear purpose without redundancy.
The toolset covers most modding workflows: texture and package management, mesh import/export, animation export, procedural generation. Minor gaps exist (e.g., no animation import/creation, no generic package creation for non-castle assets), but core operations are well-supported.