pix-mcp

pix-mcp

Wraps Microsoft PIX's pixtool.exe to enable LLMs to launch and attach to D3D12 processes, capture GPU traces, and perform fine-grained queries (e.g., root parameter bindings at specific events) without manual CSV dumps.

Category
访问服务器

README

pix-mcp

An MCP (Model Context Protocol) server for Microsoft PIX on Windows. It wraps pixtool.exe so an LLM agent can launch and attach to D3D12 processes, take GPU captures, and run fine-grained queries over the resulting .wpix files — including answering questions like "what SRV is bound at root parameter 0 of event 2372?" without you having to dump the entire event list to CSV and grep through C++ export by hand.

Why a wrapper? pixtool.exe is a real scriptable CLI, but its queries are coarse: it dumps the whole event list as CSV, the whole resource as bytes, the whole frame as a C++ project. pix-mcp indexes those coarse outputs into a SQLite DB beside the capture and parses the C++ export, so the LLM can ask precise questions instantly without re-running pixtool.

What it can do

Wraps every command exposed by pixtool.exe:

pixtool command MCP tool
launch (one-shot, capture-and-exit) pix_capture_launched
launch (long-running, F11 in-game) pix_launch_background
attach <pid> + take-capture + save-capture pix_capture_attached
programmatic-capture pix_capture_programmatic
take-capture / save-capture (composed inside the workflows above)
open-capture pix_open_capture (and implicitly chained by every capture-targeting tool)
save-event-list pix_save_event_list
save-resource pix_save_resource
save-screenshot pix_save_screenshot
list-counters pix_list_counters
save-high-frequency-counters pix_save_high_frequency_counters
export-to-cpp pix_export_to_cpp
recapture-region pix_recapture_region
upgrade-gpu-capture pix_upgrade_gpu_capture
any other / chained command pix_raw

And then the value-add — tools that don't have a pixtool equivalent because they operate on an indexed view of the capture:

Tool What it answers
pix_index_events Build a SQLite index from save-event-list CSV.
pix_find_events "All draws inside marker ShadowPass", "all dispatches between events 2000 and 2400", "every ResourceBarrier on queue 1".
pix_get_event Full per-event record including counters, by Global ID.
pix_list_markers All PIX markers with their [start, end] Global IDs.
pix_marker_range Resolve a marker name to its Global ID range.
pix_list_queues Queues seen, with event counts.
pix_event_type_counts Histogram (draws vs dispatches vs barriers vs copies …).
pix_top_by_counter Top N events sorted by a numeric counter (e.g. gpu_duration).
pix_query_sql Read-only SELECT/WITH against the index DB.
pix_parse_cpp_export Parse an existing export-to-cpp directory.
pix_state_at_event Replay the C++ export and return every bound state at a target event.
pix_get_resource_at_root_param "what's at graphics root param N of event G?" — includes structured resource_id + offset when the binding is GetGpuva(rid, off).
pix_find_cpp_calls Search the parsed C++ export for specific D3D12 calls and their exact arguments.
pix_get_root_signature_layout Parse the inline D3D12_ROOT_PARAMETER1 array and return per-slot {kind, visibility, register, register_space, descriptor_ranges, flags} for a given root sig ApiObjectId.
pix_get_resource_bytes Read raw bytes from a resource at (offset, length) by decompressing resources.bin (XPRESS via Windows Cabinet API). Solves the "save-resource only does PNG/DDS" gap.
pix_list_tracked_resources List every resource ID pix_get_resource_bytes can read, with chunk sizes and source-function names.
pix_dump_cbuffer_at_root_param End-to-end "show me these cbuffer bytes": composes state replay + GpuVa parsing + raw-bytes extraction. Returns hex + optional float[] decoding.
pix_capture_summary One-shot high-level overview of a capture.

Install

git clone <this repo> pix-mcp
cd pix-mcp
python -m venv .venv
.venv\Scripts\activate
pip install -e ".[dev]"

Requires Windows and Microsoft PIX installed (default location C:\Program Files\Microsoft PIX\<version>\pixtool.exe). pix-mcp auto-discovers the newest installed version; override with PIX_MCP_PIXTOOL=<full path>.

Quick smoke test:

pix-mcp --help
.venv\Scripts\python.exe -c "from pix_mcp.config import find_pixtool; print(find_pixtool())"

Wiring it into Claude Code / Claude Desktop

Add to your MCP config (claude_desktop_config.json or the CLI equivalent):

{
  "mcpServers": {
    "pix": {
      "command": "E:/github/pix-mcp/.venv/Scripts/pix-mcp.exe",
      "args": [],
      "env": {
        "PIX_MCP_PIXTOOL": "C:/Program Files/Microsoft PIX/2603.25/pixtool.exe"
      }
    }
  }
}

(Set PIX_MCP_PIXTOOL only if auto-discovery isn't finding the right install.)

Typical workflows

1. Capture a launched workload, then analyze it

pix_capture_launched(
    exe="C:/games/MyGame.exe",
    args="-windowed",
    output_wpix="C:/captures/mygame.wpix",
    frames=1,
)

pix_open_capture("C:/captures/mygame.wpix")
pix_index_events(capture="<handle>", counter_groups=["D3D:*"])
pix_capture_summary(capture="<handle>")

2. Interactive game session: launch, press F11 in-game, find the capture

pix_launch_background(exe="C:/games/MyGame.exe", capture_key="F11")
# ...play to the spot, press F11...
pix_find_recent_captures()
pix_open_capture("<path returned above>")
pix_index_events(capture="<handle>")

3. Fine-grained query: "what SRV is bound at root param 0 of event 2372?"

pix_open_capture("C:/captures/mygame.wpix")
pix_export_to_cpp(capture="<handle>", output_dir="C:/captures/mygame_cpp",
                  use_winpixeventruntime=True, use_agility_sdk=True)
pix_get_resource_at_root_param(capture="<handle>", global_id=2372, root_param_index=0)
# →
# {
#   "global_id": 2372,
#   "root_param_index": 0,
#   "pipeline": "graphics",
#   "binding": { "kind": "descriptor_table", "handle": "...", "raw": "..." },
#   "graphics_pso": "...",
#   "graphics_root_signature": "...",
#   "descriptor_heaps": ["..."]
# }

For the full bound state at an event (PSO, root sig, all root params, IB/VB, RTVs, viewports, scissors), use pix_state_at_event.

4. Find every draw inside a PIX marker

pix_marker_range(capture="<h>", marker_name="ShadowPass")
# {"found": true, "start": 2100, "end": 2480}

pix_find_events(capture="<h>", inside_marker="ShadowPass", event_type="draw", limit=50)

5. Top GPU-time draws

pix_index_events(capture="<h>", counters=["GPU Duration"])
pix_top_by_counter(capture="<h>", counter="gpu_duration", n=20, event_type="draw")

6. Recapture just the suspicious region for faster iteration

pix_recapture_region(capture="<h>", output_wpix="C:/captures/mygame_slice.wpix", start=2300, end=2600)

7. Dump raw cbuffer bytes from a draw call (no PIX UI)

pix_export_to_cpp(capture="<h>", output_dir="C:/captures/mygame_cpp",
                  use_winpixeventruntime=True, use_agility_sdk=True)

# One call replaces ~10 PIX-UI clicks:
pix_dump_cbuffer_at_root_param(
    capture="<h>", global_id=2372, root_param_index=3,
    length=256, preview_floats=64,
    output_file="C:/scratch/basepass_cbuffer.bin",
)
# → {
#     "resource_id": 2362,
#     "offset": 2259712,
#     "hex_preview": "00 00 80 3b ...",
#     "preview_floats": [0.00390625, 0.0, ...],
#     "output_file": "C:/scratch/basepass_cbuffer.bin"
# }

For lower-level access:

pix_get_root_signature_layout(capture="<h>", root_sig_obj_id=2361)
# → per-slot {kind, visibility, register, ranges, flags}

pix_get_resource_bytes(capture="<h>", resource_id=2362,
                       offset=2259712, length=256)
pix_list_tracked_resources(capture="<h>")

8. Escape hatch — chain arbitrary pixtool commands

pix_raw(args=[
  "open-capture", "C:/captures/mygame.wpix",
  "save-event-list", "C:/scratch/events.csv", "--counters=*",
  "list-counters",
])

How the index works

The first time you call pix_index_events, pix-mcp runs:

pixtool open-capture <wpix> save-event-list <cache>/<stem>.event_list.csv [--counters=...]

Then it streams the CSV into <wpix>.pixmcp.db (next to the .wpix, or in %LOCALAPPDATA%\pix-mcp\cache\ if that directory isn't writable). Schema:

events(global_id, queue_id, queue, name, event_type, parent_marker_id, depth,
       counters JSON, raw JSON)
markers(id, name, start_global_id, end_global_id, parent_id, depth, queue_id, queue)
queues(queue_id, name, event_count)
counter_columns(name)

event_type is a classified label (draw, dispatch, copy, barrier, begin_marker, end_marker, marker, clear, resolve, present, execute_command_lists, execute_indirect, build_as, other). Markers are reconstructed from PIX's BeginEvent/EndEvent rows with per-queue depth tracking — so pix_find_events(inside_marker="ShadowPass") works.

counters is a JSON object — query it via SQL with json_extract(counters, '$.gpu_duration'). raw is the entire original CSV row for escape-hatch queries.

The index is keyed by the wpix's mtime so it auto-invalidates when you re-capture.

How the state-at-event query works

pix_export_to_cpp(parse_after=True) runs:

pixtool open-capture <wpix> export-to-cpp <dir> [--force --use-winpixeventruntime ...]

then immediately parses every .cpp under <dir>, picking out D3D12 calls with regex. For each call we record (call_index, global_id, method, args, source_file, source_line). global_id is recovered from PIX's // Event <id> comments where present.

pix_state_at_event walks that list up to your target event and replays the state: graphics + compute root signatures, PSO, root parameters (descriptor tables, root CBV/SRV/UAV, root 32-bit constants), descriptor heaps, IB/VB views, RTVs/DSV, viewports/scissors, primitive topology.

For the specific "resource at root param N of event G" question, pix_get_resource_at_root_param returns the exact args string PIX emitted for the last Set*Root* call targeting that slot — so you get the descriptor table base / GPU VA / 32-bit constant payload PIX serialized.

Caveats

  • Windows only. The bridge to pixtool.exe is Win32-native.
  • PIX must be installed. Set PIX_MCP_PIXTOOL if auto-discovery fails.
  • The C++-export parser is regex-based and tolerates PIX's formatting variants — it doesn't compile the export. If a future PIX version reshapes the export significantly, parsing of unrecognized methods will fall back to raw call records (still queryable via pix_find_cpp_calls).
  • "Global ID" in the event list isn't guaranteed to match the call index in the C++ export 1-to-1. We rely on PIX's // Event <id> comments inside the export to associate them. If your PIX version doesn't emit those comments, pass call_index= instead of global_id= to pix_state_at_event and use pix_find_cpp_calls to discover the right call.
  • pix_capture_attached requires WinPix services running; some games block attach until you've launched them through the PIX UI once.

Layout

src/pix_mcp/
  config.py        # PIX install discovery, cache paths
  pixtool.py       # pixtool.exe subprocess wrapper (sync + async + background)
  csv_parser.py    # streaming parser for save-event-list CSV
  index.py         # SQLite indexer + query helpers
  cpp_export.py    # parser + state replay for export-to-cpp;
                   # also root-signature-layout extraction
  resources_bin.py # static call-graph walk over CreateAndInitResource_*
                   # functions + XPRESS decompression of resources.bin
                   # (uses Windows Cabinet API via ctypes)
  session.py       # in-memory capture / launch session registry
  server.py        # FastMCP server with all tools
  __main__.py      # console entry point

License

MIT.

推荐服务器

Baidu Map

Baidu Map

百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。

官方
精选
JavaScript
Playwright MCP Server

Playwright MCP Server

一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。

官方
精选
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。

官方
精选
本地
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。

官方
精选
本地
TypeScript
VeyraX

VeyraX

一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。

官方
精选
本地
graphlit-mcp-server

graphlit-mcp-server

模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。

官方
精选
TypeScript
Kagi MCP Server

Kagi MCP Server

一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。

官方
精选
Python
e2b-mcp-server

e2b-mcp-server

使用 MCP 通过 e2b 运行代码。

官方
精选
Neon MCP Server

Neon MCP Server

用于与 Neon 管理 API 和数据库交互的 MCP 服务器

官方
精选
Exa MCP Server

Exa MCP Server

模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。

官方
精选