pkgintel-mcp
# pkgintel-mcp
`pkgintel-mcp` is a keyless, read-only Model Context Protocol connector for package intelligence across npm, PyPI, Cargo, Go, Maven, NuGet, and RubyGems. It reads public metadata from deps.dev v3, OSV.dev, the npm registry, the PyPI JSON API, the crates.io API, and the OpenSSF Scorecard API. Every tool is read-only. The server speaks stdio, and it can serve stateless Streamable HTTP on `127.0.0.1` only.
A package record carries a normalized ecosystem and name, versions, latest and default version, SPDX licence strings, links, deprecation, advisories, and SLSA or provenance when deps.dev provides them. Names are normalized per ecosystem (PyPI follows PEP 503). One failed upstream does not drop the others. Each source has a waiting scheduler so this process keeps the published gap instead of bursting.
**Connects to:** public package data services (deps.dev, OSV.dev, the npm registry, PyPI, crates.io, and OpenSSF Scorecard). No API key is needed.
By Issah Abubakari ([@si-essence](https://github.com/si-essence)). Also listed on [Bot Essentials](https://bot-essentials.netlify.app).
## Requirements
- Node.js 20 or newer (CI uses Node.js 22)
- npm
## Tools
| Tool | Input | Output |
| ----------------------- | ---------------------------------------------------------- | ---------------------------------------------------------------------------------------------- |
| `get_package` | `ecosystem`, `name`. Optional `version`. | Versions (capped), latest, licences, links, deprecation, and per-source status. |
| `get_version` | `ecosystem`, `name`, exact `version`. | Licences, advisory ids, links, SLSA and attestations when present. |
| `get_dependencies` | Same as version, optional `depth` 1-4 (default 2). | Depth-limited resolved graph from deps.dev. |
| `check_vulnerabilities` | One `ecosystem`+`name`+`version`, or `packages` (1-50). | OSV advisories. A single package uses `/v1/query`. A batch uses `/v1/querybatch`. |
| `audit_lockfile` | `text` or local `path`. Optional `format`. | Parsed packages, OSV hits, licence counts from the lockfile. Caps apply. |
| `compare_packages` | `packages` array of 2-5. | Side-by-side latest, licences, deprecation. One miss is reported. |
| `get_scorecard` | `project` as `github.com/org/repo`, or `ecosystem`+`name`. | OpenSSF Scorecard aggregate and checks. |
| `search_packages` | `ecosystem`, `query`. Optional `limit` 1-25. | npm and crates search hits. PyPI has no search API and is skipped with a reason. |
| `license_check` | SPDX `expression` and `allow` list. | `allowed`, matching, blocked, unknown identifiers. |
| `list_sources` | None. | Sources, rates, terms links, and whether `PKGINTEL_CONTACT` is set. Values are never returned. |
Lockfile formats: `package-lock.json` v2/v3, pinned `requirements.txt` (`name==version` only), `Cargo.lock`, `go.sum`. Text cap 2,000,000 characters. Package cap 1,500.
Tool errors use these prefixes and name the source: `[invalid-input]`, `[not-found]`, `[rate-limited]`, `[upstream]`, `[timeout]`, `[config]`. Messages do not include stack traces or secret values.
## Setup
From a clone of this repository:
```bash
npm ci
npm run ci # typecheck, lint, test, build
npm start # stdio
npm run start:http # http://127.0.0.1:3000/mcp and /health
node scripts/live-check.mjs # optional, calls the real public APIs
```
```json
{
"mcpServers": {
"pkgintel-mcp": {
"command": "node",
"args": ["/path/to/pkgintel-mcp/dist/index.js"],
"env": {
"PKGINTEL_CONTACT": "contact@example.com"
}
}
}
}
```
Docker binds HTTP with no authentication. Keep the port on localhost.
```bash
docker build -t pkgintel-mcp .
docker run -p 3000:3000 -e PKGINTEL_CONTACT=contact@example.com pkgintel-mcp
```
The image sets `PKGINTEL_CONTACT=contact@example.com`. Override it with an address you control. Do not bake a personal address into the image.
## Environment
| Variable | Default | Role |
| ------------------------ | --------------------- | --------------------------------------------------------------------------------- |
| `PKGINTEL_CONTACT` | `contact@example.com` | User-Agent mailto. Must look like an email. Never a personal address in the repo. |
| `PKGINTEL_PER_MINUTE` | `60` | Inbound sliding window. Cache hits do not spend it. |
| `PKGINTEL_CACHE_TTL_SEC` | `60` | TTL for a successful redacted upstream body. `0` disables the cache. |
| `PKGINTEL_TIMEOUT_MS` | `20000` | Per-attempt upstream timeout. |
| `MCP_TRANSPORT` | `stdio` | `stdio` or `http`. `--http` forces HTTP. |
| `PORT` | `3000` | HTTP port. The listener is `127.0.0.1`. |
Invalid values are reported by field name and issue code. The rejected value is not included in the error.
The User-Agent is `pkgintel-mcp/0.1.0 (mailto:<PKGINTEL_CONTACT>)`.
## Sources and terms
Checked on 2026-10-20. The rate column is what this process enforces. A source is included only when its terms allow a commercially distributable wrapper that returns metadata.
| Source | What we use | Data licence | Rate we enforce | Auth | What we never do | Terms |
| ----------------- | ------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------- | ----------------------------------------- | ----------------------------------------------------------------------------------------- | ------------------------------------------------------ |
| deps.dev API v3 | GetPackage, GetVersion, GetDependencies. Ecosystems GO, RUBYGEMS, NPM, CARGO, MAVEN, PYPI, NUGET. | Generated data is [CC-BY 4.0](https://creativecommons.org/licenses/by/4.0/). Aggregated package, project, and advisory fields follow their upstream licences. Caching is expressly permitted. | 5 requests/s, one at a time. | None. Google API Terms of Service. | Treat licence strings as legal advice. Omit CC-BY attribution. | https://docs.deps.dev/api/v3/ |
| OSV.dev | POST `/v1/query`, POST `/v1/querybatch`, GET `/v1/vulns/{id}`. | Varies per upstream database. GitHub Advisory Database is CC-BY 4.0. NVD is public domain. Other feeds keep their own terms. OSV publishes no API rate cap. | 5 requests/s, one at a time. | None. | Claim one licence covers every advisory. | https://google.github.io/osv.dev/api/ |
| npm registry | Package document and `/-/v1/search`. | npm Open Source Terms (updated 2022-03-10). Public APIs may search and replicate registry metadata. Package tarballs keep the publisher's licence. | 2 requests/s against registry.npmjs.org. | None for public metadata. | Crawl npmjs.com (website crawl is 1 rps and is the wrong channel). Imply npm endorsement. | https://docs.npmjs.com/policies/open-source-terms |
| PyPI JSON API | `GET /pypi/<name>/json`. | PyPI Terms of Service and Acceptable Use. API use is a sanctioned channel. No spam. | 1 request/s. | None. | Call a search endpoint. PyPI has none. | https://policies.python.org/pypi.org/Terms-of-Service/ |
| crates.io API | Crate search `/api/v1/crates`. | crates.io data-access / crawler policy. Descriptive User-Agent required. Max 1 request/s. | 1 request/s, one at a time. | None. User-Agent identifies this process. | Send a generic HTTP-library User-Agent. Exceed 1 rps. | https://crates.io/data-access |
| OpenSSF Scorecard | `GET /projects/github.com/{org}/{repo}`. | API data is CDLA Permissive 2.0. Code is Apache-2.0. | 2 requests/s. | None. | Treat a score as a security guarantee. | https://github.com/ossf/scorecard |
## Excluded sources
npms.io is not used. This connector does not depend on that service.
RubyGems.org's own API is unused. RubyGems data comes through deps.dev, which indexes RubyGems.
Maven Central, NuGet.org, and proxy.golang.org are unused as direct HTTP sources. Those ecosystems are served through deps.dev.
## Attribution
Package intelligence includes data from Open Source Insights (deps.dev). Generated deps.dev data is licensed under CC-BY 4.0. Advisory records come from OSV.dev and the upstream databases it aggregates, including the GitHub Advisory Database (CC-BY 4.0). npm public registry metadata is used under the npm Open Source Terms. PyPI JSON metadata is used under the PyPI Terms of Service. crates.io API metadata is used under the crates.io crawler policy. OpenSSF Scorecard data is used under CDLA Permissive 2.0. None of these providers endorse this project.
## Limits and caveats
- deps.dev licence strings are SPDX 2.1 expressions when known, or `non-standard`. They are not legal advice.
- OSV `/v1/querybatch` returns ids. This connector hydrates at most 25 full advisory records per call.
- `audit_lockfile` licence counts come from fields present in the lockfile. It does not fetch a licence for every package from deps.dev.
- `requirements.txt` lines must be pinned with `==`. Ranges, VCS urls, and `-r` includes are skipped.
- PyPI search is skipped with an explicit reason. Look up an exact name with `get_package`.
- Scorecard currently resolves `github.com/org/repo`. GitLab and Bitbucket project ids from deps.dev are returned as links, not Scorecard reports.
- Retries run on 429, 5xx, timeout, and network errors, with bounded backoff and jitter, up to 3 attempts. `Retry-After` is honoured. Other 4xx responses, HTML bodies, and redirects are not retried.
- The cache and the inbound window live in the process. They disappear on exit.
- `contact@example.com` is a placeholder. Set `PKGINTEL_CONTACT` to an address you control.
## Running the tests
The tests use mocked upstream responses. They need no API key and make no network calls to the package services.
```bash
npm ci
npm test # unit and tool tests (vitest)
npm run ci # typecheck, lint, tests, and build
```
At the time of this commit, `npm test` reports 51 passing tests.
The live check writes its table to `live-check-report.txt` in the current folder, or to the path in `PKGINTEL_LIVE_CHECK_REPORT`. That file is ignored by git.
## Author
Issah Abubakari ([@si-essence](https://github.com/si-essence)).
This connector is also listed on [Bot Essentials](https://bot-essentials.netlify.app).
## Licence
MIT. See [LICENSE](LICENSE). The data licences above are separate from the MIT licence on this code.
TDQS
Scored across 10 tools
Tools mostly target distinct resource+action pairs: get_package (package-level metadata), get_version (exact version), search_packages (discovery), and get_dependencies (graph) are clearly separable. The only soft overlaps are check_vulnerabilities vs audit_lockfile (both hit OSV) and license_check vs audit_lockfile's license summary, but the descriptions make the boundary between 'single/batch package query' and 'lockfile-level audit' clear enough.
Nine of ten tools follow a clean verb_noun snake_case pattern (get_*, check_*, audit_*, compare_*, search_*, list_*). The lone exception is license_check, which inverts to noun_verb, a minor but noticeable deviation in an otherwise uniform set.
Ten tools is well within the ideal 3-15 range and every tool maps to a distinct capability of a package-intelligence service (lookup, deps, vulns, lockfile audit, comparison, scorecard, search, license, sources). No filler tools are present.
The surface covers the core lifecycle: discovery (search_packages), identity (get_package/get_version), dependency resolution, vulnerability scanning, lockfile auditing, comparison, scorecard health, and license policy. Minor gaps remain — no SBOM/export output, no version-range resolution or upgrade-path suggestion, and no direct advisory detail lookup by ID — but agents can work around these via the existing tools.