ワンクリックで
azdo-rest-param-surface-audit
Audit MCP/CLI tool parameter surface against underlying REST API capabilities to find silently-dropped params.
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
メニュー
Audit MCP/CLI tool parameter surface against underlying REST API capabilities to find silently-dropped params.
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
SOC 職業分類に基づく
Investigate .NET CI failures using the hlx CLI tool via bash. USE FOR: checking Helix job status, searching build logs, downloading test results, AzDO build timeline analysis — when MCP tools aren't loaded, when the MCP server isn't configured or fails to start, or when scripting with JSON output and jq. DO NOT USE FOR: tasks where Helix/AzDO MCP tools are already available in context (prefer ci-analysis skill when MCP server is loaded). INVOKES: bash (hlx CLI commands with --json output).
{what this skill teaches agents}
Audit pattern for comparing WorkItemSummary (list API) fields against WorkItemDetails (per-item API) after a Helix.Client SDK bump
Domain-layer normalizer + JSON-stable cache key pattern for filter types with server-side defaults and case-insensitive fields.
Strict unknown-parameter rejection for MCP tools: Stage A (UnmappedMemberHandling.Disallow) + Stage B (did-you-mean CallToolFilter).
Test MCP CallToolFilter behavior with real CallToolRequestParams and McpServerTool invocation.
| name | azdo-rest-param-surface-audit |
| description | Audit MCP/CLI tool parameter surface against underlying REST API capabilities to find silently-dropped params. |
| domain | azdo-integration |
| confidence | high |
| source | earned |
Use when adding a new AzDO REST endpoint wrapper, or when auditing existing tools for missing capabilities. The symptom of a missing param is always the same: the parameter is accepted by the MCP binding layer (or CLI), but the value is silently ignored — indistinguishable from a successful call with the filter applied.
For each AzDO MCP tool, compare:
AzdoApiClient (what actually reaches the server)If a REST param exists but is absent from either the method or the URL construction, it is a bug.
| Tool | REST param | Root cause |
|---|---|---|
azdo_builds | minTime, maxTime | Not in AzdoBuildFilter, not forwarded to URL |
azdo_builds | queryOrder | Hardcoded to queueTimeDescending, not exposed |
azdo_test_attachments | $top | Present in signature, not appended to URL |
azdo_test_results | outcomes | Hardcoded to Failed, not exposed |
minTime and maxTime are not named after a specific field — the field
they filter is determined by queryOrder:
queueTimeDescending → filters by queue timestartTimeDescending → filters by start timefinishTimeDescending → filters by finish timeAlways document this coupling in the parameter description so callers know to pair them correctly.
AzdoApiClient URL construction against the REST reference for
every param accepted by the method signature.AzdoBuildFilter properties against ListBuildsAsync query params.HashFilter, per-endpoint key strings) to ensure every
discriminating parameter is included. Missing a param → stale cache hit.FakeHttpMessageHandler.LastRequest).top / outcomes / queryOrder in the method signature but
constructing the URL before the param (classic "accepted but never used" bug).outcomes=Failed) in URL strings — use
param ?? "Failed" so the caller can override.For optional string params with a server-side default, always use
IsNullOrWhiteSpace + Trim(), not IsNullOrEmpty:
// AzdoApiClient — correct
var outcomesParam = string.IsNullOrWhiteSpace(outcomes) ? "Failed" : outcomes.Trim();
// CachingAzdoApiClient — normalize once, use in both key and inner call
var normalizedOutcomes = string.IsNullOrWhiteSpace(outcomes) ? null : outcomes.Trim();
var key = BuildCacheKey(..., $"...:{normalizedOutcomes ?? "Failed"}");
var result = await _inner.GetTestResultsAsync(..., normalizedOutcomes, ct);
Rationale:
"" and " " from a CLI or MCP caller should fall back to the default, not produce
outcomes= or outcomes=%20%20%20 in the URL (a confusing 400 from AzDO).null as the canonical "use default" value in internal layers; the API client
resolves null → "Failed" as close to the URL as possible.For validation params (e.g., queryOrder), mirror MCP validation in the CLI too:
queryOrder = AzdoService.NormalizeQueryOrder(queryOrder); // trims, null-if-empty
if (!AzdoService.IsValidQueryOrder(queryOrder))
{
Console.Error.WriteLine(AzdoService.GetInvalidQueryOrderMessage(queryOrder!));
return;
}
Don't rely on the MCP path to protect against bad CLI input — both entry points must validate.