This guide covers the internal architecture, project structure, and build/test workflow for contributors to zRover.
For Retriever-specific development (build, sign, deploy the MSIX service) see the Retriever Developer Guide.
MCP Client (tests, AI agents, etc.)
│
│ HTTP Streamable MCP (port 5100)
▼
┌──────────────────────────────────┐
│ zRover.FullTrust.McpServer │ .NET 8 console app
│ ASP.NET Core MapMcp("/mcp") │ Runs as FullTrust process
│ │
│ AppServiceConnection IPC │
└──────────┬───────────────────────┘
│ ValueSet messages
│ (ping, list_tools, invoke_tool)
▼
┌──────────────────────────────────┐
│ zRover.Uwp.Sample │ UWP AppContainer
│ ├─ App.xaml.cs │ In-process AppService handler
│ │ OnBackgroundActivated() │
│ │ │
│ ├─ DebugHost / DebugHostRunner │ Orchestrates capabilities
│ │ │
│ ├─ ToolRegistry (singleton) │ Thread-safe tool lookup
│ │ │
│ └─ Capabilities │
│ ├─ ScreenshotCapability │ Windows.Graphics.Capture → PNG (RTB fallback)
│ ├─ InputInjectionCapability │ InputInjector + Win32 SendInput
│ ├─ LoggingCapability │ In-memory ring buffer (get_logs)
│ ├─ AppActionCapability │ Delegates to IActionableApp
│ ├─ UiTreeCapability │ XAML VisualTreeHelper walker
│ ├─ WindowCapability │ ApplicationView resize
│ └─ WaitForCapability │ visual_stable / log_match polling
└──────────────────────────────────┘
- Client sends MCP
tools/callvia HTTP to:5100/mcp - FullTrust server receives it, looks up the proxy tool, sends an AppService IPC message
- UWP app's
OnBackgroundActivateddispatches toToolRegistry - The capability handler runs (e.g. captures screenshot on UI thread)
- JSON result flows back: capability → AppService → FullTrust → MCP HTTP response
| Project | Target | Purpose |
|---|---|---|
| zRover.Core | netstandard2.0 | Interfaces (IDebugCapability, IMcpToolRegistry, IToolBackend), DTOs, coordinate types |
| zRover.Mcp | netstandard2.0 | MCP SDK adapter — bridges IMcpToolRegistry to McpServerTool via DelegateMcpServerTool |
| zRover.Uwp | UAP 10.0.19041 | UWP class library — debug host, capabilities, AppService handler, coordinate resolver |
| zRover.Uwp.Sample | UAP 10.0.19041 | Sample UWP app with Color Picker test UI for E2E testing |
| zRover.WinUI | net8.0-windows10.0.19041.0 | WinUI 3 (Windows App SDK) class library — same capabilities as zRover.Uwp but the MCP server runs in-process, no FullTrust companion required |
| zRover.WinUI.Sample | net8.0-windows10.0.19041.0 | Sample WinUI 3 app for E2E testing of the in-process integration |
| zRover.FullTrust.McpServer | net8.0-windows | Out-of-process MCP HTTP server, bridges to UWP via AppService IPC |
| zRover.Retriever | net9.0-windows | Packaged WinAppSDK service: MCP endpoint (port 5200), package management, session federation. See Retriever Developer Guide |
| zRover.Mcp.IntegrationTests | net8.0 | 55 xUnit tests (unit + E2E) |
- Windows 10/11 (Desktop)
- Visual Studio 2022 with the UWP workload (for the UWP library and sample) and the Windows App SDK / WinUI 3 workload (for the WinUI library and sample)
- .NET 9 SDK (required for the Retriever; .NET 8 SDK also needed for the FullTrust server and the WinUI library)
- Developer Mode enabled in Windows Settings → Privacy & Security → For Developers
All commands assume the working directory is the repository root.
The steps below cover the UWP sample, which exercises the FullTrust + AppService IPC path. To work on the WinUI 3 library instead, use src/zRover.WinUI.Sample/deploy-dev.ps1 which builds, signs, and installs zRover.WinUI.Sample as a dev MSIX (the in-process model has no FullTrust companion to sync).
# Resolve devenv.exe via vswhere (works for any VS edition/version)
$devenv = & "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe" `
-latest -requires Microsoft.Component.MSBuild -find Common7\IDE\devenv.exe
# Rebuild (compiles zRover.Uwp + zRover.Uwp.Sample; post-build target syncs FullTrust output into AppX\FullTrust\)
& $devenv src\zRover.sln /Rebuild "Debug|x64" /Project "zRover.Uwp.Sample\zRover.Uwp.Sample.csproj"
# Deploy (registers the AppX package for sideloading)
& $devenv src\zRover.sln /Deploy "Debug|x64" /Project "zRover.Uwp.Sample\zRover.Uwp.Sample.csproj"Important: Always use
devenv /Deployfor deployment. ManualAdd-AppxPackage -Registerwith file copying to the AppX directory is unreliable because thebin\x64\Debug\AppXsubdirectory may contain stale files.
Start-Process "shell:AppsFolder\zRover.Uwp.Sample_xaf3bmhg52ma0!App"The app starts the debug host and launches the FullTrust MCP server automatically. Wait a few seconds, then verify:
Test-NetConnection -ComputerName localhost -Port 5100 | Select-Object TcpTestSucceededdotnet test src\zRover.Mcp.IntegrationTests\zRover.Mcp.IntegrationTests.csproj `
--filter "McpServerToolTests|McpToolRegistryAdapterTests|DelegateMcpServerToolInvocationTests|AppActionMcpHandlerTests"Runs 27 tests that exercise the MCP adapter and App Action protocol handlers in isolation. No UWP app required.
dotnet test src\zRover.Mcp.IntegrationTests\zRover.Mcp.IntegrationTests.csproj `
--filter "EndToEndPipelineTests|ColorPickerE2ETests"Runs 28 tests that connect to the live MCP server. Requires the UWP app to be deployed, launched, and listening on port 5100.
dotnet test src\zRover.Mcp.IntegrationTests\zRover.Mcp.IntegrationTests.csprojRuns all 55 tests. The E2E tests will fail if the app isn't running.
$devenv = & "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe" `
-latest -requires Microsoft.Component.MSBuild -find Common7\IDE\devenv.exe
# 1. Rebuild UWP app (post-build target auto-syncs FullTrust build output into AppX)
& $devenv src\zRover.sln /Rebuild "Debug|x64" /Project "zRover.Uwp.Sample\zRover.Uwp.Sample.csproj"
# 2. Deploy
& $devenv src\zRover.sln /Deploy "Debug|x64" /Project "zRover.Uwp.Sample\zRover.Uwp.Sample.csproj"
# 3. Launch app and wait for MCP server
Start-Process "shell:AppsFolder\zRover.Uwp.Sample_xaf3bmhg52ma0!App"
Start-Sleep -Seconds 5
# 4. Run all tests
dotnet test src\zRover.Mcp.IntegrationTests\zRover.Mcp.IntegrationTests.csprojThe E2E tests default to http://localhost:5100/mcp. Override with:
$env:ZROVER_MCP_ENDPOINT = "http://localhost:5100/mcp"- Non-XAML platforms — no WPF or Win32 adapter; UWP and WinUI 3 only