@yawlabs/npmjs-mcp 0.3.0 → 0.4.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.
Files changed (2) hide show
  1. package/dist/index.js +281 -94
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -21087,6 +21087,78 @@ function downloadsGet(path) {
21087
21087
  function replicateGet(path) {
21088
21088
  return request(REPLICATE_URL, path);
21089
21089
  }
21090
+ function parseSemver(v) {
21091
+ const m = v.match(/^(\d+)\.(\d+)\.(\d+)/);
21092
+ return m ? [Number(m[1]), Number(m[2]), Number(m[3])] : null;
21093
+ }
21094
+ function cmpSemver(a, b) {
21095
+ for (let i = 0; i < 3; i++) {
21096
+ if (a[i] < b[i]) return -1;
21097
+ if (a[i] > b[i]) return 1;
21098
+ }
21099
+ return 0;
21100
+ }
21101
+ function maxSatisfying(versions, range) {
21102
+ const r = range.trim().replace(/^v/, "");
21103
+ if (versions.includes(r)) return r;
21104
+ let minInclusive = null;
21105
+ let maxExclusive = null;
21106
+ if (r.startsWith("^")) {
21107
+ const base = parseSemver(r.slice(1));
21108
+ if (!base) return null;
21109
+ minInclusive = base;
21110
+ if (base[0] > 0) maxExclusive = [base[0] + 1, 0, 0];
21111
+ else if (base[1] > 0) maxExclusive = [0, base[1] + 1, 0];
21112
+ else maxExclusive = [0, 0, base[2] + 1];
21113
+ } else if (r.startsWith("~")) {
21114
+ const base = parseSemver(r.slice(1));
21115
+ if (!base) return null;
21116
+ minInclusive = base;
21117
+ maxExclusive = [base[0], base[1] + 1, 0];
21118
+ } else if (r.startsWith(">=")) {
21119
+ const base = parseSemver(r.slice(2));
21120
+ if (!base) return null;
21121
+ minInclusive = base;
21122
+ } else if (r.startsWith("<=")) {
21123
+ const base = parseSemver(r.slice(2));
21124
+ if (!base) return null;
21125
+ maxExclusive = [base[0], base[1], base[2] + 1];
21126
+ } else {
21127
+ const xm = r.match(/^(\d+)(?:\.(\d+|x)(?:\.(\d+|x))?)?$/);
21128
+ if (xm) {
21129
+ const major = Number(xm[1]);
21130
+ const minor = xm[2] !== void 0 && xm[2] !== "x" ? Number(xm[2]) : null;
21131
+ if (minor === null) {
21132
+ minInclusive = [major, 0, 0];
21133
+ maxExclusive = [major + 1, 0, 0];
21134
+ } else {
21135
+ const patch = xm[3] !== void 0 && xm[3] !== "x" ? Number(xm[3]) : null;
21136
+ if (patch === null) {
21137
+ minInclusive = [major, minor, 0];
21138
+ maxExclusive = [major, minor + 1, 0];
21139
+ } else {
21140
+ return null;
21141
+ }
21142
+ }
21143
+ } else {
21144
+ return null;
21145
+ }
21146
+ }
21147
+ let best = null;
21148
+ let bestParsed = null;
21149
+ for (const v of versions) {
21150
+ if (v.includes("-") && !r.includes("-")) continue;
21151
+ const parsed = parseSemver(v);
21152
+ if (!parsed) continue;
21153
+ if (minInclusive && cmpSemver(parsed, minInclusive) < 0) continue;
21154
+ if (maxExclusive && cmpSemver(parsed, maxExclusive) >= 0) continue;
21155
+ if (!bestParsed || cmpSemver(parsed, bestParsed) > 0) {
21156
+ best = v;
21157
+ bestParsed = parsed;
21158
+ }
21159
+ }
21160
+ return best;
21161
+ }
21090
21162
 
21091
21163
  // src/tools/access.ts
21092
21164
  var accessTools = [
@@ -21184,12 +21256,9 @@ var analysisTools = [
21184
21256
  handler: async (input) => {
21185
21257
  const results = await Promise.all(
21186
21258
  input.packages.map(async (name) => {
21187
- const [pkgRes, dlRes, auditRes] = await Promise.all([
21259
+ const [pkgRes, dlRes] = await Promise.all([
21188
21260
  registryGet(`/${encPkg(name)}`),
21189
- downloadsGet(`/downloads/point/last-week/${encPkg(name)}`),
21190
- registryPost("/-/npm/v1/security/advisories/bulk", {
21191
- [name]: ["latest"]
21192
- })
21261
+ downloadsGet(`/downloads/point/last-week/${encPkg(name)}`)
21193
21262
  ]);
21194
21263
  if (!pkgRes.ok) {
21195
21264
  return { name, error: pkgRes.error };
@@ -21198,6 +21267,15 @@ var analysisTools = [
21198
21267
  const latest = pkg["dist-tags"]?.latest;
21199
21268
  const latestVersion = latest ? pkg.versions[latest] : void 0;
21200
21269
  const versionKeys = Object.keys(pkg.versions);
21270
+ let vulnerabilities = 0;
21271
+ if (latest) {
21272
+ const auditRes = await registryPost("/-/npm/v1/security/advisories/bulk", {
21273
+ [name]: [latest]
21274
+ });
21275
+ if (auditRes.ok && auditRes.data?.[name]) {
21276
+ vulnerabilities = auditRes.data[name].length;
21277
+ }
21278
+ }
21201
21279
  return {
21202
21280
  name,
21203
21281
  description: pkg.description,
@@ -21212,7 +21290,7 @@ var analysisTools = [
21212
21290
  hasReadme: !!(pkg.readme && pkg.readme.length > 0),
21213
21291
  repository: pkg.repository,
21214
21292
  homepage: pkg.homepage,
21215
- vulnerabilities: auditRes.ok && auditRes.data?.[name] ? auditRes.data[name].length : 0
21293
+ vulnerabilities
21216
21294
  };
21217
21295
  })
21218
21296
  );
@@ -21243,6 +21321,16 @@ var analysisTools = [
21243
21321
  const latest = pkg["dist-tags"]?.latest;
21244
21322
  const latestVersion = latest ? pkg.versions[latest] : void 0;
21245
21323
  const versionKeys = Object.keys(pkg.versions);
21324
+ let vulnerabilityCount = null;
21325
+ if (latest) {
21326
+ const auditRes = await registryPost("/-/npm/v1/security/advisories/bulk", {
21327
+ [input.name]: [latest]
21328
+ });
21329
+ if (auditRes.ok) {
21330
+ const advisories = auditRes.data?.[input.name];
21331
+ vulnerabilityCount = Array.isArray(advisories) ? advisories.length : 0;
21332
+ }
21333
+ }
21246
21334
  const publishDates = versionKeys.map((v) => pkg.time[v]).filter(Boolean).map((d) => new Date(d).getTime()).sort((a, b) => b - a);
21247
21335
  const now = Date.now();
21248
21336
  const daysSinceLastPublish = publishDates.length > 0 ? Math.floor((now - publishDates[0]) / 864e5) : null;
@@ -21274,6 +21362,7 @@ var analysisTools = [
21274
21362
  versionCount: versionKeys.length,
21275
21363
  daysSinceLastPublish,
21276
21364
  avgDaysBetweenReleases,
21365
+ vulnerabilityCount,
21277
21366
  hasLicense,
21278
21367
  hasReadme,
21279
21368
  hasRepo,
@@ -21454,7 +21543,6 @@ var authTools = [
21454
21543
  data: {
21455
21544
  total: data.total,
21456
21545
  tokens: data.objects.map((t) => ({
21457
- token: t.token,
21458
21546
  key: t.key,
21459
21547
  readonly: t.readonly,
21460
21548
  cidrWhitelist: t.cidr_whitelist,
@@ -21464,6 +21552,38 @@ var authTools = [
21464
21552
  }
21465
21553
  };
21466
21554
  }
21555
+ },
21556
+ {
21557
+ name: "npm_user_packages",
21558
+ description: "List all packages published by a specific npm user. Shows package names and the user's access level for each. Requires authentication.",
21559
+ annotations: {
21560
+ title: "List user packages",
21561
+ readOnlyHint: true,
21562
+ destructiveHint: false,
21563
+ idempotentHint: true,
21564
+ openWorldHint: true
21565
+ },
21566
+ inputSchema: external_exports.object({
21567
+ username: external_exports.string().describe("npm username")
21568
+ }),
21569
+ handler: async (input) => {
21570
+ const authErr = requireAuth();
21571
+ if (authErr) return authErr;
21572
+ const res = await registryGetAuth(
21573
+ `/-/user/org.couchdb.user:${encodeURIComponent(input.username)}/package`
21574
+ );
21575
+ if (!res.ok) return res;
21576
+ const packages = Object.entries(res.data).map(([name, access]) => ({ name, access }));
21577
+ return {
21578
+ ok: true,
21579
+ status: 200,
21580
+ data: {
21581
+ username: input.username,
21582
+ packageCount: packages.length,
21583
+ packages
21584
+ }
21585
+ };
21586
+ }
21467
21587
  }
21468
21588
  ];
21469
21589
 
@@ -21541,8 +21661,8 @@ var dependencyTools = [
21541
21661
  else queue.push(run);
21542
21662
  });
21543
21663
  }
21544
- async function resolve(name, versionHint, currentDepth) {
21545
- const hintKey = `${name}@${versionHint}`;
21664
+ async function resolve(name, versionHint2, currentDepth) {
21665
+ const hintKey = `${name}@${versionHint2}`;
21546
21666
  if (resolved.has(hintKey) || currentDepth > maxDepth) return;
21547
21667
  resolved.add(hintKey);
21548
21668
  let pkg = packumentCache.get(name);
@@ -21550,19 +21670,21 @@ var dependencyTools = [
21550
21670
  const res = await runLimited(() => registryGetAbbreviated(`/${encPkg(name)}`));
21551
21671
  if (!res.ok) {
21552
21672
  warnings.push(`Failed to fetch ${name}: ${res.error}`);
21553
- tree[hintKey] = { version: versionHint, dependencies: {} };
21673
+ tree[hintKey] = { version: versionHint2, dependencies: {} };
21554
21674
  return;
21555
21675
  }
21556
21676
  pkg = res.data;
21557
21677
  packumentCache.set(name, pkg);
21558
21678
  }
21559
21679
  let resolvedVersion;
21560
- if (pkg.versions[versionHint]) {
21561
- resolvedVersion = versionHint;
21562
- } else if (pkg["dist-tags"][versionHint]) {
21563
- resolvedVersion = pkg["dist-tags"][versionHint];
21680
+ if (pkg.versions[versionHint2]) {
21681
+ resolvedVersion = versionHint2;
21682
+ } else if (pkg["dist-tags"][versionHint2]) {
21683
+ resolvedVersion = pkg["dist-tags"][versionHint2];
21564
21684
  } else {
21565
- resolvedVersion = pkg["dist-tags"]?.latest ?? versionHint;
21685
+ const available = Object.keys(pkg.versions);
21686
+ const matched = maxSatisfying(available, versionHint2);
21687
+ resolvedVersion = matched ?? pkg["dist-tags"]?.latest ?? versionHint2;
21566
21688
  }
21567
21689
  const resolvedKey = `${name}@${resolvedVersion}`;
21568
21690
  if (tree[resolvedKey]) return;
@@ -21578,12 +21700,14 @@ var dependencyTools = [
21578
21700
  await Promise.all(tasks);
21579
21701
  }
21580
21702
  }
21581
- await resolve(input.name, input.version ?? "latest", 1);
21703
+ const versionHint = input.version ?? "latest";
21704
+ await resolve(input.name, versionHint, 1);
21705
+ const rootKey = Object.keys(tree).find((k) => k.startsWith(`${input.name}@`)) ?? `${input.name}@${versionHint}`;
21582
21706
  return {
21583
21707
  ok: true,
21584
21708
  status: 200,
21585
21709
  data: {
21586
- root: `${input.name}@${input.version ?? "latest"}`,
21710
+ root: rootKey,
21587
21711
  depth: maxDepth,
21588
21712
  totalPackages: Object.keys(tree).length,
21589
21713
  tree,
@@ -21614,7 +21738,7 @@ var dependencyTools = [
21614
21738
  const res = await registryGet(`/${encPkg(input.name)}/${ver}`);
21615
21739
  if (!res.ok) return res;
21616
21740
  const pkg = res.data;
21617
- const deps = Object.keys(pkg.dependencies ?? {});
21741
+ const depEntries = Object.entries(pkg.dependencies ?? {});
21618
21742
  const MAX_CONCURRENT = 10;
21619
21743
  let active = 0;
21620
21744
  const queue = [];
@@ -21632,21 +21756,25 @@ var dependencyTools = [
21632
21756
  });
21633
21757
  }
21634
21758
  const depLicenses = await Promise.all(
21635
- deps.map(async (depName) => {
21636
- const depRes = await runLimited(() => registryGet(`/${encPkg(depName)}/latest`));
21759
+ depEntries.map(async ([depName, depRange]) => {
21760
+ const abbrevRes = await runLimited(() => registryGetAbbreviated(`/${encPkg(depName)}`));
21761
+ if (!abbrevRes.ok) return { name: depName, version: depRange, license: "FETCH_ERROR" };
21762
+ const abbrev = abbrevRes.data;
21763
+ const available = Object.keys(abbrev.versions);
21764
+ const resolved = maxSatisfying(available, depRange) ?? abbrev["dist-tags"]?.latest;
21765
+ if (!resolved) return { name: depName, version: depRange, license: "UNKNOWN" };
21766
+ const verRes = await runLimited(() => registryGet(`/${encPkg(depName)}/${resolved}`));
21637
21767
  return {
21638
21768
  name: depName,
21639
- license: depRes.ok ? depRes.data?.license ?? "UNKNOWN" : "FETCH_ERROR"
21769
+ version: resolved,
21770
+ license: verRes.ok ? verRes.data?.license ?? "UNKNOWN" : "FETCH_ERROR"
21640
21771
  };
21641
21772
  })
21642
21773
  );
21643
21774
  const allowedSet = new Set(
21644
21775
  input.allowed ?? ["MIT", "ISC", "BSD-2-Clause", "BSD-3-Clause", "Apache-2.0", "0BSD", "Unlicense"]
21645
21776
  );
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
- ];
21777
+ const results = [{ name: pkg.name, version: pkg.version, license: pkg.license ?? "UNKNOWN" }, ...depLicenses];
21650
21778
  const flagged = results.filter((r) => !allowedSet.has(r.license));
21651
21779
  return {
21652
21780
  ok: true,
@@ -21744,57 +21872,6 @@ var downloadTools = [
21744
21872
  }
21745
21873
  ];
21746
21874
 
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
21875
  // src/tools/orgs.ts
21799
21876
  var orgTools = [
21800
21877
  {
@@ -22019,7 +22096,7 @@ var packageTools = [
22019
22096
  },
22020
22097
  {
22021
22098
  name: "npm_versions",
22022
- description: "List all published versions of a package with their publish dates, ordered newest first.",
22099
+ 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
22100
  annotations: {
22024
22101
  title: "List versions",
22025
22102
  readOnlyHint: true,
@@ -22028,25 +22105,29 @@ var packageTools = [
22028
22105
  openWorldHint: true
22029
22106
  },
22030
22107
  inputSchema: external_exports.object({
22031
- name: external_exports.string().describe("Package name")
22108
+ name: external_exports.string().describe("Package name"),
22109
+ limit: external_exports.number().min(0).optional().describe("Max versions to return, newest first (default 50, 0 = all)")
22032
22110
  }),
22033
22111
  handler: async (input) => {
22034
22112
  const res = await registryGet(`/${encPkg(input.name)}`);
22035
22113
  if (!res.ok) return res;
22036
22114
  const pkg = res.data;
22037
- const versions = Object.keys(pkg.versions).map((v) => ({
22115
+ const limit = input.limit ?? 50;
22116
+ const allVersions = Object.keys(pkg.versions).map((v) => ({
22038
22117
  version: v,
22039
22118
  date: pkg.time[v],
22040
22119
  deprecated: pkg.versions[v].deprecated,
22041
22120
  npmUser: pkg.versions[v]._npmUser?.name
22042
22121
  })).sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime());
22122
+ const versions = limit > 0 ? allVersions.slice(0, limit) : allVersions;
22043
22123
  return {
22044
22124
  ok: true,
22045
22125
  status: 200,
22046
22126
  data: {
22047
22127
  name: pkg.name,
22048
22128
  distTags: pkg["dist-tags"],
22049
- total: versions.length,
22129
+ total: allVersions.length,
22130
+ showing: versions.length,
22050
22131
  versions
22051
22132
  }
22052
22133
  };
@@ -22091,6 +22172,61 @@ var packageTools = [
22091
22172
  handler: async (input) => {
22092
22173
  return registryGet(`/-/package/${encPkg(input.name)}/dist-tags`);
22093
22174
  }
22175
+ },
22176
+ {
22177
+ name: "npm_types",
22178
+ 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).",
22179
+ annotations: {
22180
+ title: "Check TypeScript types",
22181
+ readOnlyHint: true,
22182
+ destructiveHint: false,
22183
+ idempotentHint: true,
22184
+ openWorldHint: true
22185
+ },
22186
+ inputSchema: external_exports.object({
22187
+ name: external_exports.string().describe("Package name (e.g. 'express' or '@anthropic-ai/sdk')"),
22188
+ version: external_exports.string().optional().describe("Semver version or dist-tag (default: 'latest')")
22189
+ }),
22190
+ handler: async (input) => {
22191
+ const ver = input.version ?? "latest";
22192
+ let typesPackage;
22193
+ if (input.name.startsWith("@")) {
22194
+ const withoutAt = input.name.slice(1);
22195
+ typesPackage = `@types/${withoutAt.replace("/", "__")}`;
22196
+ } else {
22197
+ typesPackage = `@types/${input.name}`;
22198
+ }
22199
+ const [versionRes, typesRes] = await Promise.all([
22200
+ registryGet(`/${encPkg(input.name)}/${ver}`),
22201
+ registryGet(`/${encPkg(typesPackage)}`)
22202
+ ]);
22203
+ if (!versionRes.ok) return versionRes;
22204
+ const v = versionRes.data;
22205
+ const hasBuiltinTypes = !!(v.types || v.typings);
22206
+ const typesEntry = hasBuiltinTypes ? v.types ?? v.typings : void 0;
22207
+ const hasTypesPackage = typesRes.ok;
22208
+ const typesPackageLatest = hasTypesPackage ? typesRes.data?.["dist-tags"]?.latest : void 0;
22209
+ let recommendation;
22210
+ if (hasBuiltinTypes) {
22211
+ recommendation = "Built-in types included \u2014 no additional install needed.";
22212
+ } else if (hasTypesPackage) {
22213
+ recommendation = `Install types separately: npm install -D ${typesPackage}`;
22214
+ } else {
22215
+ recommendation = "No TypeScript types available (built-in or @types).";
22216
+ }
22217
+ return {
22218
+ ok: true,
22219
+ status: 200,
22220
+ data: {
22221
+ name: v.name,
22222
+ version: v.version,
22223
+ builtinTypes: hasBuiltinTypes,
22224
+ typesEntry,
22225
+ typesPackage: hasTypesPackage ? { name: typesPackage, latest: typesPackageLatest } : null,
22226
+ recommendation
22227
+ }
22228
+ };
22229
+ }
22094
22230
  }
22095
22231
  ];
22096
22232
 
@@ -22157,7 +22293,7 @@ var registryTools = [
22157
22293
  },
22158
22294
  {
22159
22295
  name: "npm_recent_changes",
22160
- description: "Get the most recent package publishes/updates from the npm registry via the CouchDB changes feed.",
22296
+ 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
22297
  annotations: {
22162
22298
  title: "Recent registry changes",
22163
22299
  readOnlyHint: true,
@@ -22170,21 +22306,20 @@ var registryTools = [
22170
22306
  }),
22171
22307
  handler: async (input) => {
22172
22308
  const limit = input.limit ?? 25;
22173
- const dbRes = await replicateGet("/");
22174
- if (!dbRes.ok) return dbRes;
22175
- const since = dbRes.data.update_seq - limit;
22176
- const changesRes = await replicateGet(`/_changes?since=${since}&limit=${limit}&descending=false`);
22309
+ const [dbRes, changesRes] = await Promise.all([
22310
+ replicateGet("/"),
22311
+ replicateGet(`/_changes?limit=${limit}&descending=true`)
22312
+ ]);
22177
22313
  if (!changesRes.ok) return changesRes;
22178
22314
  const changes = changesRes.data.results.map((r) => ({
22179
22315
  package: r.id,
22180
- seq: r.seq,
22181
22316
  rev: r.changes[0]?.rev
22182
22317
  }));
22183
22318
  return {
22184
22319
  ok: true,
22185
22320
  status: 200,
22186
22321
  data: {
22187
- totalPackages: dbRes.data.doc_count,
22322
+ totalPackages: dbRes.ok ? dbRes.data.doc_count : null,
22188
22323
  changes
22189
22324
  }
22190
22325
  };
@@ -22230,9 +22365,7 @@ var searchTools = [
22230
22365
  publisher: obj.package.publisher,
22231
22366
  keywords: obj.package.keywords,
22232
22367
  links: obj.package.links,
22233
- score: obj.score.detail,
22234
- downloads: obj.downloads,
22235
- dependents: obj.dependents
22368
+ score: obj.score.detail
22236
22369
  }));
22237
22370
  return { ok: true, status: 200, data: { total: res.data.total, results } };
22238
22371
  }
@@ -22243,7 +22376,7 @@ var searchTools = [
22243
22376
  var securityTools = [
22244
22377
  {
22245
22378
  name: "npm_audit",
22246
- description: "Check specific packages and versions for known vulnerabilities. Returns advisories with severity, CVEs, and patched versions.",
22379
+ 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
22380
  annotations: {
22248
22381
  title: "Audit packages",
22249
22382
  readOnlyHint: true,
@@ -22260,7 +22393,7 @@ var securityTools = [
22260
22393
  },
22261
22394
  {
22262
22395
  name: "npm_audit_deep",
22263
- description: "Run a full security audit on a set of dependencies. Returns detailed advisories with CVSS scores, CWEs, fix recommendations, and vulnerability metadata.",
22396
+ 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
22397
  annotations: {
22265
22398
  title: "Deep security audit",
22266
22399
  readOnlyHint: true,
@@ -22302,6 +22435,60 @@ var securityTools = [
22302
22435
  }
22303
22436
  ];
22304
22437
 
22438
+ // src/tools/trust.ts
22439
+ var trustTools = [
22440
+ {
22441
+ name: "npm_trusted_publishers",
22442
+ 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.",
22443
+ annotations: {
22444
+ title: "List trusted publishers",
22445
+ readOnlyHint: true,
22446
+ destructiveHint: false,
22447
+ idempotentHint: true,
22448
+ openWorldHint: true
22449
+ },
22450
+ inputSchema: external_exports.object({
22451
+ name: external_exports.string().describe("Package name (e.g. 'express' or '@yawlabs/npmjs-mcp')")
22452
+ }),
22453
+ handler: async (input) => {
22454
+ const authErr = requireAuth();
22455
+ if (authErr) return authErr;
22456
+ const res = await registryGetAuth(`/-/package/${encPkg(input.name)}/trust`);
22457
+ if (!res.ok) return res;
22458
+ const configs = (res.data ?? []).map((c) => {
22459
+ const result = {
22460
+ id: c.id,
22461
+ provider: c.type
22462
+ };
22463
+ if (c.type === "github") {
22464
+ result.repository = c.claims?.repository;
22465
+ const workflowRef = c.claims?.workflow_ref;
22466
+ result.workflowFile = workflowRef?.file;
22467
+ result.environment = c.claims?.environment;
22468
+ } else if (c.type === "gitlab") {
22469
+ result.project = c.claims?.project_path;
22470
+ const configRef = c.claims?.ci_config_ref_uri;
22471
+ result.configFile = configRef?.file;
22472
+ result.environment = c.claims?.environment;
22473
+ } else if (c.type === "circleci") {
22474
+ result.project = c.claims?.project_id;
22475
+ result.context = c.claims?.context_ids;
22476
+ }
22477
+ return result;
22478
+ });
22479
+ return {
22480
+ ok: true,
22481
+ status: 200,
22482
+ data: {
22483
+ package: input.name,
22484
+ trustedPublisherCount: configs.length,
22485
+ trustedPublishers: configs
22486
+ }
22487
+ };
22488
+ }
22489
+ }
22490
+ ];
22491
+
22305
22492
  // src/tools/workflows.ts
22306
22493
  var workflowTools = [
22307
22494
  {
@@ -22576,7 +22763,7 @@ var workflowTools = [
22576
22763
  ];
22577
22764
 
22578
22765
  // src/index.ts
22579
- var version2 = true ? "0.3.0" : (await null).createRequire(import.meta.url)("../package.json").version;
22766
+ var version2 = true ? "0.4.0" : (await null).createRequire(import.meta.url)("../package.json").version;
22580
22767
  var subcommand = process.argv[2];
22581
22768
  if (subcommand === "version" || subcommand === "--version") {
22582
22769
  console.log(version2);
@@ -22594,7 +22781,7 @@ var allTools = [
22594
22781
  ...orgTools,
22595
22782
  ...accessTools,
22596
22783
  ...provenanceTools,
22597
- ...hookTools,
22784
+ ...trustTools,
22598
22785
  ...workflowTools
22599
22786
  ];
22600
22787
  var server = new McpServer({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yawlabs/npmjs-mcp",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "npm registry MCP server — package intelligence, security audits, and dependency analysis for AI assistants",
5
5
  "license": "MIT",
6
6
  "author": "YawLabs <contact@yaw.sh>",