xyz MCP · by CyberXYZ

Your AI agent checks a package before it installs it.

xyz MCP gives Claude Code, Cursor, Codex, Gemini CLI, Devin Desktop and VS Code the same verdict as the install proxy. The agent asks before it adds a dependency, and an install hook denies a blocked install before the shell runs it.

  • 13tools
  • 4ecosystems
  • 2ways to run it
fig. 01 / six agents, one verdict
  • Claude Code
  • Cursor
  • Codex
  • Gemini CLI
  • Devin Desktop
  • VS Code
xyz MCP

each answer is the live tool's reply on 20 October 2026, shortened

the agents

Six agents, one setup each.

One command points each agent at the CyberXYZ tools, and --rules adds the dependency policy to the agent's own rules file. Every file is merged, never overwritten, and the previous version is kept as .bak.

  • Claude Code--client claude-code
    server
    ~/.claude.json · .mcp.json
    rules
    CLAUDE.md

    the install hook: --hooks

  • Cursor--client cursor
    server
    ~/.cursor/mcp.json · .cursor/mcp.json
    rules
    .cursor/rules/cyberxyz.mdc
  • Codex--client codex
    server
    ~/.codex/config.toml
    rules
    AGENTS.md
  • Gemini CLI--client gemini
    server
    ~/.gemini/settings.json · .gemini/settings.json
    rules
    GEMINI.md
  • Devin Desktop--client windsurf
    server
    ~/.codeium/windsurf/mcp_config.json
    rules
    .windsurf/rules/cyberxyz.md

    formerly Windsurf; it kept the ~/.codeium paths

  • VS Code--client vscode
    server
    .vscode/mcp.json, or code --add-mcp
    rules
    .github/copilot-instructions.md

    Copilot agent mode

set up

Three commands, two minutes.

Copy each command into a terminal. The installer merges its entry into the agent's own config, keeps the old file as .bak, and with --dry-run shows the diff before anything changes.

  1. Install xyz Scanner

    From PyPI. The MCP server needs Python 3.10 or newer.

    $pipx install cyberxyz-scanner
  2. Sign in

    Opens your browser. On a server or in CI, set XYZ_API_KEY instead.

    $xyz login
  3. Connect your agent

    $xyz mcp install --client claude-code --hooks

    Adds the server to ~/.claude.json and the install hook to ~/.claude/settings.json.

~/storefront · zsh
$ xyz mcp install --client claude-code --hooksCyberXYZ MCP server command: /opt/homebrew/bin/xyz mcp serveclaude-code MCP server: ✓ wrote ~/.claude.jsonclaude-code hook: ✓ wrote ~/.claude/settings.json Restart (or reload MCP servers in) the client, then ask it to'check lodash 4.17.20 with CyberXYZ'.`xyz mcp status` shows what is configured.$

the installer's real output (xyz 1.4.75 on a Mac, home shown as ~); run it again and each line says "already configured"

every way in

Four checkpoints, one verdict.

The agent can ask first. If it doesn't, the hook reads the command. A lockfile install goes to the proxy, which checks every download, and CyberXYZ Gate reads the lockfile in CI. A bad package stops at the first checkpoint it reaches.

fig. 02 / four ways axios 1.14.1 could get in
The agent asks firstcheck_package axios 1.14.1
block not reached not reached not reached never typed
The agent skips the checknpm install axios@1.14.1
not asked denied not reached not reached told to use 1.20.0
A lockfile installnpm ci
not asked passes to the proxy HTTP 403 not reached install aborts
A pull request in CIgit push
not on the runner not on the runner not set up verdict block build fails, exit 1

the behaviour each product documents; the lockfile in rows 3 and 4 pins axios 1.14.1, and any one checkpoint also works alone

the install hook

A blocked install never reaches the shell.

Before Claude Code runs a command, the hook reads it the way the shell does and checks every package in it in one call. A blocked or quarantined package is denied with the reason and a safe version, and the agent moves on to that version. The hook never approves a command on its own.

fig. 03 / the hook in an agent session
storefront · agent

Add an HTTP client and load the product list.

I'll add axios for the HTTP calls.

Running command: npmHook denied: npm
$ npm install axios@1.14.1
PreToolUse hook · xyz hook check-installCyberXYZ blocked this install. axios@1.14.1 (npm): BLOCK - known malicious release; abnormal version jump; 13 known vulnerabilities; use axios@1.20.0 instead.
cyberxyz · check_packagenpm axios 1.20.0ALLOWOK to install axios@1.20.0.

1.14.1 is a known malicious release. Installing 1.20.0, the version CyberXYZ suggests, instead.

Run command: npm
$ npm install axios@1.20.0
Waiting...SkipRunApproved

drawn as a generic agent chat; the denial is the hook's output for this command and the check is check_package's answer, both on 20 October 2026. The last step is the agent's own prompt: you approve it.

// what the hook reads
  • npm, pnpm, yarn and bun installs that name a package
  • pip and uv, including the exact pins inside -r files, plus poetry add and pipx install
  • go get and go install
  • dotnet add package
// when CyberXYZ can't be reached

The hook lets the command run and prints a warning. Install it with --hook-fail-closed to deny instead, and with --hook-strict to ask you about alerts and unverified packages.

// what --hooks adds to ~/.claude/settings.json
{
  "hooks": { "PreToolUse": [{
    "matcher": "Bash",
    "hooks": [{ "type": "command",
      "command": "/opt/homebrew/bin/xyz hook check-install",
      "timeout": 30 }]
  }]}
}
// lockfile installs

npm ci, a bare npm install and the unpinned lines of a requirements file name no package, so they pass to the proxy, which checks each download as it happens.

the tools

What the agent can ask.

Thirteen tools and the cyberxyz-dependency-policy prompt, which tells the agent to check before it installs and never to install a package whose verdict is block or quarantine. Pick a tool to see a real call and its answer. Lookups identify themselves, so asking about a package is never counted as installing it.

  • before installing
  • fixing
  • investigating
  • your organization
  • AI models
before installing

check_package

The install-time verdict for one version: the behaviour signals, every advisory with CVSS, EPSS, KEV and the fixed version, and a version to use instead.

the agent calls
check_package(ecosystem="npm", name="axios", version="1.14.1")
CyberXYZ answers
{
  "decision": "block",
  "malicious": true,
  "signals": [
    {
      "label": "known malicious release",
      "severity": "CRITICAL",
      "description": "Confirmed supply chain attack: RAT Dropper via Compromised Maintainer."
    },
    {
      "label": "abnormal version jump",
      "severity": "MEDIUM",
      "description": "axios jumped from 1.10.0 to 1.14.1 (skipped 4 minor versions overnight)"
    },
    // 13 "known vulnerability" signals trimmed
  ],
  "advisory_count": 35,
  "suggested_version": "1.20.0",
  "recommendation": "Do not install axios@1.14.1 (block: known malicious release; abnormal version jump; 13 known vulnerabilities). Install axios@1.20.0 instead, after checking it with check_package."
}
before installing

check_packages

The same verdict for up to 500 packages of one ecosystem: counts and an overall verdict first, detail only for what is flagged.

the agent calls
check_packages(ecosystem="npm", packages=["express@4.21.2", "faker@6.6.6", "lodash@4.17.20", "jsonwebtoken@8.5.1", "react@19.0.0"])
CyberXYZ answers
{
  "summary": {
    "checked": 5,
    "block": 1,
    "quarantine": 0,
    "alert": 3,
    "allow": 1
  },
  "verdict": "do_not_install",
  "flagged": [
    {
      "package": "faker",
      "version": "6.6.6",
      "decision": "block",
      "reason": "known malicious release; 1 known vulnerability",
      "safe_version": "5.5.3"
    },
    {
      "package": "jsonwebtoken",
      "version": "8.5.1",
      "decision": "alert",
      "reason": "2 known vulnerabilities",
      "safe_version": "9.0.0"
    },
    // lodash 4.17.20 and react 19.0.0: alert, trimmed
  ],
  "allowed": ["express@4.21.2"]
}
before installing

package_dependencies

What adding a package pulls in: its direct dependencies, how far it reaches, and the findings inside that closure. It reads the latest release.

the agent calls
package_dependencies(ecosystem="npm", name="express")
CyberXYZ answers
{
  "graph_version": "5.2.1",
  "direct_dependency_count": 44,
  "reachable_total": 48,
  "max_depth": 4,
  "findings": [
    {
      "package_name": "proxy-addr",
      "version": "2.0.7",
      "depth": 1,
      "worst_severity": "CRITICAL",
      "path": ["express", "proxy-addr"]
    },
    {
      "package_name": "qs",
      "version": "6.15.3",
      "depth": 1,
      "worst_severity": "MEDIUM",
      "path": ["express", "qs"]
    }
  ],
  // the 44 direct dependencies trimmed
}
before installing

scan_project

Reads the project's manifests and lockfiles, checks every package, and says what to change: the version to move to, or the direct dependency to bump.

the agent calls
scan_project(path=".")
CyberXYZ answers
{
  "summary": {
    "files": ["package-lock.json", "package.json", "requirements.txt"],
    "packages_checked": 6,
    "block": 1,
    "alert": 1,
    "verdict": "do_not_ship"
  },
  "flagged": [
    {
      "package": "axios",
      "version": "1.14.1",
      "decision": "block",
      "direct": true,
      "action": "upgrade to 1.20.0",
      "why": "nearest clean release above 1.14.1, clears 35 advisories (also latest clean)"
    },
    {
      "package": "jsonwebtoken",
      "version": "8.5.1",
      "decision": "alert",
      "direct": true,
      "action": "upgrade to 9.0.0",
      "why": "nearest clean release above 8.5.1, clears 4 advisories"
    }
  ]
}
fixing

upgrade_plan

Whether an installed version is affected, and the nearest clean release above it: the smallest safe bump.

the agent calls
upgrade_plan(ecosystem="npm", name="jsonwebtoken", current_version="8.5.1")
CyberXYZ answers
{
  "affected": true,
  "advisories": [
    {
      "id": "GHSA-27h2-hvpr-p74q",
      "severity": "HIGH",
      "fixed_version": "9.0.0"
    },
    {
      "id": "GHSA-8cf7-32gw-wr33",
      "severity": "HIGH",
      "fixed_version": "9.0.0"
    },
    // 2 MEDIUM advisories trimmed
  ],
  "advisory_count": 4,
  "upgrade_to": "9.0.0",
  "latest_clean": "9.0.3",
  "recommendation": "Upgrade jsonwebtoken from 8.5.1 to 9.0.0 (nearest clean release above it)."
}
fixing

dependency_paths

Why a transitive package is installed: the shortest path from one of your direct dependencies, which is the one to bump.

the agent calls
dependency_paths(ecosystem="npm", roots=["express", "jsonwebtoken"], targets=["qs", "ms"])
CyberXYZ answers
{
  "paths": [
    {
      "target": "qs",
      "root": "express",
      "depth": 1,
      "path": ["express", "qs"],
      "bump": "express"
    },
    {
      "target": "ms",
      "root": "jsonwebtoken",
      "depth": 1,
      "path": ["jsonwebtoken", "ms"],
      "bump": "jsonwebtoken"
    }
  ],
  "unresolved": [],
  "unwalked_roots": []
}
investigating

get_vulnerability

One advisory in full: the affected package and ranges, the fixed version, CVSS, EPSS and KEV, and the references.

the agent calls
get_vulnerability(id="GHSA-jqcg-44mw-7w3h")
CyberXYZ answers
{
  "aliases": {
    "cve": "CVE-2026-90711",
    "ghsa": "GHSA-jqcg-44mw-7w3h"
  },
  "package": "proxy-addr",
  "ecosystem": "npm",
  "severity": "CRITICAL",
  "cwe": {
    "id": "CWE-290",
    "name": "Authentication bypass by spoofing"
  },
  "affected_ranges": [">= 1.1.0, < 2.0.8"],
  "fixed_version": "2.0.8",
  "kev": false,
  "scores": {
    "cvss": 9.1,
    "epss": 0.00332
  },
  "published": "2026-10-05",
  // description and 7 references trimmed
}
investigating

search_vulnerabilities

Search the advisory corpus (GHSA, OSV, NVD) by package, id or description, worst first.

the agent calls
search_vulnerabilities(ecosystem="npm", package="lodash", limit=5)
CyberXYZ answers
{
  "total": 10,
  "results": [
    {
      "cve": "CVE-2019-10744",
      "severity": "CRITICAL",
      "affected_ranges": "['< 4.17.12']",
      "fixed_version": "4.17.12",
      "epss": 0.05006
    },
    {
      "cve": "CVE-2026-4800",
      "severity": "HIGH",
      "affected_ranges": "['>= 4.0.0, <= 4.17.23']",
      "fixed_version": "4.18.0",
      "epss": 0.02566
    },
    // 3 more HIGH rows trimmed
  ]
}
investigating

blast_radius

Who is exposed when a version goes bad: the packages that depend on it, the range each declares and whether it resolves into the bad version.

the agent calls
blast_radius(ecosystem="npm", name="axios", version="1.14.1")
CyberXYZ answers
{
  "direct_dependent_count": 1348,
  "direct_dependent_dev_count": 385,
  "reachable_from_required": 1582,
  "direct_dependents": [
    {
      "package_name": "@base44/sdk",
      "constraints": ["^1.6.2"],
      "resolves_into_affected": true
    },
    {
      "package_name": "@sendgrid/client",
      "constraints": ["^1.12.0"],
      "resolves_into_affected": true
    },
    {
      "package_name": "@datadog/datadog-ci-plugin-deployment",
      "constraints": ["1.13.5"],
      "resolves_into_affected": false
    },
    // more rows trimmed
  ]
}
your organization

machines_with_package

Which machines in your organization installed it in the last 90 days, at which versions, and what CyberXYZ decided.

the agent calls
machines_with_package(ecosystem="npm", name="axios")
CyberXYZ answers
{
  "window": "last 90 days of your organization's CyberXYZ install log",
  "total_machines": 192,
  "other_versions": [
    {
      "version": "1.20.0",
      "machine_count": 180,
      "machines": [
        {
          "machine_name": "ci-runner-17",
          "decision": "allow"
        },
        // 9 rows trimmed
      ]
    },
    {
      "version": "1.14.1",
      "machine_count": 13,
      "machines": [
        {
          "machine_name": "laptop-02",
          "decision": "block",
          "last_seen": "2026-10-07T18:07:04Z"
        },
        // 9 rows trimmed
      ]
    }
  ]
}
AI models

model_risk

The supply-chain risk of a Hugging Face model's install: the Python packages it pulls, declared and transitive, and what is flagged among them.

the agent calls
model_risk(repo_id="sentence-transformers/all-MiniLM-L6-v2")
CyberXYZ answers
{
  "verdict": "LOW",
  "summary": {
    "risk_level": "LOW",
    "artifact_kind": "model"
  },
  "attack_vectors": [
    {
      "vector": "weak_chokepoint",
      "score": 4.1,
      "evidence_count": 35
    },
    {
      "vector": "pin_excluded_unknown",
      "score": 2.2,
      "evidence_count": 15
    }
  ],
  "package_count": 126,
  "flagged_package_count": 0
}
AI models

model_load_safety

Whether a model's weight files are safe to load, file by file, before from_pretrained or torch.load. Only CLEAN is safe to load.

the agent calls
model_load_safety(repo_id="sentence-transformers/all-MiniLM-L6-v2")
CyberXYZ answers
{
  "verdict": "UNSCANNED",
  "safe_to_load": false,
  "guidance": "Some weight files are not scanned yet: treat as unknown and ask the user.",
  "file_count": 14,
  "files": [
    {
      "path": "tf_model.h5",
      "verdict": "UNSCANNED",
      "basis": "pickle-format file not yet scanned by CyberXYZ; Hugging Face status: queued"
    },
    {
      "path": "model.safetensors",
      "verdict": "CLEAN",
      "basis": "safetensors: tensor-only format, nothing executes on load"
    },
    {
      "path": "pytorch_model.bin",
      "verdict": "CLEAN",
      "basis": "cyberxyz_pickle_scan: no code-executing opcodes"
    },
    // 11 files trimmed
  ]
}
AI models

check_model_file

Look up a downloaded model file by its sha256: which watched model ships it, and that file’s load-safety verdict.

the agent calls
check_model_file(sha256="c3a85f238711653950f6a79ece63eb0ea93d76f6a6284be04019c53733baf256")
CyberXYZ answers
{
  "verdict": "CLEAN",
  "safe_to_load": true,
  "matches": [
    {
      "repo_id": "sentence-transformers/all-MiniLM-L6-v2",
      "path": "pytorch_model.bin",
      "current": true,
      "verdict": "CLEAN",
      "basis": "cyberxyz_pickle_scan: no code-executing opcodes"
    }
  ]
}

real answers on 20 October 2026, trimmed where marked; the project scan ran on a demo project, and machine names in machines_with_package are replaced

the hosted server

Nothing to install, if you prefer.

https://mcp.cyberxyz.io/mcp speaks MCP over HTTP. Without a token it offers the public tier: the public verdict, advisories, package search and model reports. With a dashboard API key or your xyz login token it offers the signed-in tools; scan_project becomes check_dependencies, because a hosted server cannot read your files.

add the hosted server to Claude Code
$ claude mcp add --transport http cyberxyz https://mcp.cyberxyz.io/mcp \ --header "Authorization: Bearer $XYZ_API_KEY"
// book a demo

Watch it block a real attack. Then run it on your own installs.

Book 15 minutes. We run real packages through CyberXYZ while you watch, including axios 1.14.1, a hijacked release that dropped remote-control malware in March 2026, and show you exactly what your team would see. Then we connect one laptop or one pipeline for a 30-day proof of value.

What happens next

  1. 01A 15-minute callReal packages, real verdicts, and your questions.
  2. 02Connect one laptop or one pipelineOne setup command, or one line in CI. Under an hour.
  3. 03A 30-day proof of value on your own installsEvery signal, no card.

Not ready for a call?

Check any package, free, and see the verdict we would give it.

npm

Try faker@6.6.6ua-parser-js@0.7.29express@4.21.2

Thanks! We'll be in touch.

Check your inbox. We'll reach out within 24 hours.

Where should we send the invite?

  • 15 minutes
  • Video call
  • Times in your time zone

We reply within 24 hours to set a time.

We only use these details to arrange the call. Privacy policy