Content
# Tool List
> From Installation to Mastery - Let AI Help You Analyze GPU Frames, Reverse Engineer Shaders, and Export Unity Resources
**Version**: 1.5.0 | **Tool Count**: 37 | **Update Date**: 2026-04-14
---
## Table of Contents
- [Chapter 1: Overview and Architecture](#chapter-1-overview-and-architecture)
- [Chapter 2: Environment Preparation](#chapter-2-environment-preparation)
- [Chapter 3: Installation and Configuration](#chapter-3-installation-and-configuration)
- [Chapter 4: Verifying Installation](#chapter-4-verifying-installation)
- [Chapter 5: 37 Tool Details](#chapter-5-37-tool-details)
- [Chapter 6: Practical Workflow](#chapter-6-practical-workflow)
- [Chapter 7: Troubleshooting](#chapter-7-troubleshooting)
- [Chapter 8: Advanced Techniques](#chapter-8-advanced-techniques)
- [Appendix A: API Compatibility](#appendix-a-api-compatibility)
- [Appendix B: Known Limitations](#appendix-b-known-limitations)
---
## Chapter 1: Overview and Architecture
### 1.1 What is This?
RenderDoc MCP Server is a **MCP (Model Context Protocol) server** that acts as a bridge between AI agents and RenderDoc. With it, you can use natural language to let AI:
- 🔍 Analyze GPU frames for every draw call
- 🎨 Automatically identify texture usage (diffuse, normal, PBR, etc.)
- 💎 Reverse-engineer shaders (HLSL/GLSL/SPIR-V)
- 📊 Read shader runtime parameters' actual values
- 🐛 Debug pixel/vertex shaders line by line
- 📤 Export model + texture + material to Unity with one click
- ⚡ Analyze GPU performance bottlenecks
### 1.2 Three-Layer Architecture
```
┌─────────────┐ stdio ┌──────────────────┐ File IPC ┌──────────────────┐
│ AI / IDE │ ◄────────────► │ MCP Server │ ◄────────────► │ RenderDoc Extension │
│ (WorkBuddy) │ │ (Python 3.10+) │ │ (Python 3.6) │
│ │ │ server.py │ │ __init__.py │
└─────────────┘ └──────────────────┘ └──────────────────┘
│ │
37 MCP Tools pyrenderdoc API
(renderdoc.dll)
```
**Why Three Layers?**
Because RenderDoc's built-in Python is version 3.6, while MCP SDK requires Python 3.10+. Two Python versions cannot communicate directly, so we use **file IPC (inter-process communication)** to bridge:
- **MCP Server**: Runs on system Python 3.10+, responsible for communicating with AI
- **RenderDoc Extension**: Runs on RenderDoc's built-in Python 3.6, responsible for actual GPU data operations
- **IPC Communication**: Exchanges data through JSON files in the `%TEMP%/renderdoc_mcp_ipc/` directory
### 1.3 System Requirements
| Component | Minimum Requirements |
| --------- | ----------------------------------------- |
| OS | Windows 10/11, Linux, macOS |
| RenderDoc | v1.20+ (recommended v1.30+) |
| System Python | 3.10+ (for running MCP Server) |
| MCP Client | WorkBuddy / Claude Desktop / any MCP-compatible client |
| Disk Space | ~50MB (excluding frame files) |
---
## Chapter 2: Environment Preparation
### 2.1 Installing RenderDoc
**Windows:**
1. Visit https://renderdoc.org/builds
2. Download the latest stable version
3. Install to the default path (e.g., `C:\Program Files\RenderDoc`)
4. Verify: Run `qrenderdoc.exe` to open normally
**Linux (Ubuntu/Debian):**
```bash
sudo apt-get install renderdoc
# or install the latest version from PPA
sudo add-apt-repository ppa:baldurk/renderdoc
sudo apt-get update
sudo apt-get install renderdoc
```
### 2.2 Installing Python 3.10+
If your system already has Python 3.10+, skip this step.
**Windows:**
```powershell
# using winget
winget install Python.Python.3.12
# or visit https://www.python.org/downloads/ and download manually
```
**Linux:**
```bash
sudo apt-get install python3.12 python3.12-venv python3-pip
```
Verify:
```bash
python --version
# should display Python 3.10+ version
```
### 2.3 Obtaining a GPU Frame Capture
If you don't have a `.rdc` frame capture file, do this:
1. Open RenderDoc
2. Menu `File > Launch Application`
3. Select the program you want to capture (game/graphic application)
4. Click `Launch`
5. Press `F12` or `Print Screen` to capture a frame while the application is running
6. Save the frame file as `.rdc` format
---
## Chapter 3: Installation and Configuration
### 3.1 Installing MCP Server
```bash
# 1. Enter the project directory
cd renderdoc-mcp
# 2. Install (development mode, easy to update)
pip install -e .
# Verify installation success
renderdoc-mcp --help
# or
python -m src.server --help
```
If `pip install -e .` reports an error `Unable to determine which files to ship inside the wheel`, ensure `pyproject.toml` contains:
```toml
[tool.hatch.build.targets.wheel]
packages = ["src"]
```
### 3.2 Installing RenderDoc Extension
The extension is a Python file that needs to be placed in RenderDoc's extension directory.
**Windows Path:**
```
C:\Users\<your_username>\AppData\Roaming\qrenderdoc\extensions\renderdoc_mcp\__init__.py
```
**Linux Path:**
```
~/.local/share/qrenderdoc/extensions/renderdoc_mcp/__init__.py
```
**Steps:**
1. Create the extension directory:
```powershell
# Windows
mkdir "$env:APPDATA\qrenderdoc\extensions\renderdoc_mcp"
```
# Linux
mkdir -p ~/.local/share/qrenderdoc/extensions/renderdoc_mcp
```
2. Copy the extension file to this directory (if it exists in the project)
3. Restart RenderDoc
4. Verify: In RenderDoc, menu `Tools > RenderDoc MCP > Status`, should display "MCP bridge is RUNNING"
### 3.3 Configuring MCP Client
Configure according to the MCP client you use.
#### WorkBuddy Configuration
Edit `~/.workbuddy/mcp.json`:
```json
{
"mcpServers": {
"renderdoc": {
"command": "renderdoc-mcp",
"env": {}
}
}
}
```
or use Python module:
```json
{
"mcpServers": {
"renderdoc": {
"command": "python",
"args": ["-m", "src.server"],
"cwd": "C:\\Users\\admin\\WorkBuddy\\Claw\\renderdoc-mcp",
"env": {}
}
}
}
```
#### Claude Desktop Configuration
Edit `claude_desktop_config.json`:
```json
{
"mcpServers": {
"renderdoc": {
"command": "renderdoc-mcp"
}
}
}
```
### 3.4 Complete Startup Process
Each use requires starting in the following order:
```
Method 1 (manual startup):
Step 1: Open RenderDoc (qrenderdoc.exe)
↓
Step 2: Load capture file (File > Open Capture)
↓
Step 3: Confirm extension is running (Tools > RenderDoc MCP > Status → "RUNNING")
↓
Step 4: Start/restart MCP client (WorkBuddy / Claude Desktop)
↓
Step 5: Use RenderDoc tools in AI conversation
Method 2 (automatic startup 🆕):
Step 1: Start MCP client (WorkBuddy / Claude Desktop)
↓
Step 2: Enter "Open capture C:\path\to\capture.rdc" in AI conversation
↓
Step 3: AI calls launch_renderdoc() → Automatically start RenderDoc + load capture + wait for bridge ready
↓
Step 4: Directly start analysis!
```
> 💡 **Tip**: `launch_renderdoc` tool will automatically search for the qrenderdoc executable, start it, and wait for the MCP bridge to be ready (up to 30 seconds). If RenderDoc is already running, it will automatically switch to `open_capture` to improve speed.
> ⚠️ **Note**: When using method 1, RenderDoc must be opened and the capture file loaded before starting MCP Server. Otherwise, tool calls will timeout.
---
## Chapter 4: Verifying Installation
### 4.1 Quick Health Check
Enter in AI conversation:
```
Help me check if RenderDoc MCP is connected normally
```
AI will call `ping()` tool, and a normal response should return:
```json
{"status": "ok", "server": "renderdoc_mcp", "ipc_dir": "C:\\Users\\...\\renderdoc_mcp_ipc"}
```
### 4.2 Viewing Capture Status
```
View the basic information of the current capture
```
AI will call `get_capture_status()`, returning:
```json
{
"loaded": true,
"api": "Vulkan",
"renderer": "AMD Radeon RX 6800",
"frameNumber": 8228,
"draws": 125,
"dispatches": 0,
"calls": 1547
}
```
### 4.3 If It Doesn't Work
| Symptom | Possible Cause | Solution |
| ---------------- | ------------- | ---------------------------- |
| `ping` timeout | RenderDoc not opened | Open RenderDoc first |
| `ping` timeout | Extension not loaded | Check extension directory path is correct |
| `ping` timeout | Capture not loaded | Open .rdc file in RenderDoc first |
| "Unknown method" | Extension version is old | Update extension `__init__.py` |
| Tool count mismatch | Server or extension not matched | Update server.py and __init__.py simultaneously |
---
## Chapter 5: 37 Tool Details
### 📡 Category 1: Connection Management (2 tools)
#### `ping`
Check if RenderDoc bridge is online.
```
Usage: ping
Parameters: None
Returns: {status: "ok", server: "renderdoc_mcp", ipc_dir: "..."}
```
**Usage Scenario**: Ping once before starting work to confirm connection is normal.
---
#### `get_capture_status`
Check capture loading status and graphics API information.
```
Usage: get_capture_status
Parameters: None
Returns: {loaded, api, renderer, frameNumber, draws, dispatches, calls}
```
**Return Field Explanation**:
| Field | Description |
|------|------|
| `loaded` | Whether capture is loaded |
| `api` | Graphics API (D3D11/D3D12/Vulkan/OpenGL) |
| `renderer` | GPU name |
| `frameNumber` | Frame number |
| `draws` | Draw call count |
| `dispatches` | Compute dispatch count |
| `calls` | Total API call count |
---
### 📂 Category 2: Capture Management (3 tools)
#### `list_captures`
List all `.rdc` capture files in a specified directory.
```
Usage: list_captures(directory)
Parameters: directory - Path to search
Returns: [{name, path, size}, ...]
```
**Example**:
```
List all capture files in C:\Captures
→ list_captures("C:\\Captures")
```
---
#### `open_capture`
Open a capture file in RenderDoc.
```
Usage: open_capture(capture_path)
Parameters: capture_path - Absolute path to .rdc file
Returns: {opened: "path"}
```
**Example**:
```
Open capture file C:\Captures\game_frame.rdc
→ open_capture("C:\\Captures\\game_frame.rdc")
```
---
#### `launch_renderdoc` 🆕
Launch RenderDoc application and open a `.rdc` capture file. **No need to open RenderDoc in advance**.
```
Usage: launch_renderdoc(capture_path, renderdoc_path)
Parameters:
capture_path: str Absolute path to .rdc file (required)
renderdoc_path: str Path to qrenderdoc executable (optional, auto-detected)
Returns: {launched, exe, capture, pid, bridgeReady, waitTime, fileSizeMB}
```
**Auto-detection order for qrenderdoc**:
1. User-specified path (`renderdoc_path` parameter)
2. `RENDERDOC_PATH` / `RENDERDOC_MODULE_PATH` environment variables
3. System `PATH`
4. Common installation paths (Windows: `C:\Program Files\RenderDoc\`, Linux: `/usr/bin/`, macOS: `/Applications/`)
#### `get_draw_calls`
Get all draw calls within a frame, supporting multiple filtering conditions.
```
Usage: get_draw_calls(include_children, marker_filter, only_actions, event_id_min, event_id_max)
Parameters:
include_children: bool = True Whether to include child operations
marker_filter: str = "" Filter by Marker name
only_actions: bool = False Return only actual Draw/Dispatch
event_id_min: int = 0 Minimum event ID (0=unlimited)
event_id_max: int = 0 Maximum event ID (0=unlimited)
Returns: {count, actions: [{eventId, name, flags, numIndices, numInstances, depth}, ...]}
```
**Return Field Description**:
| Field | Description |
|------|------|
| `eventId` | Event ID (globally unique, used for other tool parameters) |
| `name` | Name (Marker name or "Action N") |
| `flags` | Operation flag bits (Draw=64, Dispatch=128, etc.) |
| `numIndices` | Index/vertex count (triangle count = numIndices / 3) |
| `numInstances` | Instance count (GPU Instancing) |
| `depth` | Nesting depth (depth within a Marker) |
**Example**:
```
Get all draw calls
→ get_draw_calls()
Only consider operations between event IDs 60-100
→ get_draw_calls(event_id_min=60, event_id_max=100)
Search for operations with names containing "Eye"
→ get_draw_calls(marker_filter="Eye")
```
---
#### `get_frame_summary`
Get a statistical summary of a frame.
```
Usage: get_frame_summary
Parameters: None
Returns: Same as get_capture_status
```
---
#### `get_draw_call_details`
Get detailed information about a single DrawCall.
```
Usage: get_draw_call_details(event_id)
Parameters: event_id - Event ID
Returns: {eventId, vertexShader, fragmentShader, renderTargets, depthTarget, viewport}
```
---
### 🔧 Category 4: Pipeline State (1)
#### `get_pipeline_state`
Get the complete rendering pipeline state for a specified event.
```
Usage: get_pipeline_state(event_id)
Parameters: event_id - Event ID
Returns: {shaders: {vertex, fragment, ...}, renderTargets, depthTarget}
```
Each shader entry contains:
| Field | Description |
|------|------|
| `shaderId` | Shader resource ID |
| `entryPoint` | Entry function name |
| `textureCount` | Bound texture count |
| `cbufferCount` | Constant buffer count |
| `samplerCount` | Sampler count |
**Common Scenario**: Determine which shaders are used by a DrawCall and how many textures are bound.
---
### 💎 Category 5: Shader Analysis (4)
#### `get_shader_info`
Get detailed information about a shader, including disassembly and bound textures. **This is the most commonly used shader analysis tool.**
```
Usage: get_shader_info(event_id, stage)
Parameters:
event_id: int Event ID
stage: str "vertex" | "fragment"/"pixel" | "geometry" | "compute" | "hull"/"tess_ctrl" | "domain"/"tess_eval"
Returns: {shaderId, pipelineId, stage, entryPoint, disassemblyTargets, disassembly,
inputs, outputs, boundTextures, constantBuffers, samplers}
```
**Return Field Details**:
| Field | Description |
| -------------------- | ------------------------------------------------------------------- |
| `disassemblyTargets` | List of available disassembly targets (e.g., ["SPIR-V (RenderDoc)", "AMDIL", "RDNA2 gfx1030", ...]) |
| `disassembly` | Disassembly code for each target (dictionary) |
| `sourceFiles` | Embedded source files (if any) |
| `inputs` | Shader input signature |
| `outputs` | Shader output signature |
| `boundTextures` | Bound texture list (including slot, resourceId, size, format, inferred role) |
| `constantBuffers` | Constant buffers (including variable names and runtime values) |
| `samplers` | Sampler states |
---
#### `reverse_shader`
One-stop shader reverse engineering - same functionality as `get_shader_info`, but with more explicit semantics.
```
Usage: reverse_shader(event_id, stage)
Parameters: Same as get_shader_info
Returns: Same as get_shader_info
```
**When to Use**: When you want to fully understand what a shader is doing.
---
#### `get_bound_textures`
Get all textures bound to a shader at a specific stage, including **automatic role inference**.
```
Usage: get_bound_textures(event_id, stage)
Parameters:
event_id: int Event ID
stage: str Shader stage
Returns: [{slot, name, bind, resourceId, texName, width, height, format, role}, ...]
```
**Role Inference Rules**:
| Keyword Match | Inferred Role | Description |
|-----------|---------|------|
| `albedo`, `diffuse`, `basecolor`, `_col`, `maintex` | `albedo` | Base color map |
| `normal`, `nrm`, `bump`, `_n_` | `normal` | Normal map |
| `metallic`, `metalness`, `_met` | `metallic` | Metallic map |
| `rough`, `roughness`, `_rgh`, `smoothness` | `roughness` | Roughness map |
| `ao`, `occlusion`, `_occ` | `ao` | Ambient occlusion |
| `emissive`, `emission`, `glow` | `emissive` | Emissive map |
| `env`, `cubemap`, `reflection`, `ibl` | `environment` | Environment reflection |
| `shadow`, `shadowmap` | `shadow` | Shadow map |
| BC5/RG format | `normal` | Format-based inference |
| BC6H/HDR format | `environment` | Format-based inference |
---
#### `find_draws_by_texture`
Search for all DrawCalls that use a specified texture name.
```
Usage: find_draws_by_texture(texture_name)
Parameters: texture_name - Partially matching texture name (e.g., "eye", "skin")
Returns: {textureIds, draws: [{eventId, name}], note}
```
---
#### `find_draws_by_shader`
Search for DrawCalls by shader name.
```
Usage: find_draws_by_shader(shader_name, stage)
Parameters:
shader_name: str Partially matching shader name
stage: str = "" Optional stage filter
Returns: Search results
```
> ⚠️ This feature is not fully implemented on the extension side.
---
#### `find_draws_by_resource`
Search for DrawCalls by resource ID.
```
Usage: find_draws_by_resource(resource_id)
Parameters: resource_id - Resource ID
Returns: Search results
```
> ⚠️ This feature is not fully implemented on the extension side.
---
### 📦 Category 6: Resource Inspection (4)
#### `get_textures`
List all live textures in a frame capture.
```
Usage: get_textures
Parameters: None
Returns: [{id, name, w, h, fmt, mips, array, size}, ...]
```
**Example Output**:
```json
[
{"id": 102757, "name": "RT_Color", "w": 1598, "h": 898, "fmt": "R8G8B8A8_UNORM", "mips": 1, "size": 5738408},
{"id": 110432, "name": "eye_iris_d", "w": 512, "h": 512, "fmt": "BC3_UNORM", "mips": 10, "size": 349524}
]
```
---
#### `get_buffers`
List all buffers.
```
Usage: get_buffers
Parameters: None
Returns: [{id, name, length}, ...]
```
---
#### `get_resources`
List all resources (textures, buffers, shaders, pipeline objects, etc.).
```
Usage: get_resources
Parameters: None
Returns: [{id, name, type}, ...]
```
---
#### `get_texture_info`
Get detailed metadata for a single texture.
```
Usage: get_texture_info(resource_id)
Parameters: resource_id - Texture resource ID
Returns: {id, name, w, h, d, fmt, mips, array, size}
```
---
### 🖼️ Category 7: Texture Operations (5)
#### `get_texture_data`
Get pixel data for a texture (Base64 encoded).
```
Usage: get_texture_data(resource_id, mip, slice)
Parameters:
resource_id: int Texture ID
mip: int = 0 Mip level
slice: int = 0 Array slice
Returns: {resourceId, length, base64: "...(first 10,000 characters)"}
```
---
#### `pick_pixel`
Read the pixel value at a specified coordinate on a texture.
```
Usage: pick_pixel(resource_id, x, y)
Parameters:
resource_id: int Texture ID
x: int X coordinate
y: int Y coordinate
Returns: {x, y, r, g, b, a}
```
**Use Case**: Check the color value of a pixel on a render target to verify rendering results.
---
#### `get_texture_minmax`
Get the minimum and maximum pixel values for a texture.
```
Usage: get_texture_minmax(resource_id)
Parameters: resource_id - Texture ID
Returns: {min: {r, g, b, a}, max: {r, g, b, a}}
```
**Use Case**: Check the value range of an HDR texture to determine if there are any abnormal values.
---
#### `save_texture`
Export a texture to disk. Automatically detect CubeMaps (array size = 6) and adapt the export.
```
Usage: save_texture(resource_id, output_path, mip, slice)
Parameters:
resource_id: int Texture ID
output_path: str Output file path
mip: int = 0 Mip level
slice: int = -1 CubeMap face index: -1=all faces (default), 0-5=specific face
Returns:
2D Texture: {saved: "path", type: "2D"}
CubeMap PNG/JPG: {type: "cubemap", faces: 6, savedFaces: [...]}
CubeMap DDS: {saved: "path", type: "cubemap", format: "DDS (all 6 faces)"}
```
**Supported Formats**: PNG, JPG, BMP, TGA, HDR, EXR, DDS (automatically selected based on file extension)
**CubeMap Export Strategy** (v1.3.0 🆕):
| Format | Behavior | Files |
|------|------|------|
| DDS | 6 faces merged into a single file | `cubemap.dds` |
| PNG/JPG/etc. | Automatically split into 6 face files | `cubemap_face0_posX.png` ~ `cubemap_face5_negZ.png` |
| Specify slice=N | Export only the Nth face | `cubemap.png` (single file) |
**Face Order**: 0=+X (right), 1=-X (left), 2=+Y (up), 3=-Y (down), 4=+Z (front), 5=-Z (back)
**Example**:
```
save_texture(102757, "C:/output/render_target.png") # 2D Texture
save_texture(98134, "C:/output/env_cubemap.dds") # CubeMap → 1 DDS
save_texture(98134, "C:/output/env_cubemap.png") # CubeMap → 6 PNGs
save_texture(98134, "C:/output/env_front.png", slice=4) # CubeMap → Only +Z face
```
---
#### `get_buffer_contents`
Read raw buffer data.
```
Usage: get_buffer_contents(resource_id, offset, length)
Parameters:
resource_id: int Buffer ID
offset: int = 0 Starting offset (bytes)
length: int = 256 Read length (bytes)
Returns: {resourceId, offset, length, hex: "...", base64: "..."}
```
---
### 🔍 Category 8: Pixel History (1)
#### `pixel_history`
Track the complete modification history of a pixel throughout a frame.
```
Usage: pixel_history(resource_id, x, y)
Parameters:
resource_id: int Render target texture ID
x: int Pixel X coordinate
y: int Pixel Y coordinate
Returns: [{eventId, pre: {r,g,b,a}, post: {r,g,b,a}}, ...]
```
**Use Case**: Investigate why a pixel displays an incorrect color. By viewing the values before and after each write, you can locate the DrawCall that caused the issue.
**Example**:
```
View pixel history at coordinates (400, 300) on render target 102757
→ pixel_history(102757, 400, 300)
→ Returns: [
{eventId: 23, post: {r: 0.0, g: 0.0, b: 0.0, a: 0.0}}, // Clear
{eventId: 73, post: {r: 0.8, g: 0.2, b: 0.1, a: 1.0}}, // Eye rendering
{eventId: 94, post: {r: 0.9, g: 0.7, b: 0.3, a: 1.0}}, // Effect composition
]
```
---
### 🐛 Category 9: Shader Debugging (2)
#### `debug_pixel`
Step through the execution of a pixel shader.
```
Usage: debug_pixel(x, y)
Parameters:
x: int Pixel X coordinate
y: int Pixel Y coordinate
Returns: {x, y, steps, trace: [{step, vars: [{name, val}]}, ...]}
```
> ⚠️ Requires setting the current event using `get_pipeline_state` or `get_shader_info`.
**Use Case**: When shader output is incorrect, step through each variable's value during execution.
---
#### `debug_vertex`
Step through the execution of a vertex shader.
```
Usage: debug_vertex(vertex_id, instance_id)
Parameters:
vertex_id: int Vertex ID
instance_id: int = 0 Instance ID
Returns: {vertexId, steps, trace: [{step, vars}]}
```
---
### ⚡ Category 10: Performance Analysis (3)
#### `enumerate_counters`
List all performance counters supported by the GPU.
```
Usage: enumerate_counters
Parameters: None
Returns: [{id, name, desc, unit}, ...]
```
---
#### `fetch_counters`
Get the values of specified performance counters.
```
Usage: fetch_counters(counter_ids)
Parameters: counter_ids - Comma-separated list of counter IDs (e.g., "1,2,3")
Returns: [{eventId, counter, value}, ...]
```
---
# Tool List
## Category Eleven: Mesh and Debug (3)
### `get_post_vs_data`
Get mesh output information after vertex shader.
```
Usage: get_post_vs_data
Parameters: None
Returns: {numIndices, topology, indexStride, vertexStride}
```
### `get_debug_messages`
Get graphics driver validation/debug messages.
```
Usage: get_debug_messages
Parameters: None
Returns: [{eventId, severity, msg}, ...]
```
### `debug_vulkan_bindings`
Diagnostic tool: dump Vulkan descriptor set bindings' raw data structure for troubleshooting texture binding parsing issues.
```
Usage: debug_vulkan_bindings(event_id, stage)
Parameters:
event_id: int Event ID
stage: str Shader stage (default "fragment")
Returns: {eventId, api, readOnlyResources, descriptorAccess, shaderReflection, ...}
Timeout: 60 seconds
```
**Purpose**: When `get_bound_textures` returns resourceId=0, use this tool to diagnose the actual data path of Vulkan descriptor.
**Return fields description**:
- `readOnlyResources` — List of `UsedDescriptor` objects (including `.descriptor.resource` actual texture ID)
- `descriptorAccess` — List of `DescriptorAccess` objects (including descriptor store and index information)
- `shaderReflection` — Read-only resource binding information in Shader reflection
## Category Twelve: Export (2)
### `export_drawcall`
Export all data of a DrawCall with one click.
```
Usage: export_drawcall(event_id, output_dir)
Parameters:
event_id: int Event ID
output_dir: str Output directory
Returns: {eventId, outputDir, files: [...]}
Timeout: 60 seconds
```
**Export content**:
- Disassembled shaders in all formats (`.txt`)
- Embedded source code (if any)
- All bound textures (`.png`)
- Constant buffer values
- Pipeline state summary (`summary.json`)
### `export_to_unity`
Export a DrawCall as Unity-usable resources (model + material mapping) with one click.
**v1.5.0 improvement**: Fixed multiple model export quality issues - DX11 left-hand coordinate system automatically converted to right-hand coordinate system, index remapping accurately extracted, and compressed encoding normal automatically detected.
> **Textures are not exported in this tool** - use `save_texture` or `export_drawcall` to export texture files separately.
> The `textures` list returned by this tool contains the `resourceId` of each texture, making it convenient for subsequent on-demand export.
```
Usage: export_to_unity(event_id, output_dir, mesh_name)
Parameters:
event_id: int Event ID
output_dir: str Output directory
mesh_name: str = "exported_mesh" Model and material name
Returns: {eventId, outputDir, meshFile, fbxFile, textures, materialFile, meshStats, files}
Timeout: 60 seconds
```
**Model extraction method** (improved in v1.3.0):
Preferably use **VBuffer + IBuffer + VertexInputs** to directly read GPU buffers (refer to Model Extractor plugin),
Vulkan/ANGLE frame capture compatibility is much better than the old PostVS method. PostVS is retained as a fallback solution.
Supported vertex formats: Float32, Float16, UNorm, SNorm, UInt, SInt.
**Export content**:
| File | Description |
| -------------------------- | ---------------------------------- |
| `{name}.obj` | 3D model — OBJ format (vertices/normals/UV/indexes) |
| `{name}.fbx` | 3D model — FBX 7.4 ASCII format (Unity/Unreal/Blender compatible) |
| `{name}_material.json` | Unity material definition (Standard/URP/HDRP property mapping) |
| `{name}_UnityImport.cs` | C# editor script (one-click import) |
| `{name}_unity_export.json` | Complete export summary (including texture binding information) |
**Returned texture binding information** (no file exported):
```json
"textures": [
{
"role": "albedo",
"slot": 0,
"resourceId": 268775,
"width": 512, "height": 512,
"hint": "Use save_texture(resource_id=268775, output_path=...) to export"
}
]
```
**Unity import process**:
1. Copy the export folder (including `.fbx`) to Unity `Assets/` directory
2. Export required textures to the same directory using `save_texture` by resourceId
3. Place `_UnityImport.cs` in `Assets/Editor/`
4. Menu → `RenderDoc > Import {name}`
5. Automatic completion: import model → create material → assign texture
## Category Thirteen: Intelligent Identification and Analysis (2)
### `identify_drawcalls`
Intelligently identify the rendering content of each DrawCall (eyes, hair, armor, accessories, etc.).
**Core principle**: Execute `SetFrameEvent → SaveTexture(RT)` for each DrawCall, generate RT accumulation screenshot, and directly "see" what each DrawCall draws - much more accurate than estimating by face count.
```
Usage: identify_drawcalls(event_id_min, event_id_max, output_dir, render_target)
Parameters:
event_id_min: int = 0 Minimum event ID
event_id_max: int = 999999 Maximum event ID
output_dir: str = "" Thumbnail output directory (one RT screenshot per DrawCall)
render_target: int = 0 Render target ID (0=auto detect)
Returns: {renderTarget, rtSize, actionCount, shaderGroups, actions: [...]}
Timeout: 120 seconds
```
**Information returned for each DrawCall**:
| Field | Description |
|------|------|
| `eventId` | Event ID |
| `triangles` | Triangle count |
| `vertexShader` / `fragmentShader` | Shader ID (same shader = same material type) |
| `textureCount` | Bound texture count |
| `textures` | ResourceId and size of first 5 textures |
| `screenBBox` | Screen space bounding box (minX/Y, maxX/Y, depth) |
| `screenCoverage` | Screen coverage percentage |
| `thumbnail` | RT accumulation screenshot path (requires output_dir specified) |
**Shader grouping**: Automatically group by VS/FS shader ID, return `shaderGroups`:
```json
{
"110742/110743": [66], // skin shader → EID 66
"110755/110756": [73], // eye shader → EID 73
"110759/110760": [87, 126], // hair shader → EID 87, 126
"106208/106209": [94,97,...], // accessory shader → 8 instances
}
```
**Identification process**:
1. Run `identify_drawcalls` and specify `output_dir` to save thumbnails
2. Compare adjacent screenshots (eid_NNNN.png), and the difference is what the DrawCall draws
3. Combine with `shaderGroups` grouping - same shader DrawCalls are of the same type of components
### `analyze_lighting`
Analyze the lighting setup of a DrawCall - extract all lighting-related information from shader code and constant buffer.
```
Usage: analyze_lighting(event_id)
Parameters:
event_id: int Event ID
Returns: {eventId, cbuffers, lightingModel, shadowMaps, environmentMaps}
Timeout: 60 seconds
```
**Analysis content**:
| Dimension | Description |
|------|------|
| **Lighting model detection** | Infer PBR/Blinn-Phong/Lambert models from shader disassembly |
| **Shader features** | Shadow mapping, environment reflection, subsurface scattering, multi-light loop, etc. |
| **CBuffer structure** | Name, type, and array size of all uniform variables |
| **Variable semantic classification** | Automatically classify variables into light / shadow / ambient categories |
| **Shadow map** | Identify bound Depth format texture (shadow map) |
| **Environment map** | Identify bound CubeMap (IBL / reflection probe) |
**Lighting model detection example**:
```json
{
"model": "PBR (inferred)",
"features": [
"shadow_mapping",
"environment_reflection",
"multi_light_loop"
]
}
```
**CBuffer variable automatic classification** (heuristic rules for ANGLE anonymous variables):
| Array pattern | Inferred category | Description |
|---------|---------|------|
| `float4[4]` | `ambient_or_matrix` | SH coefficients or transformation matrix |
| `float4[6]` | `light_array` | Multi-light data (position/color/direction/attenuation) |
| `float4[8]` | `shadow_matrix` | Shadow cascade matrix |
| `float4[2]` | `shadow_param` | Shadow atlas UV parameters |
| Single value (unit vector) | `light_direction` | Main light direction |
| Single value (RGB in range 0~2) | `color_or_light` | Light color |
> **Note**: In Vulkan/ANGLE frame capture, cbuffer variable names are anonymous (`_childN`), and values need to be viewed through RenderDoc GUI.
> D3D11 frame capture usually has complete variable names and values.
## Chapter 6: Practical Workflows
### 6.1 Workflow 1: Analyze a DrawCall
```
Goal: Understand how an object is rendered in the game
Step 1: "List all draw calls"
→ get_draw_calls(only_actions=True)
→ Find the eventId of interest (e.g., 73)
Step 2: "View pipeline state of event 73"
→ get_pipeline_state(73)
→ Confirm which shaders are used
Step 3: "Reverse-engineer fragment shader of event 73"
→ get_shader_info(73, "fragment")
→ Get: disassembled code + bound textures + constant buffer values
Step 4: "Save all bound textures of event 73"
→ Call save_texture() for each boundTexture
```
### 6.2 Workflow 2: Locate Rendering Issues
```
Goal: Troubleshoot why a pixel displays an incorrect color
Step 1: "Get render target information"
→ get_textures() → Find the resourceId of the render target
Step 2: "View pixel history of (400,300)"
→ pixel_history(rt_id, 400, 300)
→ Find which eventId wrote the incorrect value
Step 3: "Analyze the shader of that DrawCall"
→ get_shader_info(event_id, "fragment")
Step 4: "Debug that pixel"
→ debug_pixel(400, 300)
→ Step-by-step view variable values
```
### 6.3 Workflow 3: Export to Unity
```
Goal: Export a character's eye from a frame capture to Unity
Step 1: "List draw calls between 60-100"
→ get_draw_calls(event_id_min=60, event_id_max=100)
→ Find the eventId of the eye (e.g., 73)
Step 2: "Export event 73 to Unity, named eye_ball"
→ export_to_unity(73, "C:/output/eye", "eye_ball")
→ Generate .obj + .png × N + material.json + UnityImport.cs
Step 3: Copy to Unity project and run import script
```
### 6.4 Workflow 4: Shader Reverse Engineering
```
Goal: Restore a shader from a frame capture to a usable .shader file
Step 1: "Reverse-engineer fragment shader of event 73"
→ reverse_shader(73, "fragment")
→ Get SPIR-V / HLSL disassembly
Step 2: "Reverse-engineer vertex shader of event 73"
→ reverse_shader(73, "vertex")
→ Get vertex shader disassembly
Step 3: "Get all bound textures and cbuffer values of event 73"
→ get_bound_textures(73, "fragment")
→ Get texture slot mapping
Step 4: "Export all data of event 73"
→ export_drawcall(73, "C:/output/shader_data")
→ Get all disassembled files + textures + parameters
Step 5: Use AI to restore a complete Unity .shader file based on exported data
```
### 6.5 Workflow 5: Performance Analysis
```
Goal: Find the most time-consuming DrawCall in a frame
Step 1: "List all available performance counters"
→ enumerate_counters()
→ Find the ID of the GPU Time counter
Step 2: "Get GPU time consumption of all DrawCalls"
→ fetch_counters("1") (assuming 1 is GPU Time)
→ Sort by time consumption and find the bottleneck
Step 3: "Analyze the shader of the most time-consuming DrawCall"
→ get_shader_info(event_id, "fragment")
→ View shader complexity
```
## Chapter 7: Troubleshooting
### 7.1 Connection Issues
**Issue: ping timeout**
```
✅ Checklist:
1. Is RenderDoc (qrenderdoc.exe) running?
2. Is the frame capture file loaded? (title bar displays file name)
3. Are extensions loaded?
→ Tools > RenderDoc MCP > Status
→ Should display "MCP bridge is RUNNING"
4. Is the IPC directory accessible?
→ Check if %TEMP%\renderdoc_mcp_ipc\ exists
```
**Issue: Extension menu does not exist**
```
✅ Checklist:
1. Is the extension file path correct?
Windows: %APPDATA%\qrenderdoc\extensions\renderdoc_mcp\__init__.py
Linux: ~/.local/share/qrenderdoc/extensions/renderdoc_mcp/__init__.py
2. Must the file name be __init__.py and the directory name be renderdoc_mcp?
3. Restart RenderDoc
4. Check if there are error messages in RenderDoc's output panel
```
### 7.2 API Compatibility Issues
**Issue: Certain tools return errors**
The Python API of different RenderDoc versions has differences. Known compatibility handling:
| Issue | Description | Solution |
| ------------------------------------ | ----------------------- | -------------------------- |
| `TextureDescription` without `name` | Older versions do not store names directly | Look up using `GetResources()` |
| `ResourceFormat` str() returns Swig object | SWIG wrapping issue | Use `.name` attribute |
| `SigParameter` without `compType` | Vulkan/ANGLE capture | Use `getattr` for safe access |
| No `GetShaderPipelineObject` | Older API | Vulkan fallback |
| No `GetConstantBuffers`/`GetSamplers` | Version differences | Use `try/except` protection |
| `UsedDescriptor` without `.resources` | Binding structure change | Compatible with multiple structures |
| `LoadCapture` requires 5 parameters | New API signature change | Try/except for automatic 4/5 parameter adaptation |
| Vulkan `UsedDescriptor.resource` returns pointer | SWIG binding difference | Use `.descriptor.resource` path (fixed in v1.2.0) |
### 7.3 Performance Issues
**Issue: Tool invocation is slow**
```
✅ Optimization suggestions:
1. Avoid frequent calls to get_textures() / get_resources() — results do not change, cache them
2. export_drawcall may take 30-60 seconds — it iterates over all disassembly targets
3. pixel_history can be slow on large RTs — this is a limitation of RenderDoc itself
4. If IPC times out, increase the timeout parameter
```
---
## Chapter 8: Advanced Techniques
### 8.1 Using Multiple Captures
By using `list_captures` + `open_capture`, you can switch between different captures for comparative analysis.
### 8.2 Batch Exporting Textures
```python
# Let AI execute:
"Get all texture lists, then export all textures larger than 256x256 as PNG"
→ get_textures()
→ Call save_texture() for each qualifying texture
```
### 8.3 Shader Comparison Analysis
```
"Compare the fragment shaders of events 73 and 80"
→ get_shader_info(73, "fragment")
→ get_shader_info(80, "fragment")
→ AI compares the differences between the two shaders
```
### 8.4 Custom Unity Import
The `_material.json` generated by `export_to_unity` contains three property mappings:
- `property`: Unity Standard Shader
- `urpProperty`: URP (Universal Render Pipeline)
- `hdrpProperty`: HDRP (High Definition Render Pipeline)
You can manually edit the JSON to adapt to custom shaders.
### 8.5 IPC Debugging
If you need to debug IPC communication, you can view intermediate files:
```powershell
# View IPC directory
dir $env:TEMP\renderdoc_mcp_ipc\
# View recent requests (if any remain)
cat $env:TEMP\renderdoc_mcp_ipc\request.json
# View [RD-MCP] logs in RenderDoc output panel
```
---
## Appendix A: API Compatibility Instructions
This project has handled compatibility for the following RenderDoc versions:
| RenderDoc Version | Graphics API | Test Status |
| ------------ | --------------------- | ----------------- |
| v1.26+ | Vulkan (ANGLE/SPIR-V) | ✅ Tested and passed |
| v1.26+ | D3D11 (DXBC/ps_5_0) | ✅ Tested and passed |
| v1.20+ | D3D12 | ⚠️ Compatibility code in place (not actually tested) |
| v1.20+ | OpenGL | ⚠️ Compatibility code in place (not actually tested) |
**D3D11 Test Results**:
- Pipeline state acquisition: ✅ null pipeline ID fallback takes effect
- DXBC disassembly: ✅ ps_5_0 correctly disassembled
- Input/output semantics: ✅ SV_Position/TEXCOORD/SV_Target/SV_IsFrontFace correctly parsed
- CBuffer variables: ✅ Supports multiple CBuffers (including 65KB dynamic index cbuffer)
- Texture binding: ✅ SRV detection
- Hull/Domain shaders: ✅ Supports Tessellation stage
Vulkan/ANGLE and D3D11 captures have undergone complete compatibility testing and fixes.
**Vulkan Texture Export Fix** (v1.2.0):
- **Issue**: In Vulkan captures, `get_bound_textures` / `export_drawcall` cannot export textures (resourceId all return 0)
- **Root cause**: In the SWIG binding of `UsedDescriptor`, `int(binding.resource)` returns a memory pointer instead of ResourceId
- **Fix**: Use the `.descriptor.resource` path to resolve (`UsedDescriptor → Descriptor → resource`)
- **Verification**: King of Glory Vulkan/ANGLE capture → 9 textures all successfully exported as PNG (including Albedo/Normal/AO/Depth)
**Model Export Rewrite + FBX Support** (v1.3.0):
- **Improvement**: Reference Model Extractor plugin, use `GetVBuffers() + GetIBuffer() + GetVertexInputs()` to directly read GPU buffers
- **Advantage**: Supports Float16/Float32/UNorm/SNorm/UInt/SInt vertex formats, Vulkan compatibility far superior to old PostVS method
- **New feature**: FBX 7.4 ASCII export (`_write_fbx_ascii`), compatible with Unity/Unreal/Blender/Maya
- **Simplification**: `export_to_unity` no longer exports texture PNG (use `save_texture` / `export_drawcall` to export separately), response from timeout → seconds to complete
- **Verification**: Guan Yu head EID=172 (2590 vertices/4772 faces) → OBJ 157.9KB + FBX 198.9KB — both formats generated simultaneously ✅
**Model Export Quality Fix** (v1.5.0):
- **Index fix**: Correctly apply `baseVertex` (BaseVertexLocation of DrawIndexed) and `indexOffset` (index buffer offset); introduce index remapping mechanism, only export unique vertices actually referenced by DrawCall, eliminate redundant vertices
- **Coordinate system conversion**: DX11 left-handed coordinate system → automatic conversion to right-handed coordinate system (position X-axis takes negative + triangle face winding direction reverses), solve model mirroring problem
- **Normal processing**: Automatically detect compressed encoded tangent frames (such as NORMAL semantics storing packed uint32), normals exceeding [-1.5, 1.5] range are discarded, let Unity/Blender recalculate based on faces
- **UV fix**: `flip_uv_v` is disabled by default (DX11 → Unity does not need to flip V coordinates), avoid UV up and down inversion
- **Vertex attribute reading**: Always read according to original compCount and then intercept to wanted_comp, avoid stride alignment errors when 4-component attributes read 3 components; automatically pad with zeros when components are insufficient
- **Format support**: Add R10G10B10A2_UNorm/SNorm packaging format decoding
- **Verification**: D3D11 capture EID=320 (3346 unique vertices) → OBJ + FBX export, UV/model/normals are completely correct in Unity ✅
---
## Appendix B: Known Limitations
1. **find_by_shader** and **find_by_resource** are not fully implemented on the extension side
2. **get_action_timings** does not have a corresponding processing function on the extension side
3. Shader debugging (debug_pixel/debug_vertex) returns a step limit of 50 steps
4. Texture data (get_texture_data) Base64 output truncated to the first 10000 characters
5. Buffer data (get_buffer_data) maximum read 4096 bytes
6. Model export prioritizes using VBuffer+IBuffer method (v1.3.0), PostVS as fallback; FBX export as ASCII 7.4 format
7. CubeMap texture export has been adapted (v1.3.0): PNG/JPG automatically export 6-face files, DDS export complete CubeMap
8. Model export includes DX→right-handed coordinate system automatic conversion (v1.5.0); compressed encoded normals (packed tangent frame) will be discarded and recalculated by the importer
---
## Appendix C: File Structure Reference
```
renderdoc-mcp/
├── pyproject.toml # Python project configuration
├── README.md # English documentation
├── README_CN.md # Chinese overview
├── MANUAL_CN.md # This document - complete manual
├── SETUP_GUIDE.md # Installation configuration report
└── src/
├── __init__.py
├── server.py # MCP Server (37 tools)
├── rd_wrapper.py # RenderDoc API wrapper (local direct connection mode)
└── ipc_client.py # File IPC client
RenderDoc extension:
%APPDATA%/qrenderdoc/extensions/renderdoc_mcp/
└── __init__.py # Extension side processing functions (31 methods)
IPC communication directory:
%TEMP%/renderdoc_mcp_ipc/
├── request.json # Request file (temporary)
├── ready # Ready signal (temporary)
└── response.json # Response file (temporary)
```
---
*Manual version: 1.5.0 | Last updated: 2026-04-14*
MCP Config
Below is the configuration for this MCP Server. You can copy it directly to Cursor or other MCP clients.
mcp.json
Connection Info
You Might Also Like
everything-claude-code
Complete Claude Code configuration collection - agents, skills, hooks,...
markitdown
MarkItDown-MCP is a lightweight server for converting URIs to Markdown.
cc-switch
All-in-One Assistant for Claude Code, Codex & Gemini CLI across platforms.
seo-skills
Claude SEO Skills — production Claude Agent Skills for the SE Ranking MCP...
awesome-claude-code-workflows
Curated workflow recipes that combine hooks, MCP servers, skills, agents,...
openclaw-xhs
🔥 Let OpenClaw Understand Your Xiaohongshu — MCP Integration + Hot Topic...