JSON output reference for snyk-agent-scan

July 21, 2026 · View on GitHub

The snyk-agent-scan CLI can emit structured JSON for programmatic consumption — useful in CI/CD pipelines, catalog validation, and custom auditing tools.

Enable JSON mode with --json:

uvx snyk-agent-scan@latest --json
uvx snyk-agent-scan@latest --json ~/.claude/skills
uvx snyk-agent-scan@latest inspect --json ~/.vscode/mcp.json

Output behavior

  • With --json, stdout contains only the JSON document (the version banner and rich-text report are suppressed).
  • Debug logging still goes to stderr when --verbose is set.
  • Skills are included by default; pass --no-skills for MCP-only scans.
  • For native pass/fail exit codes in CI, prefer --ci over custom jq parsing.

Experimental output. Field names, issue codes, and schema details may change between releases. See the project README stability notice.


JSON structure overview

The root object is a map from scan path (absolute path string) to a ScanPathResult:

{
  "/Users/me/.claude/skills/my-skill": {
    "client": "claude-code",
    "path": "/Users/me/.claude/skills/my-skill",
    "error": null,
    "servers": [
      {
        "name": "my-skill",
        "config_path": "/Users/me/.claude/skills",
        "server": {
          "path": "/Users/me/.claude/skills/my-skill/SKILL.md",
          "type": "skill"
        },
        "signature": {
          "metadata": { "...": "..." },
          "tools": [],
          "prompts": [],
          "resources": [],
          "resource_templates": []
        },
        "error": null
      }
    ],
    "issues": [
      {
        "code": "E004",
        "message": "Description of the finding",
        "reference": [0, null],
        "extra_data": null
      }
    ],
    "labels": []
  }
}

Top-level fields (ScanPathResult)

FieldTypeDescription
clientstring | nullAgent client that owns this path (e.g. cursor, claude-code).
pathstringAbsolute path for this scan result (config file, skill directory, etc.).
errorobject | nullPath-level error when discovery/parsing failed for this path. See Execution failures.
serversarray | nullInspected MCP servers and skills. null when the config could not be read at all.
issuesarraySecurity findings from analysis (E*, W*). Empty in inspect mode.
labelsarrayDeprecated — do not rely on this field. Kept for schema compatibility. Real findings live in issues.

Server entries (ServerScanResult)

FieldTypeDescription
namestring | nullServer or skill name from the config.
config_pathstring | nullAbsolute path of the config file this entry came from.
serverobjectUnderlying config: stdio MCP (command, args, type: "stdio"), remote MCP (url, type: "sse" | "http"), or skill (path, type: "skill").
signatureobject | nullLive tool/prompt/resource catalog when inspection succeeded.
errorobject | nullServer-level error when startup or inspection failed.

Issue entries (Issue)

FieldTypeDescription
codestringFinding code (e.g. E001, W015). See Issue codes.
messagestringHuman-readable description.
referencearray | nullIndex pair into the result: [server_index, entity_index]. server_index selects an entry in servers[] (an MCP server or a skill). entity_index selects an item within that entry's catalog — an MCP tool (or prompt/resource) for servers, or a file within a skill bundle; null as the second element means the issue applies to the whole server/skill, not one entity.
extra_dataobject | nullOptional structured context from analysis.

Error objects (ScanError)

FieldTypeDescription
messagestring | nullShort error description.
exceptionstring | nullSerialized exception message.
tracebackstring | nullStack trace when captured.
is_failurebooleanWhether this error should count as a runtime failure (see CI below).
categorystring | nullStructured category (e.g. server_startup, file_not_found).
server_outputstring | nullCaptured MCP traffic / stderr for startup failures.

1. Checking for execution failures

Check failures before policy violations.

Path-level errors

Inspect error on each ScanPathResult.

  • error is not null: Discovery or parsing failed for that path.
  • Read error.message (and error.category) for details.
  • error.is_failure: When false, the path was skipped benignly (e.g. file_not_found, unknown_config). When true, treat as a hard failure (e.g. parse_error).

Server-level errors

Iterate servers[]:

  • servers[i].error is not null: That MCP server or skill failed to inspect (startup error, HTTP error, skill scan error, user declined consent, etc.).
  • Check servers[i].error.is_failure the same way as path-level errors.
  • A server with signature: null and error: null was configured but not live-inspected (common for stdio MCP on unattended push-key scans without --dangerously-run-mcp-servers).

Runtime failure codes (X*)

Operational failures map to X* codes (via error.category, or occasionally in issues):

CodeCategoryTypical is_failure
X001server_startuptrue
X002skill_scan_errortrue
X003file_not_foundfalse
X004unknown_configfalse
X005parse_errortrue
X006server_http_errortrue
X007analysis_errortrue
X008(uncategorized)true
X009user_declinedtrue

These nine codes match FAILURE_CATEGORY_TO_CODE in the CLI source; there is no X010.


2. Checking for policy violations

When inspection and analysis succeeded, read the issues array.

PrefixMeaningExample
EError — high-severity security findingE001 prompt injection in MCP tool
WWarning — lower-severity or informational findingW001 suspicious words in tool description

Full reference: Issue codes.

Internal warnings (W003W006)

The human-readable CLI hides W003, W004, W005, and W006 unless --verbose is set. JSON output includes all issues unchanged.

These codes are legacy internal hints. If you want JSON parsing to mirror the default text report, filter them out in post-processing (examples below).


CI/CD integration

Use --ci for a native non-zero exit when findings or runtime failures remain:

uvx snyk-agent-scan@latest \
  --ci \
  --dangerously-run-mcp-servers \
  --json \
  ~/.claude/skills
Exit codeMeaning
0Clean (no remaining issues or failures)
1Issues or unignored runtime failures present
2Invalid flags (e.g. --ci without --dangerously-run-mcp-servers)

Ignore specific codes in CI with --ignore-issues-codes W001,W015 (requires --ci). Ignored codes are removed from the JSON payload before the exit check.

See CLI reference — CI mode.


Practical examples with jq

Any critical findings or failures?

uvx snyk-agent-scan@latest --json ./my-skill | jq '
  [ .[] ] | map(
    select(
      (.error != null and .error.is_failure) or
      (.servers[]? | .error != null and .error.is_failure) or
      (
        (.issues // []) | map(select(.code | startswith("E"))) | length > 0
      )
    )
  ) | length > 0
'

Returns true when hard failures or E* findings exist.

Filter internal warnings

Match the default text output by excluding W003W006:

uvx snyk-agent-scan@latest --json ./my-skill | jq '
  .[] | (.issues // [])[] |
  select(
    .code as $c | ["W003", "W004", "W005", "W006"] | index($c) | not
  )
'

Strict compliance check

Fail on any remaining issue (excluding internal warnings) or any is_failure error:

uvx snyk-agent-scan@latest --json ./my-skill | jq '
  [ .[] ] | map(
    select(
      (.error != null and .error.is_failure) or
      (.servers[]? | .error != null and .error.is_failure) or
      (
        (.issues // []) | map(select(
          .code as $c | ["W003", "W004", "W005", "W006"] | index($c) | not
        )) | length > 0
      )
    )
  ) | length > 0
'

If the result is true, the target failed the check.

One-liner exit code via jq

When you cannot use --ci, derive an exit code from issue codes:

uvx snyk-agent-scan@latest --json . | jq -e '
  [
    .[] | (.issues // [])[].code
  ] | map(select(. as $c | ["W003","W004","W005","W006"] | index($c) | not)) | length == 0
' > /dev/null
  • jq -e maps true → exit 0, false → exit 1.
  • This checks issues only; combine with failure checks above for full coverage.

Node.js integration

const { execSync } = require("child_process");

const IGNORE_CODES = new Set(["W003", "W004", "W005", "W006"]);

function checkAgentScan(targetPath) {
  const scanOutput = execSync(
    `uvx snyk-agent-scan@latest --json ${JSON.stringify(targetPath)}`,
    { encoding: "utf8" }
  );
  const scanResult = JSON.parse(scanOutput);

  for (const [path, result] of Object.entries(scanResult)) {
    if (result.error?.is_failure) {
      throw new Error(`Scan failed for ${path}: ${result.error.message}`);
    }

    for (const server of result.servers ?? []) {
      if (server.error?.is_failure) {
        throw new Error(
          `Inspection failed for ${server.name ?? path}: ${server.error.message}`
        );
      }
    }

    const violations = (result.issues ?? []).filter(
      (issue) => !IGNORE_CODES.has(issue.code)
    );

    if (violations.length > 0) {
      const messages = violations.map((v) => `[${v.code}] ${v.message}`).join(", ");
      throw new Error(`Security findings: ${messages}`);
    }
  }

  return true;
}

Integration notes

  • The root JSON object is keyed by absolute paths — iterate with Object.entries.
  • Check error.is_failure and servers[].error.is_failure, not just presence of error.
  • Filter W003W006 when mirroring the default text report.
  • For CI pipelines, prefer --ci --dangerously-run-mcp-servers --json over reimplementing exit logic.

  • CLI reference — all flags, including --json, --ci, and --ignore-issues-codes
  • Issue codes — security finding reference