0xWisco_Labs_ beta Launching soon
API reference

Every tool, every field.

The same 6 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

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
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.
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, 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
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, or yanked versions 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.
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
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.1.0",
      "fix_peer_range": "^18.0 || ^19",
      "fix_upgrade_risk": "high",
      "fix_breaking_changes": [
        "..."
      ]
    }
  ],
  "warnings": [],
  "unreadable": [],
  "compatible": [],
  "target_peers": [],
  "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
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": []
}

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
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
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.