0xWisco_Labs_
API reference

Every tool, every field.

The same 9 tools are available two ways: as an MCP server your agent connects to once, and as a plain HTTP API. Both take the same parameters and return the same JSON.

Connect

MCP (Claude Code, Cursor, and any client that supports remote MCP servers over streamable HTTP):

claude mcp add --transport http wisco-labs https://api.wiscolabs.dev/mcp

Each group of tools is its own MCP server, so your agent only loads the tools it needs:

ToolsMCP server
Developer toolshttps://api.wiscolabs.dev/mcp

Tools marked beta serve new data that's still being proven.

Or in a client's JSON config:

{
  "mcpServers": {
    "wisco-labs": { "url": "https://api.wiscolabs.dev/mcp" }
  }
}

VS Code (Copilot agent mode), in .vscode/mcp.json:

{
  "servers": {
    "wisco-labs": { "type": "http", "url": "https://api.wiscolabs.dev/mcp" }
  }
}

HTTP: POST https://api.wiscolabs.dev/v1/<dataset>/<tool> with a JSON body, or GET with the same names as query parameters.

Make it automatic. Agents only call a tool when they think of it. Add this to your project's CLAUDE.md, AGENTS.md or Cursor rules:

## Dependencies
Before adding, upgrading or pinning any Python or npm dependency, check it with the
wisco-labs tools: upgrade_check for the whole requirements.txt or package-lock.json,
what_changed for a single package. Never install a version they report as vulnerable
or malicious; use the suggested version instead. Tell me about any breaking changes
or removals before upgrading.

Basics

  • No key needed during the beta. Please keep usage reasonable; heavy automated use may be rate limited.
  • Responses are JSON. Package names are matched the way each registry does (e.g. Flask and flask are the same).
  • Coverage: the 3,000 most-used PyPI packages and 1,000 most-used npm packages. Vulnerabilities are checked for any package, tracked or not.
  • Freshness: data is collected continuously. GET https://api.wiscolabs.dev/health returns when it was last published.

Errors

Errors come back as JSON with an error message that says what to fix.

StatusMeaning
400A required parameter is missing, or a value isn't valid (e.g. not a real version number).
404Unknown tool, or a package we don't track (where the tool needs its history).
503Data is being published for the first time; try again shortly.
500Something went wrong on our side. It's logged; please try again.

Check a whole project's dependencies

Give it a project's dependencies: a requirements.txt or pip freeze output for Python, or a package-lock.json, package.json, or name@version lines for npm. Flags malicious packages and versions with known vulnerabilities (with the smallest safe version to move to, preferring a low-risk patch), then reports what each upgrade breaks, removes, or deprecates, ranked into remove_now / fix_now / no_fix_available / upgrade_first / safe / review / needs_care.

MCP tool
upgrade_check on https://api.wiscolabs.dev/mcp
HTTP
POST /v1/package_changes/upgrade_check with a JSON body, or GET /v1/package_changes/upgrade_check?… with query parameters

Parameters

ParameterWhat it is
requirementsrequiredPython: requirements.txt contents, one 'package==version' per line. npm: the contents of package-lock.json (best), package.json, or one 'name@version' per line. Lines without one exact version are listed but can't be assessed.
ecosystemoptional, default PyPIPyPI or npm. A package.json or package-lock.json is recognized as npm automatically.
limitoptional, default 5Max items shown per category for each package

What comes back

FieldMeaning
ecosystemPyPI or npm: the ecosystem the dependencies were read as.
input_notesPresent only when some input lines couldn't be read exactly (e.g. a version range in package.json); explains what was skipped.
summaryCounts across the whole project: packages checked, outdated, up to date, not tracked, not assessed (no exact version), how many upgrades are high / medium / low risk, and total breaking changes, removals, deprecations and security fixes the upgrades would bring.
securityVulnerabilities in the versions you're on now: how many packages are affected, the number of known vulnerabilities, packages grouped by worst severity, and any packages reported as malicious.
recommendationPackage names sorted into what to do, most urgent first. remove_now: reported as malicious. fix_now: has known vulnerabilities and a fixed version exists. no_fix_available: vulnerable with no fix released yet. upgrade_first: the upgrade gains security fixes without high risk. safe_to_upgrade: no notable changes. review_then_upgrade: removals, deprecations or new runtime requirements to check. needs_care: breaking changes or a major version jump. license_review (also listed in another group): the upgrade moves to a more restrictive license.
packages[]One entry per outdated package: current and latest version, suggested_version (the smallest version without known vulnerabilities, when the current one has any), the vulnerabilities, upgrade_risk, and the same change lists as what_changed (breaking_changes, removals, deprecations, security_fixes_gained, major_version_bumps, runtime_requirement_changes, license, entry_point_changes, notes_coverage).
up_to_date[]Packages already on the latest version, with any known vulnerabilities that still affect it.
not_tracked[]Packages outside our coverage (the most-used packages of each ecosystem). Known vulnerabilities are still checked for them.
not_assessed[]Lines without one exact version (e.g. flask>=2.0), listed but not checked.

Example request

curl -X POST https://api.wiscolabs.dev/v1/package_changes/upgrade_check \
  -H 'Content-Type: application/json' \
  -d '{"requirements": "requests==2.31.0\nurllib3==1.26.18", "limit": "2"}'
Example response (shortened)
{
  "ecosystem": "PyPI",
  "summary": {
    "packages_checked": 2,
    "outdated": 2,
    "up_to_date": 0,
    "not_tracked": 0,
    "not_assessed": 0,
    "high_risk": 1,
    "medium_risk": 1,
    "low_risk": 0,
    "total_breaking": 0,
    "total_removed": 32,
    "total_deprecated": 15,
    "total_security_fixes_gained": 23
  },
  "security": {
    "vulnerable_packages": 2,
    "known_vulnerabilities": 3,
    "vulnerable_packages_by_worst_severity": {
      "critical": 0,
      "high": 0,
      "medium": 2,
      "low": 0,
      "unknown": 0
    },
    "malicious_packages": [],
    "data": "OSV (osv.dev) and the GitHub Advisory Database, CC-BY 4.0"
  },
  "recommendation": {
    "remove_now": [],
    "fix_now": [
      "urllib3",
      "requests"
    ],
    "no_fix_available": [],
    "upgrade_first": [],
    "safe_to_upgrade": [],
    "review_then_upgrade": [],
    "needs_care": []
  },
  "packages": [
    {
      "package": "urllib3",
      "current": "1.26.18",
      "latest": "2.8.0",
      "suggested_version": "2.5.0",
      "vulnerability_count": 2,
      "max_severity": "medium",
      "known_vulnerabilities": [
        {
          "id": "GHSA-34jh-p97f-mpxf",
          "aliases": [
            "CVE-2024-37891"
          ],
          "summary": "urllib3's Proxy-Authorization request header isn't stripped during cross-origin redirects",
          "severity": "medium",
          "fixed_in": [
            "1.26.19"
          ],
          "malicious_package": false,
          "url": "https://osv.dev/vulnerability/GHSA-34jh-p97f-mpxf"
        },
        {
          "id": "GHSA-pq67-6m6q-mj2v",
          "aliases": [
            "CVE-2025-50181"
          ],
          "summary": "urllib3 redirects are not disabled when retries are disabled on PoolManager instantiation",
          "severity": "medium",
          "fixed_in": [
            "2.5.0"
          ],
          "malicious_package": false,
          "url": "https://osv.dev/vulnerability/GHSA-pq67-6m6q-mj2v"
        }
      ],
      "upgrade_risk": "high",
      "summary": {
        "releases_between": 24,
        "releases_with_notes": 24,
        "breaking": 0,
        "removed": 27,
        "deprecated": 14,
        "security_fixes_gained": 18,
        "other_changes": 156
      },
      "breaking_changes": [],
      "removals": [
        {
          "version": "2.0.0",
          "text": "Removed support for Python 2.7, 3.5, and 3.6 (#883, #2336).",
          "source": "changelog",
          "id": "51ebe54cd8a78119"
        },
        {
          "version": "2.0.0",
          "text": "Removed fallback on certificate `commonName` in `match_hostname()` function. This behavior was deprecated in May 2000 in RFC 2818. Instead only `subjectAltName` is used to verify the hostname by default. To enable verifying the hostname against `commonName` use `SSLContext.hostname_checks_common_name = True` (#2113).",
          "source": "changelog",
          "id": "876f65d187a11987"
        }
      ],
      "deprecations": [
        {
          "version": "2.0.0",
          "text": "Deprecated `HTTPResponse.getheaders()` and `HTTPResponse.getheader()` which will be removed in urllib3 v2.1.0. Instead use `HTTPResponse.headers` and `HTTPResponse.headers.get(name, default)`. (#1543, #2814).",
          "source": "changelog",
          "id": "b25e165299973395"
        },
        {
          "version": "2.0.0",
          "text": "Deprecated `urllib3.contrib.pyopenssl` module which will be removed in urllib3 v2.1.0 (#2691).",
          "source": "changelog",
          "id": "f287b578471e6771"
        }
      ],
      "security_fixes_gained": [
        {
          "version": "2.5.0",
          "text": "Fixed a security issue where restricting the maximum number of followed redirects at the `urllib3.PoolManager` level via the `retries` parameter did not work.",
          "source": "changelog",
          "id": "a611198286ef9ab9"
        },
        {
          "version": "2.6.0",
          "text": "Fixed a security issue where streaming API could improperly handle highly compressed HTTP content (\"decompression bombs\") leading to excessive resource consumption even when a small amount of data was requested. Reading small chunks of compressed data is safer and much more efficient now. (GHSA-2xpw-w6gg-jr37)",
          "source": "changelog",
          "id": "489b0b74658a81d6"
        }
      ],
      "major_version_bumps": [
        {
          "version": "2.0.0",
          "released": "2023-04-26"
        }
      ],
      "runtime_requirement_changes": [
        {
          "version": "1.26.19",
          "requires": "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7"
        },
        {
          "version": "2.0.0",
          "requires": ">=3.7"
        }
      ],
      "notes_coverage": "complete",
      "suggested_upgrade_risk": "high"
    }
  ],
  "up_to_date": [],
  "not_tracked": [],
  "not_assessed": []
}

What changed between two versions of a package

What breaks, gets removed, is deprecated, or gains a security fix when upgrading one package between two versions, with an overall upgrade risk.

MCP tool
what_changed on https://api.wiscolabs.dev/mcp
HTTP
POST /v1/package_changes/what_changed with a JSON body, or GET /v1/package_changes/what_changed?… with query parameters

Parameters

ParameterWhat it is
namerequiredPackage name, e.g. flask (PyPI) or express or @babel/core (npm)
fromrequiredThe version you're on now
torequiredThe version you want to upgrade to (use latest_version from package_info if unsure)
ecosystemoptional, default PyPIPyPI or npm
limitoptional, default 15Max items shown per category

What comes back

FieldMeaning
upgrade_riskhigh: the project lists breaking changes, or the upgrade crosses a major version. medium: removals, deprecations, new runtime requirements, yanked versions, or (npm) entry-point changes in between. low: none of those.
versioningsemantic or calendar. Major-version jumps only count as risky for semantic versioning.
summaryCounts for every release between from and to: releases with notes, breaking changes, removals, deprecations, security fixes gained, and other changes.
breaking_changes[]Each change the project's own release notes call breaking: version, text (quoted from the notes), source (changelog or github_releases), and a stable id.
removals[]Removed features, functions and supported versions, in the same shape as breaking_changes.
deprecations[]Deprecated features that will be removed later, in the same shape.
security_fixes_gained[]Security fixes described in the release notes that the upgrade brings.
major_version_bumps[]Each major version crossed, with its release date.
runtime_requirement_changes[]Versions that changed the required language runtime (e.g. Python >=3.9, Node >=18).
yanked_versions_in_range[]Versions in between that were withdrawn by the maintainers.
known_vulnerabilitiesHow many known vulnerabilities affect the from version, which ones the upgrade fixes, and which are still present in the to version.
licenseThe license at the from and to versions (SPDX ids), each change in between (version, from_license, to_license, families) and more_restrictive: true when the upgrade moves to a more restrictive kind of license (e.g. MIT to BUSL-1.1 or to GPL). null when we have no license data for the package yet. PyPI licenses are sampled per version, so a change that was later reverted can be missed.
entry_point_changesnpm only: what stops being importable or runnable, read from each version's package.json, with the version where it changed: subpath_removed (importing it fails with ERR_PACKAGE_PATH_NOT_EXPORTED), exports_added (deep imports of unlisted files stop working), esm_only (require() no longer works), command_removed (a CLI command is gone). Empty list: none. null: no data for this package yet (or PyPI).
notes_coveragecomplete: every release in between has release notes. partial: some do. none: only version signals (major bumps, runtime requirements) are available.

Example request

curl -X POST https://api.wiscolabs.dev/v1/package_changes/what_changed \
  -H 'Content-Type: application/json' \
  -d '{"name": "flask", "from": "2.3.3", "to": "3.1.3", "limit": "3"}'
Example response (shortened)
{
  "ecosystem": "PyPI",
  "package": "flask",
  "repo": "pallets/flask",
  "from": "2.3.3",
  "to": "3.1.3",
  "upgrade_risk": "high",
  "versioning": "semantic",
  "summary": {
    "releases_between": 8,
    "releases_with_notes": 8,
    "breaking": 0,
    "removed": 2,
    "deprecated": 1,
    "security_fixes_gained": 0,
    "other_changes": 28
  },
  "breaking_changes": [],
  "removals": [
    {
      "version": "3.0.0",
      "text": "Remove previously deprecated code. #5223 (edited)",
      "source": "changelog",
      "id": "3cf6eee9d0aab566"
    },
    {
      "version": "3.1.0",
      "text": "Drop support for Python 3.8. #5623 (edited)",
      "source": "changelog",
      "id": "06741e103c17a6da"
    }
  ],
  "deprecations": [
    {
      "version": "3.0.0",
      "text": "Deprecate the `__version__` attribute. Use feature detection, or `importlib.metadata.version(\"flask\")`, instead. #5230 (edited)",
      "source": "changelog",
      "id": "937b5578ec9cdedf"
    }
  ],
  "security_fixes_gained": [],
  "major_version_bumps": [
    {
      "version": "3.0.0",
      "released": "2023-09-30"
    }
  ],
  "runtime_requirement_changes": [
    {
      "version": "3.1.0",
      "requires": ">=3.9"
    }
  ],
  "yanked_versions_in_range": [],
  "known_vulnerabilities": {
    "in_from_version": 0,
    "fixed_by_upgrade": [],
    "still_present_after_upgrade": []
  },
  "notes_coverage": "complete"
}

Will my npm packages accept this upgrade? (peer dependencies)

Before upgrading a core npm package (react, typescript, eslint, vite...), checks every dependency in the project that declares it as a peer dependency: does the installed version accept the new version, and if not, the smallest release that does, with that upgrade's risk. Also checks the new version's own peer requirements against what's installed. Answers the questions behind npm's ERESOLVE errors without running npm.

MCP tool
peer_check on https://api.wiscolabs.dev/mcp
HTTP
POST /v1/package_changes/peer_check with a JSON body, or GET /v1/package_changes/peer_check?… with query parameters

Parameters

ParameterWhat it is
upgraderequiredThe package and version to upgrade to: react@19 (newest stable 19.x), [email protected] (exact), or react (latest stable)
requirementsrequiredThe project's dependencies: the contents of package-lock.json (best), package.json, or one 'name@version' per line
limitoptional, default 5Max breaking changes shown for each suggested fix

What comes back

FieldMeaning
upgradeThe package being upgraded: from (installed version, if any), to (the resolved version), and upgrade_risk of that upgrade itself.
verdictcompatible: every dependency that declares it as a peer accepts the new version. blocked: at least one doesn't (npm would fail with ERESOLVE). check_by_hand: a peer range couldn't be read.
summaryCounts: dependencies checked, compatible, blocking, warnings, unreadable.
blocking[]Each installed package that rejects the upgrade: installed version, its peer_range, fix_version (the smallest release that accepts it, or drops the requirement), fix_peer_range, fix_upgrade_risk and fix_breaking_changes. Also lists installed packages the new version itself requires a different version of.
warnings[]Optional peers that won't match, and required peers of the new version that aren't installed.
unreadable[]Peer ranges we couldn't interpret (e.g. workspace: or git URLs).
compatible[]Installed packages whose peer range already accepts the new version.
target_peers[]The new version's own peer dependencies, with the installed version of each and whether it satisfies the range.
not_tracked[]Dependencies outside our coverage, so their peer ranges weren't checked.

Example request

curl -X POST https://api.wiscolabs.dev/v1/package_changes/peer_check \
  -H 'Content-Type: application/json' \
  -d '{"upgrade": "react@19", "requirements": "[email protected]\[email protected]\[email protected]"}'
Example response (shortened)
{
  "ecosystem": "npm",
  "upgrade": {
    "package": "react",
    "from": "18.3.1",
    "to": "19.2.0",
    "upgrade_risk": "high"
  },
  "verdict": "blocked",
  "summary": {
    "dependencies_checked": 2,
    "compatible": 0,
    "blocking": 2,
    "warnings": 0,
    "unreadable": 0
  },
  "blocking": [
    {
      "package": "react-dom",
      "installed": "18.3.1",
      "peer_range": "^18.3.1",
      "fix_version": "19.2.0",
      "fix_peer_range": "^19.2.0",
      "fix_upgrade_risk": "high",
      "fix_breaking_changes": [
        "..."
      ]
    },
    {
      "package": "react-redux",
      "installed": "8.1.3",
      "peer_range": "^16.8 || ^17.0 || ^18.0",
      "fix_version": "9.2.0",
      "fix_peer_range": "^18.0 || ^19",
      "fix_upgrade_risk": "high",
      "fix_breaking_changes": [
        "..."
      ]
    }
  ],
  "warnings": [],
  "unreadable": [],
  "compatible": [],
  "target_peers": [],
  "not_tracked": []
}

Will my npm dependencies run on this Node.js version?

Before moving a project to a new Node.js version (e.g. off Node 20 to 22 or 24), checks each npm dependency's declared Node support (its engines field). For each that doesn't support the target, gives the smallest newer release that does, with that upgrade's risk. Works from a package-lock.json without installing anything.

MCP tool
node_check on https://api.wiscolabs.dev/mcp
HTTP
POST /v1/package_changes/node_check with a JSON body, or GET /v1/package_changes/node_check?… with query parameters

Parameters

ParameterWhat it is
noderequiredTarget Node.js version: a major like 24 (means the latest 24.x) or an exact 22.11.0
requirementsrequiredThe project's dependencies: the contents of package-lock.json (best), package.json, or one 'name@version' per line
limitoptional, default 5Max breaking changes shown for each suggested fix

What comes back

FieldMeaning
verdictsupported: every dependency that declares Node support includes the target. blocked: at least one excludes it. check_by_hand: a range couldn't be read.
summaryCounts: checked, supported, unsupported, not_stated (no engines field), unreadable, not_tracked.
unsupported[]Each dependency whose installed version excludes the target: its engines range, fix_version (the smallest newer stable release that supports it), fix_engines, fix_upgrade_risk and fix_breaking_changes, or a note when no release supports it yet.
not_stated[]Dependencies whose installed version doesn't declare Node support. Most run fine; npm only enforces engines with engine-strict.
supported[]Dependencies that declare support for the target, with their range.
unreadable[]Ranges we couldn't interpret.
not_tracked[]Dependencies outside our coverage.

Example request

curl -X POST https://api.wiscolabs.dev/v1/package_changes/node_check \
  -H 'Content-Type: application/json' \
  -d '{"node": "24", "requirements": "[email protected]\[email protected]"}'
Example response (shortened)
{
  "ecosystem": "npm",
  "node": "24",
  "verdict": "blocked",
  "summary": {
    "checked": 2,
    "supported": 1,
    "unsupported": 1,
    "not_stated": 0,
    "unreadable": 0,
    "not_tracked": 0
  },
  "unsupported": [
    {
      "package": "example-native-addon",
      "version": "1.4.0",
      "engines": ">=16 <22",
      "fix_version": "2.0.0",
      "fix_engines": ">=18",
      "fix_upgrade_risk": "medium",
      "fix_breaking_changes": [
        "..."
      ]
    }
  ],
  "unreadable": [],
  "not_stated": [],
  "supported": [
    {
      "package": "express",
      "version": "4.18.2",
      "engines": ">= 0.10.0"
    }
  ],
  "not_tracked": []
}

Will my npm dependencies install on this platform without compiling?

Before building on Alpine, Linux ARM, Windows ARM, a Mac or Lambda, checks which npm dependencies contain native code and whether a prebuilt binary exists for the target platform. For those that would compile from source (needing a C/C++ toolchain and Python) or fail, gives the nearest newer version that ships a prebuilt for that platform, with that upgrade's risk.

MCP tool
native_check on https://api.wiscolabs.dev/mcp
HTTP
POST /v1/package_changes/native_check with a JSON body, or GET /v1/package_changes/native_check?… with query parameters

Parameters

ParameterWhat it is
platformrequiredTarget platform: os-cpu[-libc], e.g. linux-x64-glibc, linux-arm64-musl, darwin-arm64, win32-arm64; or alpine, alpine-arm64, linux, linux-arm64, lambda, lambda-arm64, windows, win-arm64, mac, mac-intel
requirementsrequiredThe project's dependencies: the contents of package-lock.json (best), package.json, or one 'name@version' per line
limitoptional, default 5Max breaking changes shown for each suggested fix

What comes back

FieldMeaning
verdictok: nothing compiles. will_compile_or_fail: at least one dependency builds from source or has no prebuilt for the platform. check_by_hand: some download a prebuilt at install time, which can't be checked ahead.
problems[]Each dependency that won't get a prebuilt: status (builds_from_source or no_prebuilt_for_platform), platforms_offered, fix_version (the nearest newer release with a prebuilt for the target), fix_upgrade_risk and fix_breaking_changes, or a note.
unverified[]Dependencies that download or bundle a prebuilt at install time (prebuild-install, node-pre-gyp, node-gyp-build) and compile if none fits.
prebuilt[]Native dependencies that ship a prebuilt for the target.
summaryCounts: checked, not_native, prebuilt, problems, unverified, not_tracked.

Example request

curl -X POST https://api.wiscolabs.dev/v1/package_changes/native_check \
  -H 'Content-Type: application/json' \
  -d '{"platform": "alpine-arm64", "requirements": "[email protected]\[email protected]"}'
Example response (shortened)
{
  "ecosystem": "npm",
  "platform": "linux-arm64-musl",
  "verdict": "will_compile_or_fail",
  "summary": {
    "checked": 2,
    "not_native": 0,
    "prebuilt": 1,
    "problems": 1,
    "unverified": 0,
    "not_tracked": 0
  },
  "problems": [
    {
      "package": "example-image-lib",
      "version": "1.2.0",
      "status": "builds_from_source",
      "platforms_offered": null,
      "fix_version": "2.0.0",
      "fix_upgrade_risk": "high",
      "fix_breaking_changes": [
        "..."
      ]
    }
  ],
  "unverified": [],
  "prebuilt": [
    {
      "package": "example-esbuild-like",
      "version": "0.24.0"
    }
  ],
  "not_tracked": []
}

Will pip find prebuilt wheels for this platform?

For each pinned Python package, whether a prebuilt wheel exists for a target Python version and platform (Windows ARM, Alpine/musl, Linux ARM, macOS, a new Python version). Without one, pip builds from source, which usually fails without a compiler for packages with C extensions. For each that's missing, gives the nearest newer version that has a wheel, with that upgrade's risk.

MCP tool
wheel_check on https://api.wiscolabs.dev/mcp
HTTP
POST /v1/package_changes/wheel_check with a JSON body, or GET /v1/package_changes/wheel_check?… with query parameters

Parameters

ParameterWhat it is
requirementsrequiredrequirements.txt contents or pip freeze output, one 'package==version' per line
pythonrequiredTarget Python version, e.g. 3.13
platformrequiredTarget platform: manylinux_x86_64 or manylinux_aarch64 (glibc Linux, e.g. Debian/Ubuntu; assumes glibc 2.36, or give an exact tag like manylinux_2_28_x86_64), musllinux_x86_64 or musllinux_aarch64 (Alpine), win_amd64, win_arm64, win32, macosx_arm64, macosx_x86_64
limitoptional, default 5Max breaking changes shown for each suggested upgrade

What comes back

FieldMeaning
targetThe Python version and platform checked, and how many wheel tags count as compatible.
summaryCounts: packages checked, with a wheel, source only (pip will build), not tracked.
needs_build[]Packages whose pinned version has no compatible wheel: likely_needs_compiler (the project ships binary wheels for other platforms, so it has C extensions), nearest_version_with_wheel and its upgrade_risk and breaking_changes (or a note that no release has one yet), and requires_python when the pinned version doesn't support the target Python at all.
wheel_available[]Packages with a compatible wheel, and which kind: pure (any platform) or binary (built for this platform).
not_tracked[]Packages outside our coverage (the 3,000 most-used PyPI packages).
not_assessed[]Lines without one exact version.

Example request

curl -X POST https://api.wiscolabs.dev/v1/package_changes/wheel_check \
  -H 'Content-Type: application/json' \
  -d '{"python": "3.13", "platform": "win_arm64", "requirements": "numpy==1.26.4\nrequests==2.31.0"}'
Example response (shortened)
{
  "ecosystem": "PyPI",
  "target": {
    "python": "3.13",
    "platform": "win_arm64",
    "compatible_tags": 45
  },
  "summary": {
    "checked": 2,
    "wheel_available": 1,
    "needs_build": 1,
    "not_tracked": 0
  },
  "needs_build": [
    {
      "package": "numpy",
      "version": "1.26.4",
      "has_source_distribution": true,
      "likely_needs_compiler": true,
      "nearest_version_with_wheel": "2.3.0",
      "upgrade_risk": "high",
      "breaking_changes": [
        "..."
      ]
    }
  ],
  "wheel_available": [
    {
      "package": "requests",
      "version": "2.31.0",
      "wheel": "pure"
    }
  ],
  "not_tracked": []
}

Which npm dependencies need @types packages, and which version?

For a TypeScript project: which dependencies ship their own type declarations, which need a DefinitelyTyped @types package (and the version that matches the installed library), and which installed @types packages describe a different major version than the library.

MCP tool
types_check on https://api.wiscolabs.dev/mcp
HTTP
POST /v1/package_changes/types_check with a JSON body, or GET /v1/package_changes/types_check?… with query parameters

Parameters

ParameterWhat it is
requirementsrequiredThe project's dependencies, including any @types packages: the contents of package-lock.json (best), package.json, or one 'name@version' per line

What comes back

FieldMeaning
mismatched[]Installed @types packages for a different major version of their library: the library, its version, the installed and recommended @types versions.
need_types_package[]Dependencies that declare no types and have an @types package: types_package, recommended (the newest @types release matching the library's major.minor, else its major), match (minor, major or none).
ship_types[]Dependencies that declare their own types (with a note when an @types package is installed anyway).
unknown[]Dependencies that declare no types and whose @types package we don't track. Some ship an index.d.ts without declaring it, which registry data can't show.
summaryCounts for each group.

Example request

curl -X POST https://api.wiscolabs.dev/v1/package_changes/types_check \
  -H 'Content-Type: application/json' \
  -d '{"requirements": "[email protected]\n@types/[email protected]\[email protected]"}'
Example response (shortened)
{
  "ecosystem": "npm",
  "summary": {
    "ship_types": 1,
    "need_types_package": 0,
    "mismatched": 1,
    "unknown": 0,
    "not_tracked": 0
  },
  "mismatched": [
    {
      "package": "example-server",
      "version": "4.21.2",
      "types_package": "@types/example-server",
      "recommended": "4.17.22",
      "match": "major",
      "installed": "5.0.0",
      "note": "installed @types/[email protected] describes a different major version of example-server"
    }
  ],
  "need_types_package": [],
  "ship_types": [
    {
      "package": "example-utils",
      "version": "3.1.0",
      "types": "dist/index.d.ts"
    }
  ],
  "unknown": [],
  "not_tracked": []
}

Known vulnerabilities in a package version

Is this exact version of a package affected by known security advisories? Returns each vulnerability (with CVE ids and severity), the versions that fix it, and the smallest safe upgrade.

MCP tool
vulnerabilities on https://api.wiscolabs.dev/mcp
HTTP
POST /v1/osv/vulnerabilities with a JSON body, or GET /v1/osv/vulnerabilities?… with query parameters

Parameters

ParameterWhat it is
namerequiredPackage name
versionrequiredThe exact version you're using
ecosystemoptional, default PyPIPackage ecosystem (OSV naming)

What comes back

FieldMeaning
affectedtrue if this exact version is affected by at least one known vulnerability.
max_severityThe worst severity among them: critical, high, medium, low, or unknown.
malicious_packagetrue if the package is reported as malicious: remove it rather than upgrade.
vulnerabilities[]Each advisory: id (GHSA, PYSEC, MAL...), aliases (CVE ids), summary, severity, cvss_score, the versions that fix it (fixed_in), the publish date, and a link.
minimum_safe_versionThe smallest newer version with no known vulnerabilities.
minimum_safe_same_majorThe smallest safe version without changing major version: often a low-risk patch. null if none exists.
latest_version_affectedtrue if even the newest version is still affected.
notePresent when the answer needs a caveat, e.g. for packages whose release history we don't track.
sourceWhere the vulnerability data comes from, with its license.

Example request

curl -X POST https://api.wiscolabs.dev/v1/osv/vulnerabilities \
  -H 'Content-Type: application/json' \
  -d '{"name": "urllib3", "version": "1.26.18"}'
Example response (shortened)
{
  "ecosystem": "PyPI",
  "package": "urllib3",
  "version": "1.26.18",
  "affected": true,
  "vulnerability_count": 2,
  "max_severity": "medium",
  "malicious_package": false,
  "vulnerabilities": [
    {
      "id": "GHSA-34jh-p97f-mpxf",
      "aliases": [
        "CVE-2024-37891"
      ],
      "summary": "urllib3's Proxy-Authorization request header isn't stripped during cross-origin redirects",
      "severity": "medium",
      "cvss_score": 4.4,
      "malicious_package": false,
      "fixed_in": [
        "1.26.19"
      ],
      "published": "2024-06-17",
      "url": "https://osv.dev/vulnerability/GHSA-34jh-p97f-mpxf"
    },
    {
      "id": "GHSA-pq67-6m6q-mj2v",
      "aliases": [
        "CVE-2025-50181"
      ],
      "summary": "urllib3 redirects are not disabled when retries are disabled on PoolManager instantiation",
      "severity": "medium",
      "cvss_score": 5.3,
      "malicious_package": false,
      "fixed_in": [
        "2.5.0"
      ],
      "published": "2025-06-18",
      "url": "https://osv.dev/vulnerability/GHSA-pq67-6m6q-mj2v"
    }
  ],
  "minimum_safe_version": "2.5.0",
  "minimum_safe_same_major": null,
  "latest_version_affected": false,
  "source": "OSV (osv.dev) and the GitHub Advisory Database, CC-BY 4.0"
}

Basic facts about a package

Latest and latest stable version, repository, release count, and where its release notes come from.

MCP tool
package_info on https://api.wiscolabs.dev/mcp
HTTP
POST /v1/package_changes/package_info with a JSON body, or GET /v1/package_changes/package_info?… with query parameters

Parameters

ParameterWhat it is
namerequiredPackage name
ecosystemoptional, default PyPIPyPI or npm

What comes back

FieldMeaning
latest_versionThe newest published version, including pre-releases.
latest_stable_versionThe newest version that isn't a pre-release or yanked. Use this as the upgrade target.
repoThe source repository (owner/name) where release notes are read from.
release_countHow many versions have been published.
versions_with_notesHow many of those have release notes we could read.
notes_sourcesWhere the notes come from: changelog (a file in the repository) and/or github_releases.
first_releaseDates of the first and latest releases (first_release, latest_release).

Example request

curl -X POST https://api.wiscolabs.dev/v1/package_changes/package_info \
  -H 'Content-Type: application/json' \
  -d '{"name": "flask"}'
Example response (shortened)
{
  "ecosystem": "PyPI",
  "package": "flask",
  "summary": "A simple framework for building complex web applications.",
  "homepage": null,
  "repo": "pallets/flask",
  "latest_version": "3.1.3",
  "latest_stable_version": "3.1.3",
  "release_count": 64,
  "versions_with_notes": 62,
  "notes_sources": [
    "changelog"
  ],
  "first_release": "2010-04-16",
  "latest_release": "2026-02-19"
}

For machines

Everything on this page, in formats agents and code generators read directly:

https://api.wiscolabs.dev/llms.txt        what's here, in plain text
https://api.wiscolabs.dev/v1/catalog      every dataset, tool and parameter
https://api.wiscolabs.dev/openapi.json    OpenAPI schema
https://api.wiscolabs.dev/docs            interactive (Swagger) explorer

Data and credit

Changes are sorted into categories by software, which makes mistakes. See the terms.