@yawlabs/npmjs-mcp 0.3.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -5
- package/dist/index.js +346 -126
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -65,7 +65,7 @@ Add to `claude_desktop_config.json`:
|
|
|
65
65
|
}
|
|
66
66
|
```
|
|
67
67
|
|
|
68
|
-
## Tools (
|
|
68
|
+
## Tools (37)
|
|
69
69
|
|
|
70
70
|
### Search
|
|
71
71
|
- `npm_search` — Search the npm registry with qualifiers (keywords, author, scope)
|
|
@@ -76,6 +76,7 @@ Add to `claude_desktop_config.json`:
|
|
|
76
76
|
- `npm_versions` — List all published versions with dates
|
|
77
77
|
- `npm_readme` — Get README content
|
|
78
78
|
- `npm_dist_tags` — Get dist-tags (latest, next, beta, etc)
|
|
79
|
+
- `npm_types` — Check TypeScript type support (built-in types or @types/*)
|
|
79
80
|
|
|
80
81
|
### Dependencies
|
|
81
82
|
- `npm_dependencies` — Get dependency lists (prod, dev, peer, optional)
|
|
@@ -106,10 +107,14 @@ Add to `claude_desktop_config.json`:
|
|
|
106
107
|
### Provenance
|
|
107
108
|
- `npm_provenance` — Get Sigstore provenance attestations (SLSA, publish)
|
|
108
109
|
|
|
110
|
+
### Trusted Publishers (requires NPM_TOKEN)
|
|
111
|
+
- `npm_trusted_publishers` — List OIDC trust relationships with CI/CD providers
|
|
112
|
+
|
|
109
113
|
### Auth (requires NPM_TOKEN)
|
|
110
114
|
- `npm_whoami` — Check authenticated user
|
|
111
115
|
- `npm_profile` — Get profile, email, 2FA status
|
|
112
116
|
- `npm_tokens` — List access tokens
|
|
117
|
+
- `npm_user_packages` — List packages published by a user
|
|
113
118
|
|
|
114
119
|
### Access (requires NPM_TOKEN)
|
|
115
120
|
- `npm_collaborators` — List package collaborators and permissions
|
|
@@ -121,16 +126,13 @@ Add to `claude_desktop_config.json`:
|
|
|
121
126
|
- `npm_org_teams` — List org teams
|
|
122
127
|
- `npm_team_packages` — List team package permissions
|
|
123
128
|
|
|
124
|
-
### Hooks (requires NPM_TOKEN)
|
|
125
|
-
- `npm_hooks` — List npm webhooks
|
|
126
|
-
|
|
127
129
|
### Workflows
|
|
128
130
|
- `npm_check_auth` — Auth health check with headless publish feasibility
|
|
129
131
|
- `npm_publish_preflight` — Pre-publish validation checklist
|
|
130
132
|
|
|
131
133
|
## Features
|
|
132
134
|
|
|
133
|
-
- **
|
|
135
|
+
- **37 tools** covering search, packages, deps, downloads, security, analysis, auth, orgs, provenance, trust, and publish workflows
|
|
134
136
|
- **No API key required** for read-only tools — authenticated tools opt-in via NPM_TOKEN
|
|
135
137
|
- **Zero runtime dependencies** — Single bundled file for instant `npx` startup
|
|
136
138
|
- **Agent-aware publish tools** — Detects non-interactive context, provides human hand-off actions instead of unworkable retries
|
package/dist/index.js
CHANGED
|
@@ -21087,6 +21087,141 @@ function downloadsGet(path) {
|
|
|
21087
21087
|
function replicateGet(path) {
|
|
21088
21088
|
return request(REPLICATE_URL, path);
|
|
21089
21089
|
}
|
|
21090
|
+
function createLimiter(max) {
|
|
21091
|
+
let active = 0;
|
|
21092
|
+
const queue = [];
|
|
21093
|
+
return function runLimited(fn) {
|
|
21094
|
+
return new Promise((resolve, reject) => {
|
|
21095
|
+
const run = () => {
|
|
21096
|
+
active++;
|
|
21097
|
+
fn().then(resolve, reject).finally(() => {
|
|
21098
|
+
active--;
|
|
21099
|
+
if (queue.length > 0) queue.shift()();
|
|
21100
|
+
});
|
|
21101
|
+
};
|
|
21102
|
+
if (active < max) run();
|
|
21103
|
+
else queue.push(run);
|
|
21104
|
+
});
|
|
21105
|
+
};
|
|
21106
|
+
}
|
|
21107
|
+
function parseSemver(v) {
|
|
21108
|
+
const m = v.match(/^(\d+)\.(\d+)\.(\d+)/);
|
|
21109
|
+
return m ? [Number(m[1]), Number(m[2]), Number(m[3])] : null;
|
|
21110
|
+
}
|
|
21111
|
+
function cmpSemver(a, b) {
|
|
21112
|
+
for (let i = 0; i < 3; i++) {
|
|
21113
|
+
if (a[i] < b[i]) return -1;
|
|
21114
|
+
if (a[i] > b[i]) return 1;
|
|
21115
|
+
}
|
|
21116
|
+
return 0;
|
|
21117
|
+
}
|
|
21118
|
+
function parseSingleConstraint(r) {
|
|
21119
|
+
if (r === "*" || r === "") {
|
|
21120
|
+
return { min: null, max: null };
|
|
21121
|
+
}
|
|
21122
|
+
if (r.startsWith("^")) {
|
|
21123
|
+
const base = parseSemver(r.slice(1));
|
|
21124
|
+
if (!base) return null;
|
|
21125
|
+
let max;
|
|
21126
|
+
if (base[0] > 0) max = [base[0] + 1, 0, 0];
|
|
21127
|
+
else if (base[1] > 0) max = [0, base[1] + 1, 0];
|
|
21128
|
+
else max = [0, 0, base[2] + 1];
|
|
21129
|
+
return { min: base, max };
|
|
21130
|
+
}
|
|
21131
|
+
if (r.startsWith("~")) {
|
|
21132
|
+
const base = parseSemver(r.slice(1));
|
|
21133
|
+
if (!base) return null;
|
|
21134
|
+
return { min: base, max: [base[0], base[1] + 1, 0] };
|
|
21135
|
+
}
|
|
21136
|
+
if (r.startsWith(">=")) {
|
|
21137
|
+
const base = parseSemver(r.slice(2));
|
|
21138
|
+
if (!base) return null;
|
|
21139
|
+
return { min: base, max: null };
|
|
21140
|
+
}
|
|
21141
|
+
if (r.startsWith(">")) {
|
|
21142
|
+
const base = parseSemver(r.slice(1));
|
|
21143
|
+
if (!base) return null;
|
|
21144
|
+
return { min: [base[0], base[1], base[2] + 1], max: null };
|
|
21145
|
+
}
|
|
21146
|
+
if (r.startsWith("<=")) {
|
|
21147
|
+
const base = parseSemver(r.slice(2));
|
|
21148
|
+
if (!base) return null;
|
|
21149
|
+
return { min: null, max: [base[0], base[1], base[2] + 1] };
|
|
21150
|
+
}
|
|
21151
|
+
if (r.startsWith("<")) {
|
|
21152
|
+
const base = parseSemver(r.slice(1));
|
|
21153
|
+
if (!base) return null;
|
|
21154
|
+
return { min: null, max: base };
|
|
21155
|
+
}
|
|
21156
|
+
if (r.startsWith("=")) {
|
|
21157
|
+
const base = parseSemver(r.slice(1));
|
|
21158
|
+
if (!base) return null;
|
|
21159
|
+
return { min: base, max: [base[0], base[1], base[2] + 1] };
|
|
21160
|
+
}
|
|
21161
|
+
const xm = r.match(/^(\d+)(?:\.(\d+|x|\*)(?:\.(\d+|x|\*))?)?$/);
|
|
21162
|
+
if (xm) {
|
|
21163
|
+
const major = Number(xm[1]);
|
|
21164
|
+
const minor = xm[2] !== void 0 && xm[2] !== "x" && xm[2] !== "*" ? Number(xm[2]) : null;
|
|
21165
|
+
if (minor === null) {
|
|
21166
|
+
return { min: [major, 0, 0], max: [major + 1, 0, 0] };
|
|
21167
|
+
}
|
|
21168
|
+
const patch = xm[3] !== void 0 && xm[3] !== "x" && xm[3] !== "*" ? Number(xm[3]) : null;
|
|
21169
|
+
if (patch === null) {
|
|
21170
|
+
return { min: [major, minor, 0], max: [major, minor + 1, 0] };
|
|
21171
|
+
}
|
|
21172
|
+
return null;
|
|
21173
|
+
}
|
|
21174
|
+
return null;
|
|
21175
|
+
}
|
|
21176
|
+
function parseRange(r) {
|
|
21177
|
+
const hyphenMatch = r.match(/^(\d+\.\d+\.\d+)\s+-\s+(\d+\.\d+\.\d+)$/);
|
|
21178
|
+
if (hyphenMatch) {
|
|
21179
|
+
const low = parseSemver(hyphenMatch[1]);
|
|
21180
|
+
const high = parseSemver(hyphenMatch[2]);
|
|
21181
|
+
if (low && high) return { min: low, max: [high[0], high[1], high[2] + 1] };
|
|
21182
|
+
return null;
|
|
21183
|
+
}
|
|
21184
|
+
const parts = r.trim().split(/\s+/);
|
|
21185
|
+
if (parts.length > 1) {
|
|
21186
|
+
let min = null;
|
|
21187
|
+
let max = null;
|
|
21188
|
+
for (const part of parts) {
|
|
21189
|
+
const constraint = parseSingleConstraint(part);
|
|
21190
|
+
if (!constraint) return null;
|
|
21191
|
+
if (constraint.min) {
|
|
21192
|
+
if (!min || cmpSemver(constraint.min, min) > 0) min = constraint.min;
|
|
21193
|
+
}
|
|
21194
|
+
if (constraint.max) {
|
|
21195
|
+
if (!max || cmpSemver(constraint.max, max) < 0) max = constraint.max;
|
|
21196
|
+
}
|
|
21197
|
+
}
|
|
21198
|
+
return { min, max };
|
|
21199
|
+
}
|
|
21200
|
+
return parseSingleConstraint(r.trim());
|
|
21201
|
+
}
|
|
21202
|
+
function maxSatisfying(versions, range) {
|
|
21203
|
+
const r = range.trim().replace(/^v/, "");
|
|
21204
|
+
if (versions.includes(r)) return r;
|
|
21205
|
+
const subRanges = r.split("||").map((s) => s.trim());
|
|
21206
|
+
let best = null;
|
|
21207
|
+
let bestParsed = null;
|
|
21208
|
+
for (const sub of subRanges) {
|
|
21209
|
+
const parsed = parseRange(sub);
|
|
21210
|
+
if (!parsed) continue;
|
|
21211
|
+
for (const v of versions) {
|
|
21212
|
+
if (v.includes("-") && !sub.includes("-")) continue;
|
|
21213
|
+
const vp = parseSemver(v);
|
|
21214
|
+
if (!vp) continue;
|
|
21215
|
+
if (parsed.min && cmpSemver(vp, parsed.min) < 0) continue;
|
|
21216
|
+
if (parsed.max && cmpSemver(vp, parsed.max) >= 0) continue;
|
|
21217
|
+
if (!bestParsed || cmpSemver(vp, bestParsed) > 0) {
|
|
21218
|
+
best = v;
|
|
21219
|
+
bestParsed = vp;
|
|
21220
|
+
}
|
|
21221
|
+
}
|
|
21222
|
+
}
|
|
21223
|
+
return best;
|
|
21224
|
+
}
|
|
21090
21225
|
|
|
21091
21226
|
// src/tools/access.ts
|
|
21092
21227
|
var accessTools = [
|
|
@@ -21184,12 +21319,9 @@ var analysisTools = [
|
|
|
21184
21319
|
handler: async (input) => {
|
|
21185
21320
|
const results = await Promise.all(
|
|
21186
21321
|
input.packages.map(async (name) => {
|
|
21187
|
-
const [pkgRes, dlRes
|
|
21322
|
+
const [pkgRes, dlRes] = await Promise.all([
|
|
21188
21323
|
registryGet(`/${encPkg(name)}`),
|
|
21189
|
-
downloadsGet(`/downloads/point/last-week/${encPkg(name)}`)
|
|
21190
|
-
registryPost("/-/npm/v1/security/advisories/bulk", {
|
|
21191
|
-
[name]: ["latest"]
|
|
21192
|
-
})
|
|
21324
|
+
downloadsGet(`/downloads/point/last-week/${encPkg(name)}`)
|
|
21193
21325
|
]);
|
|
21194
21326
|
if (!pkgRes.ok) {
|
|
21195
21327
|
return { name, error: pkgRes.error };
|
|
@@ -21198,6 +21330,15 @@ var analysisTools = [
|
|
|
21198
21330
|
const latest = pkg["dist-tags"]?.latest;
|
|
21199
21331
|
const latestVersion = latest ? pkg.versions[latest] : void 0;
|
|
21200
21332
|
const versionKeys = Object.keys(pkg.versions);
|
|
21333
|
+
let vulnerabilities = 0;
|
|
21334
|
+
if (latest) {
|
|
21335
|
+
const auditRes = await registryPost("/-/npm/v1/security/advisories/bulk", {
|
|
21336
|
+
[name]: [latest]
|
|
21337
|
+
});
|
|
21338
|
+
if (auditRes.ok && auditRes.data?.[name]) {
|
|
21339
|
+
vulnerabilities = auditRes.data[name].length;
|
|
21340
|
+
}
|
|
21341
|
+
}
|
|
21201
21342
|
return {
|
|
21202
21343
|
name,
|
|
21203
21344
|
description: pkg.description,
|
|
@@ -21212,7 +21353,7 @@ var analysisTools = [
|
|
|
21212
21353
|
hasReadme: !!(pkg.readme && pkg.readme.length > 0),
|
|
21213
21354
|
repository: pkg.repository,
|
|
21214
21355
|
homepage: pkg.homepage,
|
|
21215
|
-
vulnerabilities
|
|
21356
|
+
vulnerabilities
|
|
21216
21357
|
};
|
|
21217
21358
|
})
|
|
21218
21359
|
);
|
|
@@ -21243,6 +21384,16 @@ var analysisTools = [
|
|
|
21243
21384
|
const latest = pkg["dist-tags"]?.latest;
|
|
21244
21385
|
const latestVersion = latest ? pkg.versions[latest] : void 0;
|
|
21245
21386
|
const versionKeys = Object.keys(pkg.versions);
|
|
21387
|
+
let vulnerabilityCount = null;
|
|
21388
|
+
if (latest) {
|
|
21389
|
+
const auditRes = await registryPost("/-/npm/v1/security/advisories/bulk", {
|
|
21390
|
+
[input.name]: [latest]
|
|
21391
|
+
});
|
|
21392
|
+
if (auditRes.ok) {
|
|
21393
|
+
const advisories = auditRes.data?.[input.name];
|
|
21394
|
+
vulnerabilityCount = Array.isArray(advisories) ? advisories.length : 0;
|
|
21395
|
+
}
|
|
21396
|
+
}
|
|
21246
21397
|
const publishDates = versionKeys.map((v) => pkg.time[v]).filter(Boolean).map((d) => new Date(d).getTime()).sort((a, b) => b - a);
|
|
21247
21398
|
const now = Date.now();
|
|
21248
21399
|
const daysSinceLastPublish = publishDates.length > 0 ? Math.floor((now - publishDates[0]) / 864e5) : null;
|
|
@@ -21274,6 +21425,7 @@ var analysisTools = [
|
|
|
21274
21425
|
versionCount: versionKeys.length,
|
|
21275
21426
|
daysSinceLastPublish,
|
|
21276
21427
|
avgDaysBetweenReleases,
|
|
21428
|
+
vulnerabilityCount,
|
|
21277
21429
|
hasLicense,
|
|
21278
21430
|
hasReadme,
|
|
21279
21431
|
hasRepo,
|
|
@@ -21454,7 +21606,6 @@ var authTools = [
|
|
|
21454
21606
|
data: {
|
|
21455
21607
|
total: data.total,
|
|
21456
21608
|
tokens: data.objects.map((t) => ({
|
|
21457
|
-
token: t.token,
|
|
21458
21609
|
key: t.key,
|
|
21459
21610
|
readonly: t.readonly,
|
|
21460
21611
|
cidrWhitelist: t.cidr_whitelist,
|
|
@@ -21464,6 +21615,38 @@ var authTools = [
|
|
|
21464
21615
|
}
|
|
21465
21616
|
};
|
|
21466
21617
|
}
|
|
21618
|
+
},
|
|
21619
|
+
{
|
|
21620
|
+
name: "npm_user_packages",
|
|
21621
|
+
description: "List all packages published by a specific npm user. Shows package names and the user's access level for each. Requires authentication.",
|
|
21622
|
+
annotations: {
|
|
21623
|
+
title: "List user packages",
|
|
21624
|
+
readOnlyHint: true,
|
|
21625
|
+
destructiveHint: false,
|
|
21626
|
+
idempotentHint: true,
|
|
21627
|
+
openWorldHint: true
|
|
21628
|
+
},
|
|
21629
|
+
inputSchema: external_exports.object({
|
|
21630
|
+
username: external_exports.string().describe("npm username")
|
|
21631
|
+
}),
|
|
21632
|
+
handler: async (input) => {
|
|
21633
|
+
const authErr = requireAuth();
|
|
21634
|
+
if (authErr) return authErr;
|
|
21635
|
+
const res = await registryGetAuth(
|
|
21636
|
+
`/-/user/org.couchdb.user:${encodeURIComponent(input.username)}/package`
|
|
21637
|
+
);
|
|
21638
|
+
if (!res.ok) return res;
|
|
21639
|
+
const packages = Object.entries(res.data).map(([name, access]) => ({ name, access }));
|
|
21640
|
+
return {
|
|
21641
|
+
ok: true,
|
|
21642
|
+
status: 200,
|
|
21643
|
+
data: {
|
|
21644
|
+
username: input.username,
|
|
21645
|
+
packageCount: packages.length,
|
|
21646
|
+
packages
|
|
21647
|
+
}
|
|
21648
|
+
};
|
|
21649
|
+
}
|
|
21467
21650
|
}
|
|
21468
21651
|
];
|
|
21469
21652
|
|
|
@@ -21521,28 +21704,13 @@ var dependencyTools = [
|
|
|
21521
21704
|
}),
|
|
21522
21705
|
handler: async (input) => {
|
|
21523
21706
|
const maxDepth = input.depth ?? 3;
|
|
21524
|
-
const
|
|
21707
|
+
const runLimited = createLimiter(10);
|
|
21525
21708
|
const packumentCache = /* @__PURE__ */ new Map();
|
|
21526
21709
|
const resolved = /* @__PURE__ */ new Set();
|
|
21527
21710
|
const tree = {};
|
|
21528
21711
|
const warnings = [];
|
|
21529
|
-
|
|
21530
|
-
|
|
21531
|
-
function runLimited(fn) {
|
|
21532
|
-
return new Promise((resolve2, reject) => {
|
|
21533
|
-
const run = () => {
|
|
21534
|
-
active++;
|
|
21535
|
-
fn().then(resolve2, reject).finally(() => {
|
|
21536
|
-
active--;
|
|
21537
|
-
if (queue.length > 0) queue.shift()();
|
|
21538
|
-
});
|
|
21539
|
-
};
|
|
21540
|
-
if (active < MAX_CONCURRENT) run();
|
|
21541
|
-
else queue.push(run);
|
|
21542
|
-
});
|
|
21543
|
-
}
|
|
21544
|
-
async function resolve(name, versionHint, currentDepth) {
|
|
21545
|
-
const hintKey = `${name}@${versionHint}`;
|
|
21712
|
+
async function resolve(name, versionHint2, currentDepth) {
|
|
21713
|
+
const hintKey = `${name}@${versionHint2}`;
|
|
21546
21714
|
if (resolved.has(hintKey) || currentDepth > maxDepth) return;
|
|
21547
21715
|
resolved.add(hintKey);
|
|
21548
21716
|
let pkg = packumentCache.get(name);
|
|
@@ -21550,19 +21718,21 @@ var dependencyTools = [
|
|
|
21550
21718
|
const res = await runLimited(() => registryGetAbbreviated(`/${encPkg(name)}`));
|
|
21551
21719
|
if (!res.ok) {
|
|
21552
21720
|
warnings.push(`Failed to fetch ${name}: ${res.error}`);
|
|
21553
|
-
tree[hintKey] = { version:
|
|
21721
|
+
tree[hintKey] = { version: versionHint2, dependencies: {} };
|
|
21554
21722
|
return;
|
|
21555
21723
|
}
|
|
21556
21724
|
pkg = res.data;
|
|
21557
21725
|
packumentCache.set(name, pkg);
|
|
21558
21726
|
}
|
|
21559
21727
|
let resolvedVersion;
|
|
21560
|
-
if (pkg.versions[
|
|
21561
|
-
resolvedVersion =
|
|
21562
|
-
} else if (pkg["dist-tags"][
|
|
21563
|
-
resolvedVersion = pkg["dist-tags"][
|
|
21728
|
+
if (pkg.versions[versionHint2]) {
|
|
21729
|
+
resolvedVersion = versionHint2;
|
|
21730
|
+
} else if (pkg["dist-tags"][versionHint2]) {
|
|
21731
|
+
resolvedVersion = pkg["dist-tags"][versionHint2];
|
|
21564
21732
|
} else {
|
|
21565
|
-
|
|
21733
|
+
const available = Object.keys(pkg.versions);
|
|
21734
|
+
const matched = maxSatisfying(available, versionHint2);
|
|
21735
|
+
resolvedVersion = matched ?? pkg["dist-tags"]?.latest ?? versionHint2;
|
|
21566
21736
|
}
|
|
21567
21737
|
const resolvedKey = `${name}@${resolvedVersion}`;
|
|
21568
21738
|
if (tree[resolvedKey]) return;
|
|
@@ -21578,12 +21748,14 @@ var dependencyTools = [
|
|
|
21578
21748
|
await Promise.all(tasks);
|
|
21579
21749
|
}
|
|
21580
21750
|
}
|
|
21581
|
-
|
|
21751
|
+
const versionHint = input.version ?? "latest";
|
|
21752
|
+
await resolve(input.name, versionHint, 1);
|
|
21753
|
+
const rootKey = Object.keys(tree).find((k) => k.startsWith(`${input.name}@`)) ?? `${input.name}@${versionHint}`;
|
|
21582
21754
|
return {
|
|
21583
21755
|
ok: true,
|
|
21584
21756
|
status: 200,
|
|
21585
21757
|
data: {
|
|
21586
|
-
root:
|
|
21758
|
+
root: rootKey,
|
|
21587
21759
|
depth: maxDepth,
|
|
21588
21760
|
totalPackages: Object.keys(tree).length,
|
|
21589
21761
|
tree,
|
|
@@ -21614,39 +21786,28 @@ var dependencyTools = [
|
|
|
21614
21786
|
const res = await registryGet(`/${encPkg(input.name)}/${ver}`);
|
|
21615
21787
|
if (!res.ok) return res;
|
|
21616
21788
|
const pkg = res.data;
|
|
21617
|
-
const
|
|
21618
|
-
const
|
|
21619
|
-
let active = 0;
|
|
21620
|
-
const queue = [];
|
|
21621
|
-
function runLimited(fn) {
|
|
21622
|
-
return new Promise((resolve, reject) => {
|
|
21623
|
-
const run = () => {
|
|
21624
|
-
active++;
|
|
21625
|
-
fn().then(resolve, reject).finally(() => {
|
|
21626
|
-
active--;
|
|
21627
|
-
if (queue.length > 0) queue.shift()();
|
|
21628
|
-
});
|
|
21629
|
-
};
|
|
21630
|
-
if (active < MAX_CONCURRENT) run();
|
|
21631
|
-
else queue.push(run);
|
|
21632
|
-
});
|
|
21633
|
-
}
|
|
21789
|
+
const depEntries = Object.entries(pkg.dependencies ?? {});
|
|
21790
|
+
const runLimited = createLimiter(10);
|
|
21634
21791
|
const depLicenses = await Promise.all(
|
|
21635
|
-
|
|
21636
|
-
const
|
|
21792
|
+
depEntries.map(async ([depName, depRange]) => {
|
|
21793
|
+
const abbrevRes = await runLimited(() => registryGetAbbreviated(`/${encPkg(depName)}`));
|
|
21794
|
+
if (!abbrevRes.ok) return { name: depName, version: depRange, license: "FETCH_ERROR" };
|
|
21795
|
+
const abbrev = abbrevRes.data;
|
|
21796
|
+
const available = Object.keys(abbrev.versions);
|
|
21797
|
+
const resolved = maxSatisfying(available, depRange) ?? abbrev["dist-tags"]?.latest;
|
|
21798
|
+
if (!resolved) return { name: depName, version: depRange, license: "UNKNOWN" };
|
|
21799
|
+
const verRes = await runLimited(() => registryGet(`/${encPkg(depName)}/${resolved}`));
|
|
21637
21800
|
return {
|
|
21638
21801
|
name: depName,
|
|
21639
|
-
|
|
21802
|
+
version: resolved,
|
|
21803
|
+
license: verRes.ok ? verRes.data?.license ?? "UNKNOWN" : "FETCH_ERROR"
|
|
21640
21804
|
};
|
|
21641
21805
|
})
|
|
21642
21806
|
);
|
|
21643
21807
|
const allowedSet = new Set(
|
|
21644
21808
|
input.allowed ?? ["MIT", "ISC", "BSD-2-Clause", "BSD-3-Clause", "Apache-2.0", "0BSD", "Unlicense"]
|
|
21645
21809
|
);
|
|
21646
|
-
const results = [
|
|
21647
|
-
{ name: pkg.name, version: pkg.version, license: pkg.license ?? "UNKNOWN" },
|
|
21648
|
-
...depLicenses.map((d) => ({ name: d.name, version: "latest", license: d.license }))
|
|
21649
|
-
];
|
|
21810
|
+
const results = [{ name: pkg.name, version: pkg.version, license: pkg.license ?? "UNKNOWN" }, ...depLicenses];
|
|
21650
21811
|
const flagged = results.filter((r) => !allowedSet.has(r.license));
|
|
21651
21812
|
return {
|
|
21652
21813
|
ok: true,
|
|
@@ -21744,57 +21905,6 @@ var downloadTools = [
|
|
|
21744
21905
|
}
|
|
21745
21906
|
];
|
|
21746
21907
|
|
|
21747
|
-
// src/tools/hooks.ts
|
|
21748
|
-
var hookTools = [
|
|
21749
|
-
{
|
|
21750
|
-
name: "npm_hooks",
|
|
21751
|
-
description: "List all npm webhooks configured for the authenticated user. Shows hook type (package, scope, or owner), endpoint URL, delivery status, and last response code.",
|
|
21752
|
-
annotations: {
|
|
21753
|
-
title: "List npm hooks",
|
|
21754
|
-
readOnlyHint: true,
|
|
21755
|
-
destructiveHint: false,
|
|
21756
|
-
idempotentHint: true,
|
|
21757
|
-
openWorldHint: true
|
|
21758
|
-
},
|
|
21759
|
-
inputSchema: external_exports.object({
|
|
21760
|
-
package: external_exports.string().optional().describe("Filter hooks by package name"),
|
|
21761
|
-
limit: external_exports.number().min(1).max(100).optional().describe("Max results (default: 25)"),
|
|
21762
|
-
offset: external_exports.number().min(0).optional().describe("Pagination offset")
|
|
21763
|
-
}),
|
|
21764
|
-
handler: async (input) => {
|
|
21765
|
-
const authErr = requireAuth();
|
|
21766
|
-
if (authErr) return authErr;
|
|
21767
|
-
const params = new URLSearchParams();
|
|
21768
|
-
if (input.package) params.set("package", input.package);
|
|
21769
|
-
if (input.limit !== void 0) params.set("limit", String(input.limit));
|
|
21770
|
-
if (input.offset !== void 0) params.set("offset", String(input.offset));
|
|
21771
|
-
const qs = params.toString();
|
|
21772
|
-
const path = `/-/npm/v1/hooks${qs ? `?${qs}` : ""}`;
|
|
21773
|
-
const res = await registryGetAuth(path);
|
|
21774
|
-
if (!res.ok) return res;
|
|
21775
|
-
const data = res.data;
|
|
21776
|
-
return {
|
|
21777
|
-
ok: true,
|
|
21778
|
-
status: 200,
|
|
21779
|
-
data: {
|
|
21780
|
-
total: data.total,
|
|
21781
|
-
hooks: data.objects.map((h) => ({
|
|
21782
|
-
id: h.id,
|
|
21783
|
-
type: h.type,
|
|
21784
|
-
name: h.name,
|
|
21785
|
-
endpoint: h.endpoint,
|
|
21786
|
-
status: h.status,
|
|
21787
|
-
lastDelivery: h.last_delivery,
|
|
21788
|
-
lastResponseCode: h.response_code,
|
|
21789
|
-
created: h.created,
|
|
21790
|
-
updated: h.updated
|
|
21791
|
-
}))
|
|
21792
|
-
}
|
|
21793
|
-
};
|
|
21794
|
-
}
|
|
21795
|
-
}
|
|
21796
|
-
];
|
|
21797
|
-
|
|
21798
21908
|
// src/tools/orgs.ts
|
|
21799
21909
|
var orgTools = [
|
|
21800
21910
|
{
|
|
@@ -22019,7 +22129,7 @@ var packageTools = [
|
|
|
22019
22129
|
},
|
|
22020
22130
|
{
|
|
22021
22131
|
name: "npm_versions",
|
|
22022
|
-
description: "List
|
|
22132
|
+
description: "List published versions of a package with their publish dates, ordered newest first. Returns up to `limit` versions (default 50). Set limit=0 to return all.",
|
|
22023
22133
|
annotations: {
|
|
22024
22134
|
title: "List versions",
|
|
22025
22135
|
readOnlyHint: true,
|
|
@@ -22028,25 +22138,29 @@ var packageTools = [
|
|
|
22028
22138
|
openWorldHint: true
|
|
22029
22139
|
},
|
|
22030
22140
|
inputSchema: external_exports.object({
|
|
22031
|
-
name: external_exports.string().describe("Package name")
|
|
22141
|
+
name: external_exports.string().describe("Package name"),
|
|
22142
|
+
limit: external_exports.number().min(0).optional().describe("Max versions to return, newest first (default 50, 0 = all)")
|
|
22032
22143
|
}),
|
|
22033
22144
|
handler: async (input) => {
|
|
22034
22145
|
const res = await registryGet(`/${encPkg(input.name)}`);
|
|
22035
22146
|
if (!res.ok) return res;
|
|
22036
22147
|
const pkg = res.data;
|
|
22037
|
-
const
|
|
22148
|
+
const limit = input.limit ?? 50;
|
|
22149
|
+
const allVersions = Object.keys(pkg.versions).map((v) => ({
|
|
22038
22150
|
version: v,
|
|
22039
22151
|
date: pkg.time[v],
|
|
22040
22152
|
deprecated: pkg.versions[v].deprecated,
|
|
22041
22153
|
npmUser: pkg.versions[v]._npmUser?.name
|
|
22042
22154
|
})).sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime());
|
|
22155
|
+
const versions = limit > 0 ? allVersions.slice(0, limit) : allVersions;
|
|
22043
22156
|
return {
|
|
22044
22157
|
ok: true,
|
|
22045
22158
|
status: 200,
|
|
22046
22159
|
data: {
|
|
22047
22160
|
name: pkg.name,
|
|
22048
22161
|
distTags: pkg["dist-tags"],
|
|
22049
|
-
total:
|
|
22162
|
+
total: allVersions.length,
|
|
22163
|
+
showing: versions.length,
|
|
22050
22164
|
versions
|
|
22051
22165
|
}
|
|
22052
22166
|
};
|
|
@@ -22091,6 +22205,61 @@ var packageTools = [
|
|
|
22091
22205
|
handler: async (input) => {
|
|
22092
22206
|
return registryGet(`/-/package/${encPkg(input.name)}/dist-tags`);
|
|
22093
22207
|
}
|
|
22208
|
+
},
|
|
22209
|
+
{
|
|
22210
|
+
name: "npm_types",
|
|
22211
|
+
description: "Check TypeScript type support for a package \u2014 whether it ships built-in types (types/typings field) or has a DefinitelyTyped companion (@types/* package).",
|
|
22212
|
+
annotations: {
|
|
22213
|
+
title: "Check TypeScript types",
|
|
22214
|
+
readOnlyHint: true,
|
|
22215
|
+
destructiveHint: false,
|
|
22216
|
+
idempotentHint: true,
|
|
22217
|
+
openWorldHint: true
|
|
22218
|
+
},
|
|
22219
|
+
inputSchema: external_exports.object({
|
|
22220
|
+
name: external_exports.string().describe("Package name (e.g. 'express' or '@anthropic-ai/sdk')"),
|
|
22221
|
+
version: external_exports.string().optional().describe("Semver version or dist-tag (default: 'latest')")
|
|
22222
|
+
}),
|
|
22223
|
+
handler: async (input) => {
|
|
22224
|
+
const ver = input.version ?? "latest";
|
|
22225
|
+
let typesPackage;
|
|
22226
|
+
if (input.name.startsWith("@")) {
|
|
22227
|
+
const withoutAt = input.name.slice(1);
|
|
22228
|
+
typesPackage = `@types/${withoutAt.replace("/", "__")}`;
|
|
22229
|
+
} else {
|
|
22230
|
+
typesPackage = `@types/${input.name}`;
|
|
22231
|
+
}
|
|
22232
|
+
const [versionRes, typesRes] = await Promise.all([
|
|
22233
|
+
registryGet(`/${encPkg(input.name)}/${ver}`),
|
|
22234
|
+
registryGet(`/${encPkg(typesPackage)}`)
|
|
22235
|
+
]);
|
|
22236
|
+
if (!versionRes.ok) return versionRes;
|
|
22237
|
+
const v = versionRes.data;
|
|
22238
|
+
const hasBuiltinTypes = !!(v.types || v.typings);
|
|
22239
|
+
const typesEntry = hasBuiltinTypes ? v.types ?? v.typings : void 0;
|
|
22240
|
+
const hasTypesPackage = typesRes.ok;
|
|
22241
|
+
const typesPackageLatest = hasTypesPackage ? typesRes.data?.["dist-tags"]?.latest : void 0;
|
|
22242
|
+
let recommendation;
|
|
22243
|
+
if (hasBuiltinTypes) {
|
|
22244
|
+
recommendation = "Built-in types included \u2014 no additional install needed.";
|
|
22245
|
+
} else if (hasTypesPackage) {
|
|
22246
|
+
recommendation = `Install types separately: npm install -D ${typesPackage}`;
|
|
22247
|
+
} else {
|
|
22248
|
+
recommendation = "No TypeScript types available (built-in or @types).";
|
|
22249
|
+
}
|
|
22250
|
+
return {
|
|
22251
|
+
ok: true,
|
|
22252
|
+
status: 200,
|
|
22253
|
+
data: {
|
|
22254
|
+
name: v.name,
|
|
22255
|
+
version: v.version,
|
|
22256
|
+
builtinTypes: hasBuiltinTypes,
|
|
22257
|
+
typesEntry,
|
|
22258
|
+
typesPackage: hasTypesPackage ? { name: typesPackage, latest: typesPackageLatest } : null,
|
|
22259
|
+
recommendation
|
|
22260
|
+
}
|
|
22261
|
+
};
|
|
22262
|
+
}
|
|
22094
22263
|
}
|
|
22095
22264
|
];
|
|
22096
22265
|
|
|
@@ -22157,7 +22326,7 @@ var registryTools = [
|
|
|
22157
22326
|
},
|
|
22158
22327
|
{
|
|
22159
22328
|
name: "npm_recent_changes",
|
|
22160
|
-
description: "Get the most recent package publishes/updates from the npm registry via the CouchDB changes feed.",
|
|
22329
|
+
description: "Get the most recent package publishes/updates from the npm registry via the CouchDB changes feed. Note: uses replicate.npmjs.com which may have intermittent availability.",
|
|
22161
22330
|
annotations: {
|
|
22162
22331
|
title: "Recent registry changes",
|
|
22163
22332
|
readOnlyHint: true,
|
|
@@ -22170,21 +22339,20 @@ var registryTools = [
|
|
|
22170
22339
|
}),
|
|
22171
22340
|
handler: async (input) => {
|
|
22172
22341
|
const limit = input.limit ?? 25;
|
|
22173
|
-
const dbRes = await
|
|
22174
|
-
|
|
22175
|
-
|
|
22176
|
-
|
|
22342
|
+
const [dbRes, changesRes] = await Promise.all([
|
|
22343
|
+
replicateGet("/"),
|
|
22344
|
+
replicateGet(`/_changes?limit=${limit}&descending=true`)
|
|
22345
|
+
]);
|
|
22177
22346
|
if (!changesRes.ok) return changesRes;
|
|
22178
22347
|
const changes = changesRes.data.results.map((r) => ({
|
|
22179
22348
|
package: r.id,
|
|
22180
|
-
seq: r.seq,
|
|
22181
22349
|
rev: r.changes[0]?.rev
|
|
22182
22350
|
}));
|
|
22183
22351
|
return {
|
|
22184
22352
|
ok: true,
|
|
22185
22353
|
status: 200,
|
|
22186
22354
|
data: {
|
|
22187
|
-
totalPackages: dbRes.data.doc_count,
|
|
22355
|
+
totalPackages: dbRes.ok ? dbRes.data.doc_count : null,
|
|
22188
22356
|
changes
|
|
22189
22357
|
}
|
|
22190
22358
|
};
|
|
@@ -22230,9 +22398,7 @@ var searchTools = [
|
|
|
22230
22398
|
publisher: obj.package.publisher,
|
|
22231
22399
|
keywords: obj.package.keywords,
|
|
22232
22400
|
links: obj.package.links,
|
|
22233
|
-
score: obj.score.detail
|
|
22234
|
-
downloads: obj.downloads,
|
|
22235
|
-
dependents: obj.dependents
|
|
22401
|
+
score: obj.score.detail
|
|
22236
22402
|
}));
|
|
22237
22403
|
return { ok: true, status: 200, data: { total: res.data.total, results } };
|
|
22238
22404
|
}
|
|
@@ -22243,7 +22409,7 @@ var searchTools = [
|
|
|
22243
22409
|
var securityTools = [
|
|
22244
22410
|
{
|
|
22245
22411
|
name: "npm_audit",
|
|
22246
|
-
description: "
|
|
22412
|
+
description: "Quick vulnerability check for specific packages and versions using the bulk advisory API. Returns matching advisories with severity, CVEs, and patched versions. For richer detail (CVSS scores, CWEs, fix recommendations), use npm_audit_deep instead.",
|
|
22247
22413
|
annotations: {
|
|
22248
22414
|
title: "Audit packages",
|
|
22249
22415
|
readOnlyHint: true,
|
|
@@ -22260,7 +22426,7 @@ var securityTools = [
|
|
|
22260
22426
|
},
|
|
22261
22427
|
{
|
|
22262
22428
|
name: "npm_audit_deep",
|
|
22263
|
-
description: "
|
|
22429
|
+
description: "Full security audit on a dependency set \u2014 returns detailed advisories with CVSS scores, CWEs, affected version ranges, fix recommendations, and full vulnerability metadata. Uses the npm audit v1 endpoint which provides richer detail than the bulk advisory API (npm_audit). Requires you to provide the dependency map (use npm_dependencies to get it first).",
|
|
22264
22430
|
annotations: {
|
|
22265
22431
|
title: "Deep security audit",
|
|
22266
22432
|
readOnlyHint: true,
|
|
@@ -22302,6 +22468,60 @@ var securityTools = [
|
|
|
22302
22468
|
}
|
|
22303
22469
|
];
|
|
22304
22470
|
|
|
22471
|
+
// src/tools/trust.ts
|
|
22472
|
+
var trustTools = [
|
|
22473
|
+
{
|
|
22474
|
+
name: "npm_trusted_publishers",
|
|
22475
|
+
description: "List trusted publishing configurations for a package. Shows OIDC trust relationships with CI/CD providers (GitHub Actions, GitLab CI, CircleCI) that allow tokenless publishing. Requires authentication with write access to the package.",
|
|
22476
|
+
annotations: {
|
|
22477
|
+
title: "List trusted publishers",
|
|
22478
|
+
readOnlyHint: true,
|
|
22479
|
+
destructiveHint: false,
|
|
22480
|
+
idempotentHint: true,
|
|
22481
|
+
openWorldHint: true
|
|
22482
|
+
},
|
|
22483
|
+
inputSchema: external_exports.object({
|
|
22484
|
+
name: external_exports.string().describe("Package name (e.g. 'express' or '@yawlabs/npmjs-mcp')")
|
|
22485
|
+
}),
|
|
22486
|
+
handler: async (input) => {
|
|
22487
|
+
const authErr = requireAuth();
|
|
22488
|
+
if (authErr) return authErr;
|
|
22489
|
+
const res = await registryGetAuth(`/-/package/${encPkg(input.name)}/trust`);
|
|
22490
|
+
if (!res.ok) return res;
|
|
22491
|
+
const configs = (res.data ?? []).map((c) => {
|
|
22492
|
+
const result = {
|
|
22493
|
+
id: c.id,
|
|
22494
|
+
provider: c.type
|
|
22495
|
+
};
|
|
22496
|
+
if (c.type === "github") {
|
|
22497
|
+
result.repository = c.claims?.repository;
|
|
22498
|
+
const workflowRef = c.claims?.workflow_ref;
|
|
22499
|
+
result.workflowFile = workflowRef?.file;
|
|
22500
|
+
result.environment = c.claims?.environment;
|
|
22501
|
+
} else if (c.type === "gitlab") {
|
|
22502
|
+
result.project = c.claims?.project_path;
|
|
22503
|
+
const configRef = c.claims?.ci_config_ref_uri;
|
|
22504
|
+
result.configFile = configRef?.file;
|
|
22505
|
+
result.environment = c.claims?.environment;
|
|
22506
|
+
} else if (c.type === "circleci") {
|
|
22507
|
+
result.project = c.claims?.project_id;
|
|
22508
|
+
result.context = c.claims?.context_ids;
|
|
22509
|
+
}
|
|
22510
|
+
return result;
|
|
22511
|
+
});
|
|
22512
|
+
return {
|
|
22513
|
+
ok: true,
|
|
22514
|
+
status: 200,
|
|
22515
|
+
data: {
|
|
22516
|
+
package: input.name,
|
|
22517
|
+
trustedPublisherCount: configs.length,
|
|
22518
|
+
trustedPublishers: configs
|
|
22519
|
+
}
|
|
22520
|
+
};
|
|
22521
|
+
}
|
|
22522
|
+
}
|
|
22523
|
+
];
|
|
22524
|
+
|
|
22305
22525
|
// src/tools/workflows.ts
|
|
22306
22526
|
var workflowTools = [
|
|
22307
22527
|
{
|
|
@@ -22576,7 +22796,7 @@ var workflowTools = [
|
|
|
22576
22796
|
];
|
|
22577
22797
|
|
|
22578
22798
|
// src/index.ts
|
|
22579
|
-
var version2 = true ? "0.
|
|
22799
|
+
var version2 = true ? "0.5.0" : (await null).createRequire(import.meta.url)("../package.json").version;
|
|
22580
22800
|
var subcommand = process.argv[2];
|
|
22581
22801
|
if (subcommand === "version" || subcommand === "--version") {
|
|
22582
22802
|
console.log(version2);
|
|
@@ -22594,7 +22814,7 @@ var allTools = [
|
|
|
22594
22814
|
...orgTools,
|
|
22595
22815
|
...accessTools,
|
|
22596
22816
|
...provenanceTools,
|
|
22597
|
-
...
|
|
22817
|
+
...trustTools,
|
|
22598
22818
|
...workflowTools
|
|
22599
22819
|
];
|
|
22600
22820
|
var server = new McpServer({
|
package/package.json
CHANGED