# Package Intel

**Category:** 💻 Developer Tools  
**Repository:** https://github.com/adam121393/package-intel  
**Views:** 0  
**Installs:** 0  
**Upvotes:** 0  
**Directory Page:** https://allmcps.com/mcp/package-intel

## Description
npm, PyPI & crates.io health, vulns and dependency graphs. Runs locally, no API key.

## Claude Desktop Quick Installation
Heuristic fallback — verify the package name and runner against the repository README before running it. Uses `npx` (confidence: low):

```json
"mcpServers": {
  "package-intel": {
    "command": "npx",
    "args": ["-y","package-intel"]
  }
}
```

## Documentation & README

# Package & Dependency Intelligence API (x402)

A pay-per-call API selling npm/PyPI package health, dependency-graph, and vulnerability
data to AI coding agents over the [x402](https://github.com/x402-foundation/x402) payment
protocol — plus an MCP server so agents in Claude Desktop/Cursor can call it and pay
automatically.

Defaults to **Base Sepolia testnet** via the free public facilitator. Going to mainnet is
an explicit config change (see [Going to mainnet](#going-to-mainnet)).

## Endpoints

Raw passthrough of the upstream sources is **free**: npm, PyPI, OSV and deps.dev are
themselves free and unauthenticated, so charging for a relay of them prices against zero.
What gets charged for is the consolidation — the score.

| Endpoint | Method | Price | Returns |
|---|---|---|---|
| `/v1/package/:ecosystem/:name` | GET | free | Consolidated snapshot |
| `/v1/vulns/:ecosystem/:name` | GET | free | Known vulnerabilities (OSV.dev) |
| `/v1/deps/:ecosystem/:name` | GET | free | Dependency graph (deps.dev) |
| `/v1/downloads/:ecosystem/:name` | GET | free | Download counts |
| `/v1/health/:ecosystem/:name` | GET | $0.01 | Health/risk score 0-100 |
| `/v1/batch` | POST | $0.02 | Batched health scores (≤50 packages) |

`:ecosystem` is `npm` or `pypi`. Also unpaid: `/healthz`, `/v1/sample` (canned example
response), `/.well-known/x402` (discovery manifest).

Free routes are rate limited to **60/min and 2000/day per caller** — a runaway agent loop
is how we would get our egress IP blocked by npm or OSV. Paid routes are exempt; their
price is the limiter. Exceeding a limit returns `429` with `Retry-After`.

Tier, price, description, and discovery metadata all come from `src/catalog.ts` — edit
there and the payment middleware, rate limiter, manifest, and Bazaar declarations stay in
sync. `tier` is a required discriminant, so a new endpoint cannot default into being free.

### Trusting the caller's address

The rate limiter counts per client IP, but the service sits behind a Worker proxy and a
tunnel, so every request arrives from the same address. The proxy forwards the real one as
`x-stable-ip` **signed with `PROXY_SECRET`**, and the origin honours it only when the
secret matches. Anything else — wrong secret, no secret, or a request straight to the
tunnel hostname — shares a single bucket. Without that signature a caller could forge a
fresh address per request, or skip the proxy, and get unmetered upstream fan-out.

Set the same value in both places:

```bash
# .env for the origin, plus:
npx wrangler secret put PROXY_SECRET
```

The server warns at startup if it is missing on mainnet.

## Local setup (testnet)

```bash
npm install
npm run gen-wallet
```

`gen-wallet` prints two **testnet-only** keypairs — never fund these with real assets:

- **Seller** — put its address in `.env` as `PAY_TO` (where payments land).
- **Buyer** — put its private key in `.env` as `BUYER_PRIVATE_KEY` (used by the test
  script to simulate a paying agent).

Copy `.env.example` to `.env` and fill those in. Then fund the **buyer** with Base Sepolia
USDC at [faucet.circle.com](https://faucet.circle.com) (select Base Sepolia; no account
needed). No testnet ETH is required — x402's `exact` scheme uses EIP-3009, so the buyer
only signs off-chain and the facilitator pays gas.

```bash
npm run dev
```

Verify: `curl http://localhost:4021/healthz` → 200, and
`curl -i http://localhost:4021/v1/health/npm/express` → 402 with payment instructions.

## Test the payment flow

```bash
npm run test-buyer                              # GET /v1/health/npm/express (default)
npm run test-buyer -- /v1/deps/npm/express
npm run test-buyer -- /v1/batch
```

On Git Bash/Windows, prefix with `MSYS_NO_PATHCONV=1` so the leading `/` isn't rewritten
into a Windows path.

A request for a nonexistent package returns 404 **without charging** — the x402 middleware
skips settlement entirely on any 4xx/5xx response, so failures are free.

## MCP server (how agents consume this)

`mcp-client/` is a standalone npm package (`package-intel-mcp`) — a stdio MCP server that
runs on the *buyer's* machine. It is published separately from this server so an install
does not drag in Hono and the x402 server stack; it imports nothing from `src/`.

**It runs with no configuration at all.** With no wallet it registers the four free tools
(`package_snapshot`, `package_vulns`, `package_deps`, `package_downloads`). Requiring a
funded hot wallet before the tool did anything was the single biggest adoption blocker, so
that is now the default path, not an error.

```bash
claude mcp add package-intel -- npx -y package-intel-mcp
```

Setting `X402_PRIVATE_KEY` additionally registers `package_health` and
`package_batch_health`, which call the paid endpoints and, on a 402, sign a USDC payment
from that wallet and retry — the agent just sees data. A malformed key is a hard error
rather than a silent drop back to free mode, since that would look like the paid tools
vanishing for no reason.

```json
{
  "mcpServers": {
    "package-intel": {
      "command": "npx",
      "args": ["-y", "package-intel-mcp"],
      "env": { "X402_PRIVATE_KEY": "0x..." }
    }
  }
}
```

`X402_PRIVATE_KEY` is the *agent operator's* wallet, funded with USDC on `NETWORK`. Use a
dedicated low-balance wallet — it is a hot key that spends automatically.

To run it from source against a local server: `npm run mcp`.

### Getting an agent to actually call it

Installing a tool does not make an agent reach for it. A line in the consuming repo's
`AGENTS.md` / `CLAUDE.md` / `.cursor/rules` does, on every relevant task — that is the
mechanism that produces recurring invocation, not registry listings. `mcp-client/README.md`
ships a copy-paste block for this.

## GitHub Action

`action.yml` publishes this repository as a dependency-review action. On a pull request that
touches `package.json`, `requirements*.txt` or `Cargo.toml`, it looks up every **newly added**
dependency and comments with advisories, deprecation, staleness and missing licences.

```yaml
name: Dependency review
on:
  pull_request:
    paths: ["**/package.json", "**/requirements*.txt", "**/Cargo.toml"]

permissions:
  contents: read
  pull-requests: write

jobs:
  review:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0        # needed: the action diffs base against head
      - uses: adam121393/package-intel@v1
        with:
          fail-on: critical     # none | low | moderate | high | critical
```

Uses the free endpoints only — no wallet, no API key, no signup. Zero runtime dependencies, so
adding it to a pipeline is not a supply-chain ask.

| Input | Default | Purpose |
|---|---|---|
| `fail-on` | `none` | Fail the check at this severity or above |
| `comment` | `true` | Post and update a PR comment |
| `github-token` | `${{ github.token }}` | Needs `pull-requests: write` |
| `api-url` | hosted service | Override to run against your own instance |

Two behaviours worth knowing. Only **added** dependencies are reviewed, not version bumps of
existing ones, so the comment does not become noise people learn to scroll past. And advisories
are scoped to a version: an exact pin is checked as written, while a range is checked against the
package's current release. That distinction matters — querying without a version returns every
advisory ever filed, which reports a fully patched `lodash` as critical.

A dependency that cannot be looked up is never a failure. An upstream outage must not block an
unrelated pull request.

## Coinbase CDP setup

Two **different** CDP credentials, easy to conflate:

| Credential | Needed for |
|---|---|
| `CDP_API_KEY_ID` + `CDP_API_KEY_SECRET` | The **facilitator** — verifying and settling payments |
| `CDP_WALLET_SECRET` | The **wallet SDK** — creating/controlling CDP-managed accounts |

Receiving payments needs only a public address. The server never holds key material to
get paid — `CDP_WALLET_SECRET` is only for `npm run cdp-wallet`.

```bash
# 1. Add CDP_API_KEY_ID + CDP_API_KEY_SECRET to .env, then:
npm run cdp-check          # verifies keys, prints which networks CDP actually serves

# 2. Add CDP_WALLET_SECRET, then create a TEE-backed receiving account:
npm run cdp-wallet                  # prints an address to use as PAY_TO
npm run cdp-wallet -- --faucet      # also request Base Sepolia test funds
```

`cdp-check` exists because CDP's docs list supported networks as "Base, Polygon, Arbitrum,
World, Solana" without saying whether Base *Sepolia* is included, and `/supported` requires
auth. It answers that empirically and tells you whether the testnet rehearsal below is
possible.

### Rehearsing the CDP path on testnet

If `cdp-check` reports Base Sepolia is supported, set `USE_CDP_FACILITATOR=true` while
leaving `NETWORK=eip155:84532`. You then exercise the real CDP credentials and settlement
path against **test** funds. If it isn't supported, leave the flag unset — the CDP path
will first run on mainnet, so make that first payment a small one.

## Going to mainnet

1. **Receiving wallet** — use a dedicated address (ideally from `npm run cdp-wallet`), never
   a personal wallet. Only the public address goes in `PAY_TO`.
2. **Set `NETWORK=eip155:8453`.** The server switches to the CDP facilitator automatically
   and refuses to boot without CDP keys, rather than silently using a testnet facilitator.
3. **Set `PUBLIC_URL`** to the real origin so the manifest advertises reachable URLs.
4. **Deploy** (below), then make 2–3 real settled payments — the CDP Bazaar only catalogs a
   service after its first successful settlement.

Start small and confirm settlement on [BaseScan](https://basescan.org) against your `PAY_TO`
address before promoting the endpoint anywhere.

## Deploy (Railway)

`railway.json` is included (Nixpacks, `npm run start:api`, `/healthz` health check). Push the repo,
create a Railway project from it, and set the environment variables from `.env.example` in
Railway's variables UI — **not** in a committed file. Point uptime monitoring at `/healthz`.

## Getting listed

- **CDP Bazaar** — automatic once on mainnet via the CDP facilitator, after the first
  settled payment. Each route already declares discovery metadata with a *valid* sample
  input (`npm`/`express`); this matters because the Bazaar probes with that input and only
  indexes endpoints that answer **402** — a placeholder ecosystem would 400 and never list.
- **`/.well-known/x402`** — already served, for agentic.market / x402scan / x402-list.
- **MCP registries** — publish to the official MCP Registry, then Glama, Smithery, PulseMCP.

## Notes

- **Caching:** in-process LRU with TTLs from 1h (vulns) to 24h (downloads/deps). On upstream
  failure a stale value is served with `stale: true` rather than erroring.
- **Validation before payment:** unsupported ecosystems 400 in middleware *before* the
  payment check, so they're never charged.
- **Version-scoped vulnerabilities:** health scores query OSV for the resolved current
  version. Querying without a version returns every advisory in the package's history,
  which badly misrepresents maintained packages.
- **pypistats rate limits** aggressively (429 after a couple of rapid calls). Download
  counts are best-effort: a failure omits that field rather than failing the request. Warm
  the cache for popular packages if this matters.
- The health score in `src/domain/health.ts` is a documented v1 heuristic — tune the weights
  as real usage data arrives.

