# GPA MCP Server

MCP Server for Intel GPA (Graphics Performance Analyzers) frame analysis. Enables Claude to analyze GPU captures, extract textures/shaders/geometry, and collect performance metrics via the MCP protocol.

## Features

- **20 MCP tools** for complete GPU frame reverse engineering
- **DXBC shader disassembly** — automatic extraction of D3D Shader Disassembler output for DX11 captures
- **Three backend modes**: Mock (development), Frame (`.gpa_frame`), Legacy (`GPA.Stream`)
- **Batch export** — deduplicated export of all unique shaders, textures, and geometry from an entire frame
- **GPU metrics** — per-draw-call timing and pipeline statistics

## Quick Start

### Prerequisites

- Python 3.10+
- Intel GPA Framework 2025.1 installed (`C:\Program Files\IntelSWTools\GPA\`)
- MCP SDK: `pip install mcp pydantic pillow numpy`

### Claude Code Configuration

Add to your MCP settings (`.claude/settings.json` or project settings):

```json
{
  "mcpServers": {
    "gpa_mcp": {
      "command": "python",
      "args": ["-m", "gpa_mcp.server"],
      "cwd": "F:/GPA",
      "env": {
        "GPA_INSTALL_DIR": "C:/Program Files/IntelSWTools/GPA",
        "GPA_OUTPUT_DIR": "F:/GPA/gpa_exports"
      }
    }
  }
}
```

### Claude Desktop Configuration

Add to `claude_desktop_config.json`:

```json
{
  "mcpServers": {
    "gpa_mcp": {
      "command": "python",
      "args": ["-m", "gpa_mcp.server"],
      "cwd": "F:/GPA",
      "env": {
        "GPA_INSTALL_DIR": "C:/Program Files/IntelSWTools/GPA",
        "GPA_OUTPUT_DIR": "F:/GPA/gpa_exports"
      }
    }
  }
}
```

### Mock Mode (No GPA Required)

For development/testing without GPA installed:

```json
{
  "env": {
    "GPA_MOCK_MODE": "1"
  }
}
```

## Architecture

```
.gpa_frame  -->  FrameAnalyzer.exe + gpa_export_all plugin  -->  JSON cache (8 files)
                                                                       |
MCP Tool  -->  gpa_loader.open_stream(path)  -->  FrameData  -->  read JSON
```

Three modes are auto-detected based on the input path:

| Mode | Condition | Backend |
|------|-----------|---------|
| Mock | `GPA_MOCK_MODE=1` | Fake data for development |
| Frame | Path ends with `.gpa_frame` | FrameAnalyzer JSON export |
| Legacy | GPA SDK available + stream directory | Native `GPA.Stream` |

## Tools

### Stream Management (stream_tools.py)
| Tool | Description |
|------|-------------|
| `gpa_open_stream` | Open a stream/frame, validate, return basic info |
| `gpa_stream_info` | Get stream metadata, file list, API type |
| `gpa_list_ranges` | List draw call ranges with pagination and filtering |

### Draw Call Analysis (drawcall_tools.py)
| Tool | Description |
|------|-------------|
| `gpa_get_drawcall_detail` | Get API call sequence and parameters for a range |
| `gpa_get_pipeline_state` | Get full pipeline state (shaders, blend, rasterizer, etc.) |
| `gpa_search_api_calls` | Search for specific API calls across the entire stream |

### Resource Export (resource_tools.py)
| Tool | Description |
|------|-------------|
| `gpa_list_bound_resources` | List all GPU resources bound to a draw call |
| `gpa_export_texture` | Export a single texture to PNG/DDS |
| `gpa_batch_export_textures` | Export all textures for a draw call |
| `gpa_export_geometry` | Export geometry as OBJ/CSV |
| `gpa_export_geometry_fbx` | Export geometry with UVs as FBX/OBJ |

### Shader Extraction (shader_tools.py)
| Tool | Description |
|------|-------------|
| `gpa_get_shader_info` | Get shader metadata: hash, model, source availability |
| `gpa_export_shader` | Export shader source/disassembly/bytecode |
| `gpa_batch_export_shaders` | Batch export all unique shaders (deduplicated) |

### GPU Metrics (metrics_tools.py)
| Tool | Description |
|------|-------------|
| `gpa_list_metrics` | List available GPU performance metrics |
| `gpa_collect_metrics` | Collect metrics for a specific draw call |
| `gpa_export_metrics_report` | Export GPU timing report (top-N expensive calls) |

### Export & Utilities (export_tools.py)
| Tool | Description |
|------|-------------|
| `gpa_full_export` | One-click export of all resources for a draw call |
| `gpa_cli_wrapper` | Run official GPA CLI tools (FrameAnalyzer, etc.) |
| `gpa_list_exports` | List all exported files grouped by type |

## Shader Disassembly

For DX11 captures, HLSL source code is typically unavailable (requires debug info at capture time). The server automatically falls back to DXBC disassembly:

**Source priority:**
1. HLSL source (if debug info was enabled during capture)
2. DXBC disassembly (DX11 default — from `prog.get_description()[stage]["dxbc"]`)
3. DXIL disassembly (DX12 captures)
4. ISA disassembly (Intel GPU only)

When `output_type="source"` returns DXBC disassembly instead of HLSL, the file extension is automatically set to `.asm` (not `.hlsl`).

Example DXBC disassembly output:
```asm
//
// Generated by Microsoft (R) D3D Shader Disassembler
//
// Input signature:
//
// Name                 Index   Mask Register SysValue  Format   Used
// -------------------- ----- ------ -------- -------- ------- ------
// SV_Position              0   xyzw        0      POS   float
// SV_IsFrontFace           0   x           1    FFACE    uint   x
//
ps_5_0
dcl_globalFlags refactoringAllowed
dcl_constantbuffer CB0[159], immediateIndexed
dcl_input_ps_sgv constant v1.x, is_front_face
dcl_output o0.xyzw
and r0.x, cb1[0].x, l(64)
movc r0.x, r0.x, l(-1.000000), l(1.000000)
mul r0.x, r0.x, cb0[158].w
discard_nz r0.x
mov o0.xyzw, l(0,0,0,0)
ret
```

## Example Workflow

```
# Analyze a VALORANT DX11 frame capture

1. gpa_stream_info(stream_path="path/to/VALORANT.gpa_frame")
   -> First open triggers FrameAnalyzer export (~30s)
   -> 12,791 ranges, 886 draw call events

2. gpa_list_ranges(start=665, count=10)
   -> Browse draw calls, find target DrawIndexed

3. gpa_get_shader_info(range_index=669)
   -> vertex: hash=319abd7168826503, has_source=True, lang=DXBC
   -> pixel:  hash=950c23be14e49ee1, has_source=True, lang=DXBC

4. gpa_export_shader(range_index=669, stage="pixel", output_type="source")
   -> Export DXBC disassembly to ps_950c23be14e49ee1.asm

5. gpa_batch_export_shaders(output_type="disasm", deduplicate=True)
   -> Export 199 unique shaders (62 VS + 137 PS), skipped 1540 duplicates

6. gpa_collect_metrics(range_index=669, metric_names=["GpuTime"])
   -> GpuTime: 21.00 us
```

## Project Structure

```
gpa_mcp/
├── server.py              # Entry point, registers all 20 tools
├── requirements.txt       # Dependencies: mcp, pydantic, pillow, numpy
├── tools/
│   ├── stream_tools.py    # Module 1: Stream management (3 tools)
│   ├── drawcall_tools.py  # Module 2: Draw call analysis (3 tools)
│   ├── resource_tools.py  # Module 3: Resource export (5 tools)
│   ├── shader_tools.py    # Module 4: Shader extraction (3 tools)
│   ├── metrics_tools.py   # Module 5: GPU metrics (3 tools)
│   └── export_tools.py    # Module 6: Export utilities (3 tools)
├── utils/
│   ├── gpa_loader.py      # Three-mode loader (Mock/Frame/Legacy)
│   ├── frame_loader.py    # Frame mode: FrameData reads JSON cache
│   └── formatting.py      # Unified JSON response formatting
└── fa_plugins/            # FrameAnalyzer Python plugins
    ├── gpa_export_all/    # Full frame export (8 JSON files)
    ├── gpa_export_texture/ # On-demand texture pixel export
    └── gpa_export_buffer/  # On-demand buffer data export
```

## Environment Variables

| Variable | Default | Description |
|----------|---------|-------------|
| `GPA_INSTALL_DIR` | `C:\Program Files\IntelSWTools\GPA` | GPA installation root |
| `GPA_TOOLS_DIR` | Same as above | GPA CLI tools path |
| `GPA_OUTPUT_DIR` | `./gpa_exports` | Root directory for all exports |
| `GPA_MOCK_MODE` | `0` | Set to `1` for mock mode (no GPA needed) |
| `GPA_FRAME_ANALYZER` | `<GPA_INSTALL_DIR>/FrameAnalyzer.exe` | FrameAnalyzer executable |
| `GPA_PLUGINS_DIR` | `gpa_mcp/fa_plugins/` | FrameAnalyzer plugin directory |
| `GPA_FRAME_CACHE_DIR` | `<GPA_OUTPUT_DIR>/frame_cache/` | JSON cache root directory |

## Known Limitations

- **DX11 captures have no HLSL source** — DXBC disassembly is used instead (automatic fallback, `.asm` extension)
- **ISA disassembly requires Intel GPU** — non-Intel GPUs get "participating driver" error
- **Texture/geometry export requires FrameAnalyzer** — on-demand FA plugin calls are slow (~30s startup per invocation)
- **Frame header metadata is empty** — FrameAnalyzer plugin API does not expose frame header info (GPU name, resolution, etc.)
- **GPA 2025.1 is the final version** — Intel has announced end-of-life in 2026

## References

- [GPA Python API](https://intel.github.io/gpasdk-doc/src/python.html)
- [GPA Samples](https://intel.github.io/gpasdk-doc/src/samples.html)
- [GPA CLI Utilities](https://intel.github.io/gpasdk-doc/src/utilities.html)
- [GPA Layer Parameters](https://intel.github.io/gpasdk-doc/src/layers.html)
