lewing.helix.mcp
0.2.1
See the version list below for details.
{ "servers": { "lewing.helix.mcp": { "type": "stdio", "command": "dnx", "args": ["lewing.helix.mcp@0.2.1", "--yes"] } } }
.vscode/mcp.json settings file.
dotnet tool install --global lewing.helix.mcp --version 0.2.1
dotnet new tool-manifest
dotnet tool install --local lewing.helix.mcp --version 0.2.1
#tool dotnet:?package=lewing.helix.mcp&version=0.2.1
nuke :add-package lewing.helix.mcp --version 0.2.1
helix.mcp — MCP server and CLI for investigating .NET Helix CI failures
An MCP server that exposes the .NET Helix API as 13 structured tools with cross-process local caching — purpose-built for AI agents diagnosing CI failures in dotnet repos (runtime, sdk, aspnetcore, etc.). Also works as a standalone CLI for humans.
Built with Squad — meet the squad.
Why hlx?
When an AI agent investigates a CI failure in a dotnet repo, it needs to inspect Helix test artifacts — console logs, TRX test results, binlogs, crash dumps. The raw Helix API returns unstructured blobs that agents must download and parse, burning context window on boilerplate extraction. If multiple agents (or the same agent across tool calls) look at the same job, each one repeats the same API calls and downloads.
hlx solves this by wrapping the Helix API as MCP tools that return structured, pre-parsed data:
- Structured output —
hlx_statusreturns categorized failure summaries as JSON;hlx_test_resultsparses TRX files and returns test names, outcomes, and error messages directly. No raw text parsing needed. - Cross-process caching — API responses and downloaded artifacts are cached in a local SQLite database. Different MCP server instances (one per IDE/agent) share the same cache, so the second agent to inspect a job gets instant results. TTLs are smart — running jobs cache briefly (15–30s), completed jobs cache for hours.
- Context-efficient —
hlx_search_logandhlx_search_filesearch in place and return matching lines with context, so agents never need to download a full log.hlx_find_fileslocates artifacts across work items without listing every file. - Zero config — public dotnet CI jobs work out of the box. Install and go.
ci-analysis replacement: hlx provides 100% coverage of the Helix API surface used by the
ci-analysisskill's ~150 lines of PowerShell, with structured caching, failure categorization, and MCP tool support on top.
Architecture
The project is split into three layers:
- HelixTool.Core — Shared library containing
HelixService,IHelixApiClient, and model types. All Helix API logic lives here. - HelixTool — CLI tool built with ConsoleAppFramework. Serves both human-readable terminal commands and a stdio MCP server (
hlx mcp). MCP is also the default mode when no subcommand is given. - HelixTool.Mcp — Standalone MCP HTTP server built with ModelContextProtocol. Returns structured JSON for LLM agents over HTTP.
Both the CLI and MCP server depend on Core but not on each other.
Installation
Run with dnx (no install needed)
dnx (new in .NET 10) auto-downloads and runs NuGet tool packages — no install step required:
dnx lewing.helix.mcp
This is the recommended approach for MCP server configuration (see below). No explicit mcp subcommand is needed — MCP mode is the default when no command is specified.
Install as Global Tool
dotnet tool install -g lewing.helix.mcp
For repo-local installation via a tool manifest:
dotnet new tool-manifest # if .config/dotnet-tools.json doesn't exist
dotnet tool install --local lewing.helix.mcp
Install from Local Build
dotnet pack src/HelixTool
dotnet tool install -g --add-source src/HelixTool/nupkg lewing.helix.mcp
After installation, hlx is available globally.
Build from Source
# Prerequisites: .NET 10 SDK
git clone https://github.com/lewing/helix.mcp.git
cd helix.mcp
dotnet build
NuGet feed requirement: The
Microsoft.DotNet.Helix.ClientSDK package is published to the dotnet-eng Azure Artifacts feed. The includednuget.configreferences this feed. If you see restore errors forMicrosoft.DotNet.Helix.Client, ensure the feed is accessible.
Quick Start
CLI
After installing lewing.helix.mcp as a global or local tool, the hlx command is available:
# Check a Helix job (shows failed work items by default)
hlx status 02d8bd09-9400-4e86-8d2b-7a6ca21c5009
# Show all work items including passed
hlx status 02d8bd09 all
# Download console log for a failed work item
hlx logs 02d8bd09 "dotnet-watch.Tests.dll.1"
# List uploaded files (binlogs, test results, etc.)
hlx files 02d8bd09 "dotnet-watch.Tests.dll.1"
# Download binlogs from a work item
hlx download 02d8bd09 "dotnet-watch.Tests.dll.1" --pattern "*.binlog"
# Scan work items to find which ones have binlogs
hlx find-binlogs 02d8bd09
# Search work items for any file type
hlx find-files 02d8bd09 --pattern "*.trx"
# Download a file by direct URL (from hlx files output)
hlx download-url "https://helix..."
# Show detailed info about a specific work item
hlx work-item 02d8bd09 "dotnet-watch.Tests.dll.1"
# Check status of multiple jobs at once
hlx batch-status 02d8bd09 a1b2c3d4
# Search console log for error patterns
hlx search-log 02d8bd09 "dotnet-watch.Tests.dll.1" "error CS"
# Search an uploaded file for a pattern
hlx search-file 02d8bd09 "dotnet-watch.Tests.dll.1" "testhost.log" "error"
# Parse TRX test results from a work item
hlx test-results 02d8bd09 "dotnet-watch.Tests.dll.1"
Accepts bare GUIDs or full Helix URLs:
hlx status https://helix.dot.net/api/jobs/02d8bd09-9400-4e86-8d2b-7a6ca21c5009/details
If running from a local build instead of the installed tool, substitute
dotnet run --project src/HelixTool --forhlx.
MCP Server
Stdio (recommended for local use) — launched automatically by MCP clients:
hlx mcp
HTTP (for remote/shared servers):
# Start the HTTP MCP server (default port 5000)
dotnet run --project src/HelixTool.Mcp
# Or on a specific port
dotnet run --project src/HelixTool.Mcp --urls http://localhost:3001
MCP Configuration
Add the following to your MCP client config. The --yes flag ensures dnx doesn't prompt for confirmation:
{
"servers": {
"hlx": {
"type": "stdio",
"command": "dnx",
"args": ["lewing.helix.mcp", "--yes"]
}
}
}
If you've installed
lewing.helix.mcpas a global tool, you can use"command": "hlx"with"args": []instead ofdnx.
Config file locations
| Client | Config file | Top-level key |
|---|---|---|
| VS Code / GitHub Copilot | .vscode/mcp.json |
servers |
| Claude Desktop (macOS) | ~/Library/Application Support/Claude/claude_desktop_config.json |
mcpServers |
| Claude Desktop (Windows) | %APPDATA%\Claude\claude_desktop_config.json |
mcpServers |
| Claude Code / Cursor | .cursor/mcp.json |
mcpServers |
Note: VS Code uses the
serverskey (shown above). Claude Desktop, Claude Code, and Cursor usemcpServersinstead — the rest of the JSON is identical.
HTTP alternative (for remote/shared servers)
{
"servers": {
"hlx": {
"type": "http",
"url": "http://localhost:3001"
}
}
}
MCP Tools
| Tool | Description |
|---|---|
hlx_status |
Get work item pass/fail summary for a Helix job. Accepts a filter parameter: failed (default), passed, or all. Returns structured JSON with job metadata, failed items (with exit codes, state, duration, machine, failure category), and passed count. |
hlx_logs |
Get console log content for a work item. Returns the log text directly (last N lines if tail specified, default 500). |
hlx_files |
List uploaded files for a work item, grouped by type. Returns binlogs, testResults, and other files with names and URIs. |
hlx_download |
Download files from a work item to a temp directory. Supports glob patterns (e.g., *.binlog). Returns local file paths. |
hlx_download_url |
Download a file by direct blob storage URL (e.g., from hlx_files output). Returns the local file path. |
hlx_find_files |
Search work items in a job for files matching a glob pattern (*.binlog, *.trx, *.dmp, etc.). Returns work item names and matching file URIs. |
hlx_find_binlogs |
Scan work items in a job to find which ones contain binlog files. Shortcut for hlx_find_files with *.binlog pattern. |
hlx_work_item |
Get detailed info about a specific work item: exit code, state, machine, duration, failure category, console log URL, and uploaded files. |
hlx_batch_status |
Get status for multiple Helix jobs at once (max 50). Accepts an array of job IDs/URLs. Returns per-job summaries, overall totals, and failure breakdown by category. |
hlx_search_log |
Search a work item's console log for lines matching a pattern. Returns matching lines with context. Supports contextLines and maxMatches parameters. |
hlx_search_file |
Search an uploaded file's content for lines matching a pattern — without downloading it. Supports context lines and max match limits. Disabled when HLX_DISABLE_FILE_SEARCH=true. |
hlx_test_results |
Parse TRX test result files from a work item. Returns structured test results: names, outcomes, durations, and error messages/stack traces for failures. Auto-discovers .trx files or filter to a specific one. Disabled when HLX_DISABLE_FILE_SEARCH=true. |
CLI Commands
| Command | Description |
|---|---|
hlx status <jobId> [failed\|passed\|all] |
Work item summary. Filter is a positional arg (default: failed). |
hlx logs <jobId> <workItem> |
Download console log to a temp file and print the path. |
hlx files <jobId> <workItem> |
List uploaded files for a work item. |
hlx download <jobId> <workItem> [--pattern PAT] |
Download work item files. Glob pattern (default: *). |
hlx download-url <url> |
Download a file by direct blob storage URL. |
hlx find-files <jobId> [--pattern PAT] [--max-items N] |
Search work items for files matching a glob pattern. |
hlx find-binlogs <jobId> [--max-items N] |
Shortcut for find-files --pattern "*.binlog". |
hlx work-item <jobId> <workItem> |
Detailed work item info (exit code, state, machine, files). |
hlx batch-status <jobId1> <jobId2> ... |
Status for multiple jobs in parallel. |
hlx search-log <jobId> <workItem> <pattern> [--context N] [--max-matches N] |
Search console log for a pattern. |
hlx search-file <jobId> <workItem> <fileName> <pattern> [--context N] [--max-matches N] |
Search an uploaded file for a pattern. |
hlx test-results <jobId> <workItem> [--file-name NAME] [--include-passed] [--max-results N] |
Parse TRX test results from a work item. |
hlx cache status |
Show cache size, entry count, oldest/newest entries. |
hlx cache clear |
Wipe all cached data (all auth contexts). |
hlx mcp |
Start MCP server over stdio. Also the default when no command is given. |
Failure Categorization
Failed work items are automatically classified into one of: Timeout, Crash, BuildFailure, TestFailure, InfrastructureError, AssertionFailure, or Unknown. The category appears in status, work-item, and batch-status output, and is available as failureCategory in JSON and MCP tool responses.
How hlx Enhances the Helix API
hlx isn't a thin API wrapper — it adds a local intelligence layer between agents and the raw Helix REST API. The biggest win for LLM agents is that TRX parsing, remote search, and failure classification work together to return structured, pre-categorized, context-efficient data instead of raw blobs.
Major enhancements
| Enhancement | What you get | Why it matters |
|---|---|---|
| Failure classification | Every failed work item is categorized (Timeout, Crash, BuildFailure, TestFailure, InfrastructureError, etc.) from exit code + state + work item name | Agents can triage without parsing logs. The Helix API only gives you an exit code. |
| TRX test result parsing | hlx_test_results returns test names, outcomes, durations, and error messages as structured JSON |
The raw API gives you a .trx file URL. hlx downloads it, parses the VS Test XML (XXE-safe), and extracts what matters. |
| Remote content search | hlx_search_file and hlx_search_log return matching lines with context — no full download needed |
Agents search multi-MB logs without blowing their context window. Includes binary detection and a 50 MB cap. |
| Cross-process SQLite cache | WAL-mode SQLite with LRU eviction and a 1 GB cap. Multiple hlx instances share one cache. | The second agent to inspect a job gets instant results. Auth-isolated directories prevent cross-token leakage. |
| Smart TTL policy | Running jobs: 15–30s. Completed jobs: 1–4h. Console logs for running jobs: never cached. | Helix jobs transition from mutable (running) to immutable (completed). The TTL strategy tracks this lifecycle so agents always see fresh data for active jobs and avoid redundant calls for finished ones. |
Convenience enhancements
| Enhancement | What you get |
|---|---|
| URL parsing | Pass full Helix URLs instead of extracting job IDs and work item names yourself. hlx parses both from a single URL. |
| Cross-work-item file discovery | hlx_find_files scans N work items for files matching a glob and aggregates results — one tool call instead of N+1 API calls. |
| Batch status aggregation | hlx_batch_status queries up to 50 jobs in parallel with overall totals and failure breakdown by category. |
| File type classification | hlx_files groups uploaded files into binlogs, test results, and other — no manual filename matching. |
| Computed duration | Work item durations are calculated and formatted as human-readable strings (e.g., 2m 34s). |
| Console log URL construction | Log download URLs are built from job/work-item IDs — agents don't need to know the Helix URL format. |
| Auth-isolated cache storage | Each unique token gets its own cache directory (cache-{hash}/). Unauthenticated requests use public/. |
Project Structure
src/
├── HelixTool/ # CLI tool + stdio MCP server
│ └── Program.cs # Console commands via ConsoleAppFramework + MCP server
├── HelixTool.Core/ # Shared library — Helix API logic + MCP tool definitions
│ ├── HelixService.cs # Core operations (status, logs, files, download)
│ ├── HelixMcpTools.cs # MCP tool definitions ([McpServerToolType])
│ ├── HelixIdResolver.cs # GUID and URL parsing
│ ├── IHelixApiClient.cs # Helix API abstraction
│ ├── HelixApiClient.cs # Helix API implementation
│ ├── IHelixApiClientFactory.cs # Per-request client creation (HTTP multi-auth)
│ ├── IHelixTokenAccessor.cs # Token resolution abstraction
│ ├── HelixException.cs # Typed exceptions
│ └── Cache/ # SQLite-backed response caching
│ ├── SqliteCacheStore.cs # Cache storage implementation
│ ├── CachingHelixApiClient.cs # Transparent caching wrapper
│ ├── CacheSecurity.cs # Path traversal protection
│ ├── CacheOptions.cs # TTL, size, auth isolation config
│ └── ICacheStore.cs # Cache store abstraction
├── HelixTool.Mcp/ # MCP HTTP server
│ ├── Program.cs # ASP.NET Core + ModelContextProtocol
│ └── HttpContextHelixTokenAccessor.cs # Per-request token from Authorization header
└── HelixTool.Tests/ # Unit tests (369 tests)
Authentication
No authentication is needed for public Helix jobs (dotnet open-source CI). For internal/private jobs, set the HELIX_ACCESS_TOKEN environment variable:
# Get your token from https://helix.dot.net → Profile → Access Tokens
export HELIX_ACCESS_TOKEN=your-token-here
# Or for a single command
HELIX_ACCESS_TOKEN=your-token hlx status <jobId>
For MCP clients, pass the token in the server config:
{
"servers": {
"hlx": {
"type": "stdio",
"command": "dnx",
"args": ["lewing.helix.mcp", "--yes"],
"env": {
"HELIX_ACCESS_TOKEN": "your-token-here"
}
}
}
}
HTTP MCP server (per-request auth)
The HTTP MCP server (HelixTool.Mcp) supports per-request authentication via the Authorization header:
Authorization: Bearer <token>
Authorization: token <token>
Each authenticated client gets isolated cache storage. If no header is present, the server falls back to the HELIX_ACCESS_TOKEN environment variable. This enables shared/remote MCP server deployments where multiple users connect with different credentials.
API key auth: Set HLX_API_KEY to require an X-Api-Key header on every request. When set, requests without a valid key receive 401 Unauthorized. This is independent of Helix token auth — it gates access to the server itself.
If a job requires authentication and no token is set, hlx will show an actionable error message.
Caching
Helix API responses are automatically cached to a local SQLite database — no configuration needed.
Multiple MCP server instances share a single cache safely:
flowchart LR
subgraph IDEs["IDE / Agent processes"]
A1["VS Code"]
A2["Copilot CLI"]
A3["Other agent"]
end
subgraph Stdio["hlx stdio MCP servers"]
P1["hlx (pid 1)"]
P2["hlx (pid 2)"]
P3["hlx (pid 3)"]
end
A1 --> P1
A2 --> P2
A3 --> P3
P1 --> Cache
P2 --> Cache
P3 --> Cache
subgraph Cache["CachingHelixApiClient"]
direction TB
Check{"Cache\nhit?"}
end
Check -- miss --> API["Helix API"]
API -- response --> Check
Check -- hit --> Result["Cached response"]
subgraph Store["SQLite + Disk (shared)"]
direction TB
DB["SQLite DB\n(WAL mode)"]
Artifacts["Artifact files\n(logs, TRX, binlogs)"]
end
Cache <--> Store
subgraph Isolation["Auth isolation"]
direction LR
T1["cache-a1b2c3/"]
T2["cache-d4e5f6/"]
T3["public/"]
end
Store --- Isolation
Concurrency guarantees:
- SQLite WAL mode with busy timeout — multiple processes read/write the same DB safely
- Atomic artifact writes — files are written to a temp path, then renamed into place
- Safe concurrent reads —
FileShare.ReadWrite|Deleteprevents conflicts during eviction - Isolated temp dirs — each
DownloadFilesAsynccall uses its own temp directory
| Setting | Default | Env var |
|---|---|---|
| Max cache size | 1 GB | HLX_CACHE_MAX_SIZE_MB (set to 0 to disable) |
| Cache location (Windows) | %LOCALAPPDATA%\hlx\ |
— |
| Cache location (Linux/macOS) | $XDG_CACHE_HOME/hlx/ |
— |
| Artifact expiry | 7 days without access | — |
TTL policy: Running jobs use short TTLs (15–30s). Completed jobs cache for 1–4h. Console logs are never cached while a job is still running.
Auth isolation: Each unique token gets its own cache directory (cache-{hash}). Unauthenticated requests use public/. The HTTP MCP server isolates per-request tokens automatically.
CLI commands:
hlx cache status # Show cache size, entry count, oldest/newest entries
hlx cache clear # Wipe all cached data (all auth contexts)
Security
- Safe XML parsing: TRX files are parsed with
DtdProcessing.Prohibit,XmlResolver = null, and a 50 MB character limit to prevent XXE and billion-laughs attacks. - Path traversal protection: All cache paths and download file names are sanitized via
CacheSecurity— directory separators are replaced and..sequences are stripped. Resolved paths are validated to stay within their designated root. - URL scheme validation:
hlx_download_urlonly accepts HTTP/HTTPS URLs; other schemes are rejected. - File search toggle: Set
HLX_DISABLE_FILE_SEARCH=trueto disablehlx_search_file,hlx_search_log, andhlx_test_results. Useful for locked-down deployments where file content inspection is not desired. - Input validation: Job IDs are resolved through
HelixIdResolver(GUIDs and URLs). Batch operations are capped at 50 jobs per request. File search is limited to 50 MB files.
Cached data
The SQLite cache (%LOCALAPPDATA%\hlx\ on Windows, $XDG_CACHE_HOME/hlx/ on Linux/macOS) stores Helix API responses and downloaded artifacts on disk. Cached data includes job metadata, work item details, console logs, and uploaded files like binlogs and TRX results. Console logs and test output from CI runs may inadvertently contain secrets such as connection strings or tokens — treat the cache directory as potentially sensitive.
What is NOT cached: Authentication tokens are never written to the cache. The HELIX_ACCESS_TOKEN is used only for API requests and to derive an 8-character SHA256 hash for cache directory isolation (cache-{hash}/). The hash is not reversible to the original token.
Access control: The cache lives in the current user's profile directory, protected by OS-level file permissions. Each unique Helix token gets its own isolated cache directory; unauthenticated requests use a separate public/ directory. No cross-token data leakage is possible. On shared machines or when switching between security contexts, run hlx cache clear to wipe all cached data. Cached metadata expires via TTL (15s–4h depending on job state), and artifact files expire after 7 days without access.
Requirements
- .NET 10 SDK
Known Issues
- File listing uses
ListFilesendpoint — hlx uses theListFilesAsyncendpoint for work item file listing, which correctly returns file URIs for files in subdirectories and files with unicode characters. This avoids the known bug in theDetailsendpoint where file URIs are broken (dotnet/dnceng#6072).
How to find Helix job IDs
Helix job IDs appear in Azure DevOps build logs. Look for tasks like "Send to Helix" or "Wait for Helix" — the job ID is a GUID in the log output. You can also use the azp CLI to find them.
License
MIT
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
This package has no dependencies.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.7.6 | 94 | 5/30/2026 |
| 0.7.5 | 224 | 5/28/2026 |
| 0.7.4 | 342 | 5/25/2026 |
| 0.7.3 | 230 | 5/22/2026 |
| 0.7.2 | 258 | 5/21/2026 |
| 0.7.1 | 102 | 5/21/2026 |
| 0.7.0 | 101 | 5/21/2026 |
| 0.6.0 | 735 | 5/8/2026 |
| 0.5.4 | 446 | 3/29/2026 |
| 0.5.3 | 106 | 3/29/2026 |
| 0.5.2 | 185 | 3/19/2026 |
| 0.5.1 | 105 | 3/19/2026 |
| 0.5.0 | 136 | 3/16/2026 |
| 0.4.1 | 119 | 3/15/2026 |
| 0.4.0 | 111 | 3/14/2026 |
| 0.3.5 | 112 | 3/12/2026 |
| 0.3.4 | 113 | 3/12/2026 |
| 0.3.3 | 106 | 3/12/2026 |
| 0.3.2 | 117 | 3/10/2026 |
| 0.2.1 | 119 | 3/3/2026 |