Every tool, every field.
The same 4 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.
Flaskandflaskare 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/healthreturns when it was last published.
Errors
Errors come back as JSON with an error message that says what to fix.
| Status | Meaning |
|---|---|
400 | A required parameter is missing, or a value isn't valid (e.g. not a real version number). |
404 | Unknown tool, or a package we don't track (where the tool needs its history). |
503 | Data is being published for the first time; try again shortly. |
500 | Something 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_checkwith a JSON body, orGET /v1/package_changes/upgrade_check?…with query parameters
Parameters
| Parameter | What it is | |
|---|---|---|
requirements | required | Python: 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. |
ecosystem | optional, default PyPI | PyPI or npm. A package.json or package-lock.json is recognized as npm automatically. |
limit | optional, default 5 | Max items shown per category for each package |
What comes back
| Field | Meaning |
|---|---|
ecosystem | PyPI or npm: the ecosystem the dependencies were read as. |
input_notes | Present only when some input lines couldn't be read exactly (e.g. a version range in package.json); explains what was skipped. |
summary | Counts 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. |
security | Vulnerabilities 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. |
recommendation | Package 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_changedwith a JSON body, orGET /v1/package_changes/what_changed?…with query parameters
Parameters
| Parameter | What it is | |
|---|---|---|
name | required | Package name, e.g. flask (PyPI) or express or @babel/core (npm) |
from | required | The version you're on now |
to | required | The version you want to upgrade to (use latest_version from package_info if unsure) |
ecosystem | optional, default PyPI | PyPI or npm |
limit | optional, default 15 | Max items shown per category |
What comes back
| Field | Meaning |
|---|---|
upgrade_risk | high: 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. |
versioning | semantic or calendar. Major-version jumps only count as risky for semantic versioning. |
summary | Counts 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_vulnerabilities | How many known vulnerabilities affect the from version, which ones the upgrade fixes, and which are still present in the to version. |
notes_coverage | complete: 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"
}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/vulnerabilitieswith a JSON body, orGET /v1/osv/vulnerabilities?…with query parameters
Parameters
| Parameter | What it is | |
|---|---|---|
name | required | Package name |
version | required | The exact version you're using |
ecosystem | optional, default PyPI | Package ecosystem (OSV naming) |
What comes back
| Field | Meaning |
|---|---|
affected | true if this exact version is affected by at least one known vulnerability. |
max_severity | The worst severity among them: critical, high, medium, low, or unknown. |
malicious_package | true 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_version | The smallest newer version with no known vulnerabilities. |
minimum_safe_same_major | The smallest safe version without changing major version: often a low-risk patch. null if none exists. |
latest_version_affected | true if even the newest version is still affected. |
note | Present when the answer needs a caveat, e.g. for packages whose release history we don't track. |
source | Where 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_infowith a JSON body, orGET /v1/package_changes/package_info?…with query parameters
Parameters
| Parameter | What it is | |
|---|---|---|
name | required | Package name |
ecosystem | optional, default PyPI | PyPI or npm |
What comes back
| Field | Meaning |
|---|---|
latest_version | The newest published version, including pre-releases. |
latest_stable_version | The newest version that isn't a pre-release or yanked. Use this as the upgrade target. |
repo | The source repository (owner/name) where release notes are read from. |
release_count | How many versions have been published. |
versions_with_notes | How many of those have release notes we could read. |
notes_sources | Where the notes come from: changelog (a file in the repository) and/or github_releases. |
first_release | Dates 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
- Vulnerabilities: OSV and the GitHub Advisory Database, licensed CC-BY 4.0; malicious-package reports from OpenSSF Malicious Packages.
- Releases: PyPI and the npm registry.
- Release notes: each project's changelog and release notes, quoted for reference; text belongs to its authors. The
sourcefield on every item says where it came from.
Changes are sorted into categories by software, which makes mistakes. See the terms.