{
  "checker": {
    "claims": [
      {
        "claim": "Offline by default: audits a config without starting servers",
        "command": "<guest-path> inspect config_example.json --format json",
        "evidence": "execute_bash_command\",\n    \"server\": null,\n    \"risk\": \"CRITICAL\",\n    \"findings\": [\n      {\n        \"id\": \"fad9054d64b5abca4b3d8419ac2ec834\",\n        \"category\": \"command-execution\",\n        \"risk\": \"CRITICAL\",\n        \"evidence\": \"bash, execute, shell\"\n      },\n      {\n        \"id\": \"6994492e89d4c3a5716087bc51558440\",\n        \"category\": \"privileged-access\",\n        \"risk\": \"CRITICAL\",\n        \"evidence\": \"root\"\n      }\n    ]\n  },\n  {\n    \"kind\": \"tool\",\n    \"name\": \"update_customer_record\",\n    \"server\": null,\n    \"risk\": \"HIGH\",\n    \"findings\": [\n      {\n        \"id\": \"0773e4a328e89cfd104d",
        "expected": "JSON audit listing execute_bash_command",
        "input": "config_example.json",
        "kind": "claim",
        "outcome": "Real input produced the expected result: execute_bash_command",
        "returncode": 0,
        "source": "By default it runs entirely offline and never executes the servers it audits.",
        "source_checked": true,
        "source_file": "README.md",
        "verdict": "yes"
      },
      {
        "claim": "--live starts the server and audits its real tools (memory server quick start)",
        "command": "<guest-path> inspect --live --yes --server 'npx -y @modelcontextprotocol/server-memory' --format json",
        "evidence": "delete_entities\",\n    \"server\": \"server-memory\",\n    \"risk\": \"HIGH\",\n    \"findings\": [\n      {\n        \"id\": \"15bbe97fbbcc2c91b67f5876a704eec9\",\n        \"category\": \"write-operation\",\n        \"risk\": \"HIGH\",\n        \"evidence\": \"delete\"\n      }\n    ]\n  },\n  {\n    \"kind\": \"tool\",\n    \"name\": \"delete_observations\",\n    \"server\": \"server-memory\",\n    \"risk\": \"HIGH\",\n    \"findings\": [\n      {\n        \"id\": \"2ab73595feb0ebea35c99155b8995d06\",\n        \"category\": \"write-operation\",\n        \"risk\": \"HIGH\",\n        \"evidence\": \"delete\"\n      }\n    ]\n  },\n  {\n    \"kind\": \"tool\",\n    \"name\": \"delete_rel",
        "expected": "JSON audit listing the real delete_entities tool",
        "input": "npx -y @modelcontextprotocol/server-memory",
        "kind": "claim",
        "outcome": "Real input produced the expected result: delete_entities",
        "returncode": 0,
        "source": "mcp-guard starts the server once, performs the MCP handshake, reads the tools it really exposes and audits each one:",
        "source_checked": true,
        "source_file": "README.md",
        "verdict": "yes"
      },
      {
        "claim": "inspect flags hidden instructions as tool poisoning",
        "command": "<guest-path> inspect examples/poisoned_tools.json",
        "evidence": "TOOL POISONING DETECTED \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256e\n\u2502 4 tool(s) carry hidden instructions for the model: get_weather, add_numbers, \u2502\n\u2502 translate_text, format_date.                                                 \u2502\n\u2502 Any agent connected to this server reads them as if they came from you. Do   \u2502\n\u2502 not enable these tools until their descriptions and parameter descriptions   \u2502\n\u2502 have been reviewed.                                                          \u2502\n\u2570\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256f\n",
        "expected": "TOOL POISONING DETECTED alert",
        "input": "examples/poisoned_tools.json",
        "kind": "claim",
        "outcome": "Real input produced the expected result: TOOL POISONING DETECTED",
        "returncode": 0,
        "source": "prints a **TOOL POISONING DETECTED** alert under the table",
        "source_checked": true,
        "source_file": "README.md",
        "verdict": "yes"
      }
    ],
    "cycle_checks": [
      {
        "claim": "Scheduled or looping main behavior",
        "command": "",
        "evidence": "Inspected README (no cron, schedule, --once or --now, webhook or loop features) and mcp_guard source. The only loops are stdio/proxy message pumps (mcp_guard/live/*, runtime/proxy.py, runtime/journal.py, runtime/recorder.py, runtime/inspector.py), which serve one request stream and are not product cycles. mcp-guard runs one audit per invocation.",
        "expected": "identify the product trigger",
        "input": "source inspection",
        "kind": "cycle",
        "outcome": "Inspected README (no cron, schedule, --once or --now, webhook or loop features) and mcp_guard source. The only loops are stdio/proxy message pumps (mcp_guard/live/*, runtime/proxy.py, runtime/journal.py, runtime/recorder.py, runtime/inspector.py), which serve one request stream and are not product cycles. mcp-guard runs one audit per invocation.",
        "source": "repository entry points",
        "verdict": "yes"
      }
    ],
    "details": {
      "argv": [
        "<guest-path>",
        "inspect",
        "config_example.json",
        "--format",
        "json"
      ],
      "kind": "cli",
      "needs_browser": false,
      "needs_credentials": false,
      "returncode": 0,
      "scope": "product operation",
      "stderr": "",
      "stdout": "[\n  {\n    \"kind\": \"server\",\n    \"name\": \"ops-toolbox\",\n    \"server\": null,\n    \"risk\": \"CRITICAL\",\n    \"findings\": [\n      {\n        \"id\": \"99d47e387fac685c88458e9c10c13132\",\n        \"category\": \"privileged-access\",\n        \"risk\": \"CRITICAL\",\n        \"evidence\": \"sudo\"\n[excerpt truncated]",
      "working": true
    },
    "evidence_strength": "readme_checked",
    "example_checks": [
      {
        "claim": "Tool poisoning detection on the shipped sample",
        "command": "<guest-path> inspect examples/poisoned_tools.json",
        "deferred": false,
        "evidence": " 0   HIGH  4   MEDIUM  0   LOW  1\n\u256d\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 TOOL POISONING DETECTED \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256e\n\u2502 4 tool(s) carry hidden instructions for the model: get_weather, add_numbers, \u2502\n\u2502 translate_text, format_date.                                                 \u2502\n\u2502 Any agent connected to this server reads them as if they came from you. Do   \u2502\n\u2502 not enable these tools until their descriptions and parameter descriptions   \u2502\n\u2502 have been reviewed.                                                          \u2502\n\u2570\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256f",
        "expected": "TOOL POISONING DETECTED alert",
        "input": "examples/poisoned_tools.json",
        "kind": "example",
        "outcome": "command completed successfully",
        "returncode": 0,
        "source": "README.md Tool poisoning section (examples/poisoned_tools.json)",
        "verdict": "yes"
      },
      {
        "claim": "Custom rules file (--rules) applied to a config",
        "command": "<guest-path> inspect --rules examples/rules.yaml config_example.json --format json",
        "deferred": false,
        "evidence": "\"update\"\n      },\n      {\n        \"id\": \"1b25a8ab4e22246c65c777ebbfa39be8\",\n        \"category\": \"database\",\n        \"risk\": \"MEDIUM\",\n        \"evidence\": \"database, query, sql, table\"\n      },\n      {\n        \"id\": \"e5efd8045e9a7c12789b1a68b6cdf766\",\n        \"category\": \"customer-data\",\n        \"risk\": \"HIGH\",\n        \"evidence\": \"customer, customers\"\n      }\n    ]\n  },\n  {\n    \"kind\": \"server\",\n    \"name\": \"filesystem\",\n    \"server\": null,\n    \"risk\": \"LOW\",\n    \"findings\": []\n  },\n  {\n    \"kind\": \"tool\",\n    \"name\": \"fetch_url\",\n    \"server\": null,\n    \"risk\": \"LOW\",\n    \"findings\": []\n  }\n]",
        "expected": "JSON audit with privileged-access finding",
        "input": "examples/rules.yaml with config_example.json",
        "kind": "example",
        "outcome": "command completed successfully",
        "returncode": 0,
        "source": "README.md --rules: custom rules (examples/rules.yaml)",
        "verdict": "yes"
      },
      {
        "claim": "Documented test suite",
        "command": "",
        "deferred": false,
        "evidence": "Ran the documented command with the venv pytest: 945 passed, 1 failed (tests/test_proxy.py::test_pins_never_store_secrets_or_the_home_directory). The failure is environmental: the test expects the venv python under the home directory, but the venv is at <guest-path> and resolves to /usr/bin/python3.12. Not a product defect as far as observed.",
        "expected": "documented command completes successfully",
        "input": "",
        "kind": "example",
        "outcome": "Ran the documented command with the venv pytest: 945 passed, 1 failed (tests/test_proxy.py::test_pins_never_store_secrets_or_the_home_directory). The failure is environmental: the test expects the venv python under the home directory, but the venv is at <guest-path> and resolves to /usr/bin/python3.12. Not a product defect as far as observed.",
        "source": "README.md Development section (pytest --cov=mcp_guard)",
        "verdict": "blocked"
      }
    ],
    "status": "PASS"
  },
  "deviations": [
    "python3 -m venv failed: ensurepip not available (Ubuntu python3-venv package missing). Installed python3-venv with sudo apt-get and recreated the venv.",
    "Node/npm were not installed in the guest; installed nodejs and npm from apt (v18.19.1) with sudo so the README's npx quick start could run.",
    "README Development pytest run: 945 passed, 1 failed. tests/test_proxy.py::test_pins_never_store_secrets_or_the_home_directory expects the venv python path to start with ~, but the venv is at <guest-path> and Python resolves to /usr/bin/python3.12. Environmental, recorded as a reasoned example rather than a pass.",
    "The README's pipx/uvx install path was not used; the Development-section editable install (pip install -e .[dev]) was used instead, as the README documents it.",
    "The task's /inputs/coldpass-preflight.py path does not exist in this VM; the checker at <guest-path> was run with --validate --replay instead.",
    "MCP probe not used: mcp-guard is a CLI and does not serve MCP; the probe and claims are kind cli.",
    "Cycle: none detected (no scheduler, cron, --once or webhook). The while-loops in the source are stdio/proxy pumps."
  ],
  "fault_owner": null,
  "main_blocker": null,
  "operation": "Audit MCP server configs and live servers with mcp-guard (static audit of config_example.json, live tools/list of the official memory server, tool-poisoning detection on examples/poisoned_tools.json)",
  "operation_scope": "Linux x86_64 Ubuntu 24.04, Python 3.12.3 venv at <guest-path>, Node v18.19.1 / npm 9.2.0 (apt). Offline audit needs no network; the --live memory-server check needs npm registry access. No credentials or browser needed.",
  "outcome": "working",
  "plain_failure": null,
  "steps": [
    "sudo apt-get install -y python3-venv (after python3 -m venv failed on missing ensurepip)",
    "python3 -m venv <guest-path>",
    "<guest-path> install -e \".[dev]\" (README Development section)",
    "<guest-path> --version -> mcp-guard, version 0.12.0",
    "sudo apt-get install -y nodejs npm (Node needed for npx in README Quick Replication)",
    "<guest-path> inspect config_example.json",
    "NODE_USE_ENV_PROXY=1 <guest-path> inspect --live --yes --server \"npx -y @modelcontextprotocol/server-memory\" --format json (run from /tmp)",
    "<guest-path> inspect examples/poisoned_tools.json",
    "<guest-path> inspect --rules examples/rules.yaml config_example.json --format json",
    "<guest-path> -m pytest --cov=mcp_guard --cov-report=term-missing (README Development)"
  ],
  "stuck_step": null,
  "suggested_fix": "None required for the product. Optional: make the test_proxy home-directory assertion independent of where the venv lives (or run the suite from a venv under $HOME)."
}
