MCP Server
July 27, 2026 · View on GitHub
D3D12LookDevPTWinUI includes a local MCP server for inspecting and controlling the running renderer from tools such as VS Code, Codex, or custom JSON-RPC clients. The server and WinUI editor share the same validation-oriented renderer-command layer.
Japanese documentation: MCP サーバー
MCP-Driven Workflow Example
An MCP-capable client can issue camera, quality, material, or denoise requests. The WinUI MCP panel shows sessions, pending approvals, and recent local JSON-RPC requests. Do not commit real MCP tokens in screenshots or project files.
The client should validate settings first, apply mutation tools, then read state back to confirm that the renderer accepted the same values. Treat the live schema returned by tools/list or lookdevpt://actions/schema—and the examples below—as authoritative for the current build.
Availability And Security
- Endpoint:
http://127.0.0.1:<port>/mcp - Default port:
8777 - Bind address:
127.0.0.1only - Transport: Streamable HTTP-style JSON-RPC over
POST /mcp - Protocol versions accepted:
2025-11-25,2025-06-18 - Authentication:
Authorization: Bearer <token>is required - Session:
initializereturnsMCP-Session-Id; all later requests must send it - Server-Sent Events: not implemented;
GET /mcpreturns405 Method Not Allowed - Maximum HTTP request body: 16 MiB
The bearer token and MCP settings are stored in:
%APPDATA%\D3D12LookDevPTWinUI\settings.json
This file is user-local. Do not copy the token into .lookdevpt.json, README files, screenshots, issue comments, or committed VS Code settings.
The server accepts browser/client Origin values only when absent, null, http://127.0.0.1:*, or http://localhost:*. Other origins are rejected with 403.
Starting The Server
Use the dockable MCP Server panel:
Start Server/Stop ServerPortRequest TimeoutAccess ModeCopy TokenRegenerate Token- pending approvals and recent request log
The server is disabled by default. It can also be started from the command line:
.\Bin\x64\Debug\D3D12LookDevPTWinUI.exe --mcp-server --mcp-port 8777 --mcp-token <token> --mcp-access confirm_mutations
Access modes:
read_only: read tools work; mutation tools are rejected.confirm_mutations: mutation tools wait for approval in the WinUIMCPpanel.allow_mutations: mutation tools execute without UI approval.
The mutation queue is processed at a renderer-thread safe point and has a limit of 16 queued requests. Mutations never touch D3D12 or WinUI state directly from the HTTP server thread.
capture_viewport is a read operation, but it is still queued on the renderer thread because it performs a GPU readback. capture_debug_pack temporarily changes the debug view and invalidates its related temporal history, so it requires mutation access (and approval in confirm_mutations mode). Its restoreView option defaults to true.
Snapshot Cadence And Freshness
MCP reads use mutex-protected snapshots rather than walking renderer or scene data on the HTTP thread. Snapshot work is disabled while the server is stopped. Starting the server forces an initial snapshot; while it is running:
stateis refreshed about every 33 ms (30 Hz).statsanddiagnosticsare refreshed about every 100 ms (10 Hz).materials,project,scene/summary, material variants, and presets are rebuilt only when their scene/project/catalog revisions change.- Debug-view, render-mode, and action-schema resources are generated from fixed metadata on demand.
A read immediately following a mutation can therefore normally trail the renderer by one refresh interval. If a client must verify a value, read get_state again after that interval while the renderer is advancing frames. Mutation, validation, and capture operations are serialized through the renderer command queue; ordinary immutable snapshot reads do not block renderer state mutation.
VS Code Configuration
VS Code stores MCP server configuration in mcp.json, either in .vscode/mcp.json or in the user profile. VS Code's current MCP configuration reference uses type, url, and headers for HTTP servers, with optional inputs for secrets.
Example .vscode/mcp.json:
{
"inputs": [
{
"type": "promptString",
"id": "lookdevpt-token",
"description": "D3D12LookDevPTWinUI MCP bearer token",
"password": true
}
],
"servers": {
"d3d12LookDevPT": {
"type": "http",
"url": "http://127.0.0.1:8777/mcp",
"headers": {
"Authorization": "Bearer ${input:lookdevpt-token}",
"MCP-Protocol-Version": "2025-11-25"
}
}
}
}
Use MCP: List Servers to start or restart the server entry after editing the file. Use MCP: Reset Cached Tools if the tool list changes after rebuilding D3D12LookDevPTWinUI.
Notes:
- Start D3D12LookDevPTWinUI and its MCP server before starting the VS Code MCP entry.
- If the token is regenerated in the WinUI MCP panel, restart the VS Code MCP server entry and enter the new token.
- This server supports HTTP POST JSON-RPC. Clients that require SSE-only MCP will not work.
JSON-RPC Flow
Every client should initialize first, keep the returned session id, then send notifications/initialized.
PowerShell example:
$endpoint = "http://127.0.0.1:8777/mcp"
$token = "<token>"
$headers = @{
"Authorization" = "Bearer $token"
"MCP-Protocol-Version" = "2025-11-25"
}
$initBody = @{
jsonrpc = "2.0"
id = 1
method = "initialize"
params = @{
protocolVersion = "2025-11-25"
capabilities = @{}
clientInfo = @{ name = "manual-client"; version = "1.0" }
}
} | ConvertTo-Json -Depth 10 -Compress
$init = Invoke-WebRequest -Uri $endpoint -Method Post -Headers $headers -ContentType "application/json" -Body $initBody
$sessionId = [string]$init.Headers["MCP-Session-Id"][0]
$sessionHeaders = @{
"Authorization" = "Bearer $token"
"MCP-Protocol-Version" = "2025-11-25"
"MCP-Session-Id" = $sessionId
}
$initialized = @{
jsonrpc = "2.0"
method = "notifications/initialized"
params = @{}
} | ConvertTo-Json -Depth 10 -Compress
Invoke-WebRequest -Uri $endpoint -Method Post -Headers $sessionHeaders -ContentType "application/json" -Body $initialized
Call a read tool:
$body = @{
jsonrpc = "2.0"
id = 2
method = "tools/call"
params = @{
name = "lookdevpt.get_state"
arguments = @{}
}
} | ConvertTo-Json -Depth 10 -Compress
Invoke-WebRequest -Uri $endpoint -Method Post -Headers $sessionHeaders -ContentType "application/json" -Body $body
End a session:
Invoke-WebRequest -Uri $endpoint -Method Delete -Headers $sessionHeaders
Tools
Read tools:
lookdevpt.get_stats: returns adapter, DXR tier, resolution, aggregate GPU timing, scene counts, history/resource-memory status, active secondary shading rate, denoiser status, and MCP queue state.lookdevpt.get_state: returns scene/project paths, quality and ray-budget settings, camera, lighting, path tracing, ReSTIR/RTXDI status, denoise, frame-history revisions, and view state.lookdevpt.list_materials: returns material names, usage counts, editable PBR factors, and texture slot state.lookdevpt.list_debug_views: returns debug view ids, labels, and keys.lookdevpt.list_render_modes: returns render mode labels and action values.lookdevpt.get_diagnostics: returns scene/project/capture/MCP diagnostics.lookdevpt.capture_viewport: captures the current final/debug viewport as PNG and returns an inlineimage/pngpluslookdevpt://captures/latest.png.
Validation and capture workflow tools:
lookdevpt.validate_action: accepts{ "method": "...", "params": { ... } }and runs the same action path withvalidateOnly=true.lookdevpt.run_actions: validates and applies up to 16 action-layer calls as one MCP request. Validation failure prevents all mutation. Application is ordered but not rollback-transactional if a later runtime operation fails.lookdevpt.capture_debug_pack: captures up to eight debug views and returns resource links for each PNG. It is treated as a mutation because it changes debug-view/history state while capturing.
Mutation tools:
lookdevpt.reset_accumulationlookdevpt.reset_denoise_historylookdevpt.reset_reservoirslookdevpt.reset_camera_viewlookdevpt.set_camera_speedlookdevpt.fit_camera_to_scenelookdevpt.set_display_resolutionlookdevpt.load_projectlookdevpt.save_projectlookdevpt.save_project_aslookdevpt.set_scenelookdevpt.set_cameralookdevpt.set_materiallookdevpt.set_material_texturelookdevpt.reset_materiallookdevpt.save_material_variantlookdevpt.apply_material_variantlookdevpt.delete_material_variantlookdevpt.set_material_viewlookdevpt.set_color_managementlookdevpt.set_lightinglookdevpt.set_path_tracinglookdevpt.set_qualitylookdevpt.set_restirlookdevpt.set_denoiselookdevpt.set_view
Tool results primarily use structuredContent. A text content summary is also included for compatibility.
Resources
lookdevpt://state: current state JSON.lookdevpt://stats: current stats JSON.lookdevpt://diagnostics: scene, project, capture, and MCP diagnostics.lookdevpt://materials: material list JSON.lookdevpt://materials/{index}: one material object.lookdevpt://materials/{index}/textures: source/current/override texture slots for one material.lookdevpt://material-variants: saved per-material variant snapshots.lookdevpt://material-presets: built-in and user material presets.lookdevpt://debug-views: debug view ids, labels, and keys.lookdevpt://render-modes: render modes andset_path_tracing.modevalues.lookdevpt://project: current project path and dirty flag.lookdevpt://scene/summary: scene counts, bounds, lights, and asset paths.lookdevpt://actions/schema: action names and JSON input schemas.lookdevpt://captures/index: in-memory capture history.lookdevpt://captures/latest.png: most recent PNG capture.lookdevpt://captures/{id}.png: PNG fromcapture_viewportorcapture_debug_pack.
Resource templates:
lookdevpt://captures/{id}.pnglookdevpt://materials/{index}lookdevpt://materials/{index}/textures
Prompts:
lookdevpt.inspect_scene: read state/stats/materials/diagnostics and summarize the scene.lookdevpt.tune_denoise: propose and apply stable denoise settings through validation.lookdevpt.setup_camera_shot: fit/refine a camera shot using scene bounds and state.lookdevpt.capture_debug_review: capture a debug pack and summarize visible issues.
State, Stats, And Benchmark Metrics
Important get_state fields added for the stability/performance pipeline are:
quality: the stored/requestedqualityProfile,restirBackend,secondaryShadingRate, completerayBudget,finalTaa,sharpenStrength, andreferenceSpppolicy object. Profile- and availability-dependent results are reported separately byfinalTaaActive,restir.effective, anddenoise.activeBackend.finalTaaActive: whether the selected profile and available pipeline are actually running Final TAA.pathTracing.requestedSecondaryShadingRate,activeSecondaryRate, andautoSecondaryHalfActive: requested policy versus the currently active secondary rate.restir.requestedBackend,effective, andrtxdiStatus: requested RTXDI path, compiled/runtime availability, active DI/GI state, and fallback reason.frameState: frame/sample counters, change mask, valid history-domain mask, camera-cut flag, and independent scene/geometry/material/light/HDRI/backend/profile revisions.
Important get_stats groups are:
gpuTiming: last completed aggregate pipeline, Path Trace, ReSTIR reuse, denoise, copy, and UI timings, together with validity and completion serial.historyDomains: valid history mask and the last change mask.resourceMemory: frame/history bytes and MiB, the 512 MiB budget, budget status, and active allocation profile.secondaryShading: requested/effective rate, active ratio, automatic half-rate state, additional-sample quota, bounce penalty, and over/under-budget counters.denoiserandmcp: effective backend/history status and server queue state.
The benchmark CSV/JSON artifacts contain the heavier per-phase metrics—ReSTIR candidate/temporal/spatial/shade/publish, denoise prepare/core/composite, Final TAA, quality counters, history publish, detailed CPU stages, estimated ray budgets, and history/contribution diagnostics. get_stats intentionally remains a lower-cost aggregate snapshot. In a performance benchmark, full-screen quality counters are disabled; use a quality or combined run when those counters are required.
Example resource read:
{
"jsonrpc": "2.0",
"id": 3,
"method": "resources/read",
"params": {
"uri": "lookdevpt://actions/schema"
}
}
Common Operations
Get camera:
{
"jsonrpc": "2.0",
"id": 10,
"method": "tools/call",
"params": {
"name": "lookdevpt.get_state",
"arguments": {}
}
}
Set camera:
{
"jsonrpc": "2.0",
"id": 11,
"method": "tools/call",
"params": {
"name": "lookdevpt.set_camera",
"arguments": {
"position": [-14.7075, 7.99065, -11.7407],
"yaw": 0.456,
"pitch": -0.144733,
"historyMode": "auto"
}
}
}
historyMode controls only this camera mutation:
auto(default): preserve and reproject history for ordinary motion, but classify a large teleport/turn as a camera cut.preserve: force reprojection even when the automatic cut threshold would be exceeded. Use only when the previous and new views are intentionally continuous.reset: mark an explicit camera cut and reject temporal history for the new frame.
Load Bistro:
{
"jsonrpc": "2.0",
"id": 12,
"method": "tools/call",
"params": {
"name": "lookdevpt.set_scene",
"arguments": {
"scenePath": "C:\\Projects\\D3D12LookDevPTWinUI\\Bistro_v5_2\\BistroExterior.fbx"
}
}
}
Set ReSTIR GI + DI:
{
"jsonrpc": "2.0",
"id": 13,
"method": "tools/call",
"params": {
"name": "lookdevpt.set_path_tracing",
"arguments": {
"mode": "restir_gi_di",
"samplesPerFrame": 2,
"maxBounces": 4,
"radianceClamp": 8.0
}
}
}
Set the interactive quality profile and automatic secondary shading budget:
{
"jsonrpc": "2.0",
"id": 14,
"method": "tools/call",
"params": {
"name": "lookdevpt.set_quality",
"arguments": {
"qualityProfile": "interactive_game",
"restirBackend": "rtxdi",
"secondaryShadingRate": "auto",
"rayBudget": {
"movingSpp": 1,
"movingBounces": 2,
"staticBaseSpp": 1,
"staticMaxSpp": 2,
"staticBounces": 4,
"settleFrames": 8,
"targetGpuMs": 14.5
},
"finalTaa": true,
"sharpenStrength": 0.15,
"referenceSpp": 4096
}
}
}
secondaryShadingRate accepts auto, full, or adaptive_half. auto spends the additional-sample quota and then reduces bounce depth before enabling half-rate secondary shading after sustained budget overruns; recovery occurs only after a sustained under-budget period. adaptive_half forces the interactive secondary path to half rate, while full disables it. Sharp Preview and Reference Still always resolve this field to full. Partial set_quality calls preserve unspecified values, but changing profiles applies that profile's renderer/denoiser defaults and resets the affected histories.
Set the interactive denoise preset:
{
"jsonrpc": "2.0",
"id": 14,
"method": "tools/call",
"params": {
"name": "lookdevpt.set_denoise",
"arguments": {
"preset": "interactive_stable",
"temporalStability": true,
"jitterMode": "stable32",
"movingJitterScale": 0.25,
"resetHistory": true
}
}
}
Select NRD REBLUR. When the NRD SDK and D3D12 evaluation resources are available, this becomes the active backend; otherwise the renderer safely falls back to the internal denoiser. Inspect denoise.activeBackend and denoise.nrd.fallbackReason from lookdevpt.get_state for the effective path. More setup notes are in Optional NVIDIA NRD Backend.
{
"jsonrpc": "2.0",
"id": 15,
"method": "tools/call",
"params": {
"name": "lookdevpt.set_denoise",
"arguments": {
"backend": "nrd_reblur",
"resetNrd": true
}
}
}
Select DLSS Ray Reconstruction when available. Unsupported machines keep the selected backend but fall back to the internal denoiser; read denoise.dlss.fallbackReason from lookdevpt.get_state for details. More setup notes are in Optional DLSS Ray Reconstruction.
{
"jsonrpc": "2.0",
"id": 16,
"method": "tools/call",
"params": {
"name": "lookdevpt.set_denoise",
"arguments": {
"backend": "dlss_rr",
"dlssMode": "quality",
"resetDlss": true
}
}
}
Set material factors:
{
"jsonrpc": "2.0",
"id": 17,
"method": "tools/call",
"params": {
"name": "lookdevpt.set_material",
"arguments": {
"index": 0,
"baseColor": [0.9, 0.76, 0.54, 1.0],
"roughness": 0.42,
"metallic": 0.0
}
}
}
Override or clear a material texture slot:
{
"jsonrpc": "2.0",
"id": 16,
"method": "tools/call",
"params": {
"name": "lookdevpt.set_material_texture",
"arguments": {
"index": 0,
"slot": "baseColor",
"path": "D:\\LookDevTextures\\paint_basecolor.png"
}
}
}
Use "clear": true to remove the slot override, or "resetToSource": true to restore the imported source texture for that slot.
Save and apply a material variant:
{
"jsonrpc": "2.0",
"id": 17,
"method": "tools/call",
"params": {
"name": "lookdevpt.save_material_variant",
"arguments": {
"index": 0,
"variant": "warm rough"
}
}
}
{
"jsonrpc": "2.0",
"id": 18,
"method": "tools/call",
"params": {
"name": "lookdevpt.apply_material_variant",
"arguments": {
"index": 0,
"variant": "warm rough"
}
}
}
Focus one material and adjust the final view transform:
{
"jsonrpc": "2.0",
"id": 19,
"method": "tools/call",
"params": {
"name": "lookdevpt.run_actions",
"arguments": {
"actions": [
{
"method": "set_material_view",
"params": { "selectedMaterial": 0, "focusMode": "dim" }
},
{
"method": "set_color_management",
"params": { "toneMapper": "aces", "exposure": 0.0, "gamma": 2.2 }
}
],
"validateOnly": false,
"stopOnError": true
}
}
}
Capture the viewport:
{
"jsonrpc": "2.0",
"id": 20,
"method": "tools/call",
"params": {
"name": "lookdevpt.capture_viewport",
"arguments": {}
}
}
Run a validated batch:
{
"jsonrpc": "2.0",
"id": 21,
"method": "tools/call",
"params": {
"name": "lookdevpt.run_actions",
"arguments": {
"actions": [
{
"method": "set_path_tracing",
"params": { "mode": "restir_gi_di", "samplesPerFrame": 2 }
},
{
"method": "set_denoise",
"params": { "preset": "interactive_stable", "resetHistory": true }
}
],
"validateOnly": false,
"stopOnError": true
}
}
}
Capture a debug review pack:
{
"jsonrpc": "2.0",
"id": 22,
"method": "tools/call",
"params": {
"name": "lookdevpt.capture_debug_pack",
"arguments": {
"views": [
"Final",
"Base Color",
"World Normal",
"Roughness",
"Metallic",
"Direct Signal",
"Indirect Signal",
"History Confidence"
]
}
}
}
Save a project without a dialog:
{
"jsonrpc": "2.0",
"id": 23,
"method": "tools/call",
"params": {
"name": "lookdevpt.save_project_as",
"arguments": {
"path": "C:\\Projects\\D3D12LookDevPTWinUI\\projects\\bistro.lookdevpt.json"
}
}
}
Troubleshooting
401 Unauthorized: token mismatch. Copy the token from the WinUIMCPpanel and restart the client connection.403 Forbidden: client sent a disallowedOriginheader.400 Unsupported MCP-Protocol-Version: use2025-11-25or2025-06-18.400 MCP-Session-Id is required: callinitializefirst, then send the returnedMCP-Session-Id.404 Unknown MCP session: the session was deleted or the app/server restarted. Initialize again.405 Method Not AllowedonGET: expected; this server does not implement SSE.- Mutation request hangs in
confirm_mutations: approve or reject it in the WinUIMCPpanel before the request timeout. MCP mutation queue is full: wait for pending requests to finish, approve/reject pending mutations, or restart the server.- A state/stat read appears stale after a successful mutation: wait 33 ms for state or 100 ms for stats/diagnostics, then read again.
capture_debug_packis rejected inread_onlyor waits inconfirm_mutations: the tool temporarily changes debug-view/history state and therefore requires mutation access/approval.lookdevpt://captures/latest.pngfails: calllookdevpt.capture_viewportonce before reading the resource.