mcp-scorecard 0.1.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 (67) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/LICENSE +21 -0
  3. package/README.md +187 -0
  4. package/dist/audit/checks/agent-manifest.d.ts +12 -0
  5. package/dist/audit/checks/agent-manifest.js +72 -0
  6. package/dist/audit/checks/agent-manifest.js.map +1 -0
  7. package/dist/audit/checks/annotations.d.ts +10 -0
  8. package/dist/audit/checks/annotations.js +54 -0
  9. package/dist/audit/checks/annotations.js.map +1 -0
  10. package/dist/audit/checks/manifest-discoverability.d.ts +13 -0
  11. package/dist/audit/checks/manifest-discoverability.js +48 -0
  12. package/dist/audit/checks/manifest-discoverability.js.map +1 -0
  13. package/dist/audit/checks/mutation-gating.d.ts +14 -0
  14. package/dist/audit/checks/mutation-gating.js +58 -0
  15. package/dist/audit/checks/mutation-gating.js.map +1 -0
  16. package/dist/audit/checks/privacy-modes.d.ts +17 -0
  17. package/dist/audit/checks/privacy-modes.js +62 -0
  18. package/dist/audit/checks/privacy-modes.js.map +1 -0
  19. package/dist/audit/checks/resources.d.ts +10 -0
  20. package/dist/audit/checks/resources.js +39 -0
  21. package/dist/audit/checks/resources.js.map +1 -0
  22. package/dist/audit/checks/schema-validity.d.ts +9 -0
  23. package/dist/audit/checks/schema-validity.js +59 -0
  24. package/dist/audit/checks/schema-validity.js.map +1 -0
  25. package/dist/audit/checks/smoke-test.d.ts +14 -0
  26. package/dist/audit/checks/smoke-test.js +59 -0
  27. package/dist/audit/checks/smoke-test.js.map +1 -0
  28. package/dist/audit/checks/tool-descriptions.d.ts +13 -0
  29. package/dist/audit/checks/tool-descriptions.js +59 -0
  30. package/dist/audit/checks/tool-descriptions.js.map +1 -0
  31. package/dist/audit/checks/tool-naming.d.ts +16 -0
  32. package/dist/audit/checks/tool-naming.js +81 -0
  33. package/dist/audit/checks/tool-naming.js.map +1 -0
  34. package/dist/audit/probe.d.ts +20 -0
  35. package/dist/audit/probe.js +145 -0
  36. package/dist/audit/probe.js.map +1 -0
  37. package/dist/audit/runner.d.ts +9 -0
  38. package/dist/audit/runner.js +77 -0
  39. package/dist/audit/runner.js.map +1 -0
  40. package/dist/audit/scorer.d.ts +8 -0
  41. package/dist/audit/scorer.js +17 -0
  42. package/dist/audit/scorer.js.map +1 -0
  43. package/dist/cli/commands.d.ts +10 -0
  44. package/dist/cli/commands.js +123 -0
  45. package/dist/cli/commands.js.map +1 -0
  46. package/dist/cli/output.d.ts +13 -0
  47. package/dist/cli/output.js +76 -0
  48. package/dist/cli/output.js.map +1 -0
  49. package/dist/constants.d.ts +28 -0
  50. package/dist/constants.js +54 -0
  51. package/dist/constants.js.map +1 -0
  52. package/dist/index.d.ts +2 -0
  53. package/dist/index.js +13 -0
  54. package/dist/index.js.map +1 -0
  55. package/dist/resolvers/github-resolver.d.ts +10 -0
  56. package/dist/resolvers/github-resolver.js +65 -0
  57. package/dist/resolvers/github-resolver.js.map +1 -0
  58. package/dist/resolvers/local-resolver.d.ts +8 -0
  59. package/dist/resolvers/local-resolver.js +50 -0
  60. package/dist/resolvers/local-resolver.js.map +1 -0
  61. package/dist/resolvers/npm-resolver.d.ts +11 -0
  62. package/dist/resolvers/npm-resolver.js +100 -0
  63. package/dist/resolvers/npm-resolver.js.map +1 -0
  64. package/dist/types.d.ts +84 -0
  65. package/dist/types.js +6 -0
  66. package/dist/types.js.map +1 -0
  67. package/package.json +61 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runner.js","sourceRoot":"","sources":["../../src/audit/runner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Scorer — sums the 10 check scores (each 0..10) into a single 0..100.
3
+ *
4
+ * Currently every check has equal weight. Future versions may introduce
5
+ * weighting (CLI: --weights schema=2,naming=1,...). For now: trivially sum.
6
+ */
7
+ import type { CheckResult } from '../types.js';
8
+ export declare function aggregateScore(checks: CheckResult[]): number;
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Scorer — sums the 10 check scores (each 0..10) into a single 0..100.
3
+ *
4
+ * Currently every check has equal weight. Future versions may introduce
5
+ * weighting (CLI: --weights schema=2,naming=1,...). For now: trivially sum.
6
+ */
7
+ const EXPECTED_CHECK_COUNT = 10;
8
+ export function aggregateScore(checks) {
9
+ if (checks.length === 0)
10
+ return 0;
11
+ // Use the expected denominator (10 checks * 10 each = 100); if a check
12
+ // failed to even run, we still divide by 10 so the score reflects gaps.
13
+ const sum = checks.reduce((acc, c) => acc + Math.max(0, Math.min(10, c.score)), 0);
14
+ const denom = EXPECTED_CHECK_COUNT * 10;
15
+ return Math.round((sum / denom) * 100);
16
+ }
17
+ //# sourceMappingURL=scorer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scorer.js","sourceRoot":"","sources":["../../src/audit/scorer.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,MAAM,oBAAoB,GAAG,EAAE,CAAC;AAEhC,MAAM,UAAU,cAAc,CAAC,MAAqB;IAClD,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,CAAC,CAAC;IAClC,uEAAuE;IACvE,wEAAwE;IACxE,MAAM,GAAG,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACnF,MAAM,KAAK,GAAG,oBAAoB,GAAG,EAAE,CAAC;IACxC,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,GAAG,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC;AACzC,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * CLI parser — plain argv, no commander. The first positional is the
3
+ * subject (npm package, GitHub URL, or absolute path). Flags:
4
+ *
5
+ * --json emit JSON instead of markdown
6
+ * --min-score N exit 1 if total score < N (CI gate)
7
+ * --version print scorecard version
8
+ * --help, -h print usage
9
+ */
10
+ export declare function run(argv: string[]): Promise<number>;
@@ -0,0 +1,123 @@
1
+ /**
2
+ * CLI parser — plain argv, no commander. The first positional is the
3
+ * subject (npm package, GitHub URL, or absolute path). Flags:
4
+ *
5
+ * --json emit JSON instead of markdown
6
+ * --min-score N exit 1 if total score < N (CI gate)
7
+ * --version print scorecard version
8
+ * --help, -h print usage
9
+ */
10
+ import { existsSync } from 'node:fs';
11
+ import { isAbsolute } from 'node:path';
12
+ import { SERVER_VERSION } from '../constants.js';
13
+ import { runAudit } from '../audit/runner.js';
14
+ import { resolveGithubRepo } from '../resolvers/github-resolver.js';
15
+ import { resolveLocal } from '../resolvers/local-resolver.js';
16
+ import { resolveNpmPackage } from '../resolvers/npm-resolver.js';
17
+ import { renderJson, renderMarkdown } from './output.js';
18
+ const USAGE = `mcp-scorecard v${SERVER_VERSION}
19
+
20
+ Usage:
21
+ mcp-scorecard <subject> [--json] [--min-score N]
22
+
23
+ Subjects:
24
+ npm-package e.g. whoop-mcp-unofficial[@version]
25
+ github-url e.g. https://github.com/davidmosiah/whoop-mcp
26
+ /abs/path/dist/index.js built MCP server entry
27
+
28
+ Flags:
29
+ --json emit structured JSON to stdout
30
+ --min-score N exit non-zero if total score < N (default 0)
31
+ --version print version
32
+ --help, -h print this message
33
+
34
+ Privacy: the probe sets MCP_PROBE=1 so MCP authors can detect an audit and
35
+ skip auth-only side effects. Probe responses are NEVER persisted; only
36
+ counts and field names are recorded. See the README for the security model.`;
37
+ function parseArgs(argv) {
38
+ const out = { json: false, minScore: 0, help: false, showVersion: false };
39
+ for (let i = 0; i < argv.length; i++) {
40
+ const arg = argv[i];
41
+ if (arg === '--help' || arg === '-h')
42
+ out.help = true;
43
+ else if (arg === '--version')
44
+ out.showVersion = true;
45
+ else if (arg === '--json')
46
+ out.json = true;
47
+ else if (arg === '--min-score') {
48
+ const v = argv[++i];
49
+ const n = Number.parseInt(v, 10);
50
+ if (!Number.isFinite(n))
51
+ throw new Error(`--min-score expects a number, got: ${v}`);
52
+ out.minScore = n;
53
+ }
54
+ else if (arg.startsWith('--')) {
55
+ throw new Error(`Unknown flag: ${arg}`);
56
+ }
57
+ else if (!out.subject) {
58
+ out.subject = arg;
59
+ }
60
+ }
61
+ return out;
62
+ }
63
+ function classifySubject(subject) {
64
+ if (/^https?:\/\/github\.com\//.test(subject) || /^github:/.test(subject))
65
+ return 'github';
66
+ if (isAbsolute(subject) && existsSync(subject))
67
+ return 'local';
68
+ return 'npm';
69
+ }
70
+ async function resolveSubject(subject) {
71
+ const kind = classifySubject(subject);
72
+ if (kind === 'github')
73
+ return resolveGithubRepo(subject);
74
+ if (kind === 'local')
75
+ return resolveLocal(subject);
76
+ return resolveNpmPackage(subject);
77
+ }
78
+ export async function run(argv) {
79
+ let parsed;
80
+ try {
81
+ parsed = parseArgs(argv);
82
+ }
83
+ catch (err) {
84
+ process.stderr.write(`${err instanceof Error ? err.message : String(err)}\n\n${USAGE}\n`);
85
+ return 2;
86
+ }
87
+ if (parsed.help) {
88
+ process.stdout.write(`${USAGE}\n`);
89
+ return 0;
90
+ }
91
+ if (parsed.showVersion) {
92
+ process.stdout.write(`${SERVER_VERSION}\n`);
93
+ return 0;
94
+ }
95
+ if (!parsed.subject) {
96
+ process.stderr.write(`Missing subject.\n\n${USAGE}\n`);
97
+ return 2;
98
+ }
99
+ let target;
100
+ try {
101
+ target = await resolveSubject(parsed.subject);
102
+ }
103
+ catch (err) {
104
+ process.stderr.write(`Resolver error: ${err instanceof Error ? err.message : String(err)}\n`);
105
+ return 1;
106
+ }
107
+ let report;
108
+ try {
109
+ report = await runAudit(target);
110
+ }
111
+ catch (err) {
112
+ process.stderr.write(`Audit error: ${err instanceof Error ? err.message : String(err)}\n`);
113
+ return 1;
114
+ }
115
+ process.stdout.write(parsed.json ? renderJson(report) : renderMarkdown(report));
116
+ process.stdout.write('\n');
117
+ if (report.totalScore < parsed.minScore) {
118
+ process.stderr.write(`\nScore ${report.totalScore} < --min-score ${parsed.minScore}\n`);
119
+ return 1;
120
+ }
121
+ return 0;
122
+ }
123
+ //# sourceMappingURL=commands.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commands.js","sourceRoot":"","sources":["../../src/cli/commands.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Output formatters: markdown (default) + json (--json).
3
+ *
4
+ * Markdown layout matches the spec sample. Status icons use plain text so
5
+ * the output is readable in non-emoji terminals too.
6
+ *
7
+ * Privacy: we run a redaction pass on any string going into details/fixes/
8
+ * summary, so a stray customer_id in a tool description doesn't leak.
9
+ */
10
+ import type { AuditReport } from '../types.js';
11
+ /** Markdown table-ish output suitable for terminals and PR comments. */
12
+ export declare function renderMarkdown(report: AuditReport): string;
13
+ export declare function renderJson(report: AuditReport): string;
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Output formatters: markdown (default) + json (--json).
3
+ *
4
+ * Markdown layout matches the spec sample. Status icons use plain text so
5
+ * the output is readable in non-emoji terminals too.
6
+ *
7
+ * Privacy: we run a redaction pass on any string going into details/fixes/
8
+ * summary, so a stray customer_id in a tool description doesn't leak.
9
+ */
10
+ import { REDACTION_KEYS } from '../constants.js';
11
+ const STATUS_ICON = {
12
+ pass: '[PASS]',
13
+ warn: '[WARN]',
14
+ fail: '[FAIL]'
15
+ };
16
+ const REDACTION_RE = new RegExp(`\\b(${REDACTION_KEYS.map((k) => k.replace(/_/g, '[_-]?')).join('|')})\\b\\s*[:=]\\s*([^\\s,]+)`, 'gi');
17
+ function redact(text) {
18
+ return text.replace(REDACTION_RE, (_full, key) => `${key}: [REDACTED]`);
19
+ }
20
+ function redactAll(items) {
21
+ return items.map(redact);
22
+ }
23
+ /** Markdown table-ish output suitable for terminals and PR comments. */
24
+ export function renderMarkdown(report) {
25
+ const lines = [];
26
+ const versionTag = report.target.version ? ` @${report.target.version}` : '';
27
+ lines.push(`# mcp-scorecard - ${report.target.displayName}${versionTag}`);
28
+ lines.push('');
29
+ lines.push(`**Agent-readiness score:** ${report.totalScore}/100`);
30
+ lines.push('');
31
+ for (const c of report.checks) {
32
+ lines.push(`- ${STATUS_ICON[c.status]} ${c.label.padEnd(28)} (${redact(c.summary)})`);
33
+ }
34
+ const detailLines = [];
35
+ for (const c of report.checks) {
36
+ if (c.details.length > 0) {
37
+ detailLines.push(`### ${c.label}`);
38
+ for (const d of redactAll(c.details)) {
39
+ detailLines.push(`- ${d}`);
40
+ }
41
+ }
42
+ }
43
+ if (detailLines.length > 0) {
44
+ lines.push('');
45
+ lines.push('## Details');
46
+ lines.push(...detailLines);
47
+ }
48
+ const fixLines = [];
49
+ for (const c of report.checks) {
50
+ if (c.fixes.length > 0) {
51
+ for (const f of redactAll(c.fixes)) {
52
+ fixLines.push(`- ${f}`);
53
+ }
54
+ }
55
+ }
56
+ if (fixLines.length > 0) {
57
+ lines.push('');
58
+ lines.push('## Suggested fixes');
59
+ lines.push(...fixLines);
60
+ }
61
+ lines.push('');
62
+ lines.push(`_Generated by mcp-scorecard v${report.scorecardVersion} at ${report.generatedAt}_`);
63
+ return lines.join('\n');
64
+ }
65
+ export function renderJson(report) {
66
+ // JSON output is also redacted at the string level so consumers don't
67
+ // accidentally persist secrets from probed servers.
68
+ const redactedChecks = report.checks.map((c) => ({
69
+ ...c,
70
+ summary: redact(c.summary),
71
+ details: redactAll(c.details),
72
+ fixes: redactAll(c.fixes)
73
+ }));
74
+ return JSON.stringify({ ...report, checks: redactedChecks }, null, 2);
75
+ }
76
+ //# sourceMappingURL=output.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"output.js","sourceRoot":"","sources":["../../src/cli/output.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Version pinned in source so the audit output and probe handshake show the
3
+ * same string. Bumping this without updating package.json is intentional during
4
+ * dev (keep src as source of truth); a release script can sync them.
5
+ */
6
+ export declare const SERVER_VERSION = "0.1.0";
7
+ /** Identifier used when the probe connects to a target MCP server. */
8
+ export declare const PROBE_CLIENT_NAME = "mcp-scorecard";
9
+ /** Env var set on the spawned target so MCP authors can detect we are probing
10
+ * and skip auth-only side effects. Documented in the README. */
11
+ export declare const PROBE_ENV_FLAG = "MCP_PROBE";
12
+ /**
13
+ * Patterns that imply a tool MUTATES state on the target system. We use these
14
+ * to score mutation gating — if a tool name matches and the description does
15
+ * not mention an explicit gate, it loses points.
16
+ */
17
+ export declare const MUTATION_PATTERNS: RegExp[];
18
+ /**
19
+ * Words that, when present in a mutation tool's description, signal the author
20
+ * thought about gating: env vars, explicit consent, dry-run, etc.
21
+ */
22
+ export declare const MUTATION_GATE_HINTS: string[];
23
+ /** Manifest-discoverability candidates — at least one must exist on target. */
24
+ export declare const DISCOVERY_TOOL_SUFFIXES: string[];
25
+ /** Field names that, if echoed back in tool descriptions, are redacted in
26
+ * output to avoid leaking real customer data when run against a logged-in
27
+ * server. */
28
+ export declare const REDACTION_KEYS: string[];
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Version pinned in source so the audit output and probe handshake show the
3
+ * same string. Bumping this without updating package.json is intentional during
4
+ * dev (keep src as source of truth); a release script can sync them.
5
+ */
6
+ export const SERVER_VERSION = '0.1.0';
7
+ /** Identifier used when the probe connects to a target MCP server. */
8
+ export const PROBE_CLIENT_NAME = 'mcp-scorecard';
9
+ /** Env var set on the spawned target so MCP authors can detect we are probing
10
+ * and skip auth-only side effects. Documented in the README. */
11
+ export const PROBE_ENV_FLAG = 'MCP_PROBE';
12
+ /**
13
+ * Patterns that imply a tool MUTATES state on the target system. We use these
14
+ * to score mutation gating — if a tool name matches and the description does
15
+ * not mention an explicit gate, it loses points.
16
+ */
17
+ export const MUTATION_PATTERNS = [
18
+ /(^|_)(set|update|delete|create|pause|resume|enable|disable|cancel|publish|send|remove|add|insert|patch|put|post)(_|$)/i
19
+ ];
20
+ /**
21
+ * Words that, when present in a mutation tool's description, signal the author
22
+ * thought about gating: env vars, explicit consent, dry-run, etc.
23
+ */
24
+ export const MUTATION_GATE_HINTS = [
25
+ 'gated by',
26
+ 'requires explicit',
27
+ 'explicit user intent',
28
+ 'allow_mutations',
29
+ 'dry-run',
30
+ 'dry_run',
31
+ 'confirm',
32
+ 'consent'
33
+ ];
34
+ /** Manifest-discoverability candidates — at least one must exist on target. */
35
+ export const DISCOVERY_TOOL_SUFFIXES = [
36
+ 'agent_manifest',
37
+ 'data_inventory',
38
+ 'capabilities',
39
+ 'connection_status'
40
+ ];
41
+ /** Field names that, if echoed back in tool descriptions, are redacted in
42
+ * output to avoid leaking real customer data when run against a logged-in
43
+ * server. */
44
+ export const REDACTION_KEYS = [
45
+ 'customer_id',
46
+ 'email',
47
+ 'phone',
48
+ 'access_token',
49
+ 'refresh_token',
50
+ 'client_secret',
51
+ 'developer_token',
52
+ 'api_key'
53
+ ];
54
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,OAAO,CAAC;AAEtC,sEAAsE;AACtE,MAAM,CAAC,MAAM,iBAAiB,GAAG,eAAe,CAAC;AAEjD;iEACiE;AACjE,MAAM,CAAC,MAAM,cAAc,GAAG,WAAW,CAAC;AAE1C;;;;GAIG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAa;IACzC,wHAAwH;CACzH,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG;IACjC,UAAU;IACV,mBAAmB;IACnB,sBAAsB;IACtB,iBAAiB;IACjB,SAAS;IACT,SAAS;IACT,SAAS;IACT,SAAS;CACV,CAAC;AAEF,+EAA+E;AAC/E,MAAM,CAAC,MAAM,uBAAuB,GAAG;IACrC,gBAAgB;IAChB,gBAAgB;IAChB,cAAc;IACd,mBAAmB;CACpB,CAAC;AAEF;;cAEc;AACd,MAAM,CAAC,MAAM,cAAc,GAAG;IAC5B,aAAa;IACb,OAAO;IACP,OAAO;IACP,cAAc;IACd,eAAe;IACf,eAAe;IACf,iBAAiB;IACjB,SAAS;CACV,CAAC"}
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * mcp-scorecard CLI entrypoint.
4
+ *
5
+ * Thin wrapper around src/cli/commands.ts so the bin field can point at
6
+ * a single file that just dispatches argv.
7
+ */
8
+ import { run } from './cli/commands.js';
9
+ run(process.argv.slice(2)).then((code) => process.exit(code), (err) => {
10
+ process.stderr.write(`Fatal: ${err instanceof Error ? err.stack ?? err.message : String(err)}\n`);
11
+ process.exit(1);
12
+ });
13
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;;;GAKG;AACH,OAAO,EAAE,GAAG,EAAE,MAAM,mBAAmB,CAAC;AAExC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAC7B,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAC5B,CAAC,GAAG,EAAE,EAAE;IACN,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAClG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CACF,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * GitHub resolver — extracts owner/repo from a URL, clones via `gh repo
3
+ * clone` into /tmp/scorecard-work/, reads package.json for the npm name,
4
+ * then delegates to npm resolver (so we audit what users actually `npx`).
5
+ *
6
+ * Falls back to launching from a local `dist/index.js` if the package was
7
+ * never published.
8
+ */
9
+ import type { ResolvedTarget } from '../types.js';
10
+ export declare function resolveGithubRepo(url: string): Promise<ResolvedTarget>;
@@ -0,0 +1,65 @@
1
+ /**
2
+ * GitHub resolver — extracts owner/repo from a URL, clones via `gh repo
3
+ * clone` into /tmp/scorecard-work/, reads package.json for the npm name,
4
+ * then delegates to npm resolver (so we audit what users actually `npx`).
5
+ *
6
+ * Falls back to launching from a local `dist/index.js` if the package was
7
+ * never published.
8
+ */
9
+ import { spawnSync } from 'node:child_process';
10
+ import { existsSync, mkdirSync, mkdtempSync, readFileSync } from 'node:fs';
11
+ import { join, resolve as pathResolve } from 'node:path';
12
+ import { resolveNpmPackage } from './npm-resolver.js';
13
+ const SCRATCH_ROOT = '/tmp/scorecard-work';
14
+ function parseOwnerRepo(input) {
15
+ const m = input.match(/^https?:\/\/github\.com\/([^/]+)\/([^/]+?)(?:\.git)?\/?$/i) ||
16
+ input.match(/^github:([^/]+)\/(.+)$/i);
17
+ if (!m)
18
+ return undefined;
19
+ return { owner: m[1], repo: m[2].replace(/\.git$/, '') };
20
+ }
21
+ export async function resolveGithubRepo(url) {
22
+ const parsed = parseOwnerRepo(url);
23
+ if (!parsed)
24
+ throw new Error(`Not a recognizable GitHub URL: ${url}`);
25
+ if (!existsSync(SCRATCH_ROOT))
26
+ mkdirSync(SCRATCH_ROOT, { recursive: true });
27
+ const dest = mkdtempSync(join(SCRATCH_ROOT, 'gh-'));
28
+ const cloneDir = join(dest, parsed.repo);
29
+ const gh = spawnSync('gh', ['repo', 'clone', `${parsed.owner}/${parsed.repo}`, cloneDir, '--', '--depth=1'], {
30
+ encoding: 'utf8'
31
+ });
32
+ if (gh.status !== 0) {
33
+ throw new Error(`gh repo clone failed for ${parsed.owner}/${parsed.repo}: ${gh.stderr}`);
34
+ }
35
+ const pkgJsonPath = join(cloneDir, 'package.json');
36
+ if (!existsSync(pkgJsonPath)) {
37
+ throw new Error(`Cloned repo has no package.json: ${pkgJsonPath}`);
38
+ }
39
+ const pkg = JSON.parse(readFileSync(pkgJsonPath, 'utf8'));
40
+ // Prefer auditing the published npm package — that's what agents actually
41
+ // pull via `npx -y <name>`. Falls back to local dist if npm pack fails.
42
+ if (typeof pkg.name === 'string') {
43
+ try {
44
+ return await resolveNpmPackage(pkg.name);
45
+ }
46
+ catch {
47
+ // package not published — try local dist
48
+ }
49
+ }
50
+ const localBin = pathResolve(cloneDir, (pkg.bin && typeof pkg.bin === 'object'
51
+ ? (Object.values(pkg.bin)[0] ?? 'dist/index.js')
52
+ : (typeof pkg.bin === 'string' ? pkg.bin : 'dist/index.js')));
53
+ if (!existsSync(localBin)) {
54
+ throw new Error(`No published npm package and no local bin at ${localBin}. Run \`npm run build\` in the repo first.`);
55
+ }
56
+ return {
57
+ displayName: pkg.name ?? `${parsed.owner}/${parsed.repo}`,
58
+ version: pkg.version,
59
+ command: 'node',
60
+ args: [localBin],
61
+ packageDir: cloneDir,
62
+ packageJson: pkg
63
+ };
64
+ }
65
+ //# sourceMappingURL=github-resolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"github-resolver.js","sourceRoot":"","sources":["../../src/resolvers/github-resolver.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Local resolver — the subject is an absolute path to a built MCP binary.
3
+ *
4
+ * The packageDir is the nearest ancestor containing package.json (so smoke
5
+ * test detection and version display work). We launch with `node <path>`.
6
+ */
7
+ import type { ResolvedTarget } from '../types.js';
8
+ export declare function resolveLocal(targetPath: string): ResolvedTarget;
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Local resolver — the subject is an absolute path to a built MCP binary.
3
+ *
4
+ * The packageDir is the nearest ancestor containing package.json (so smoke
5
+ * test detection and version display work). We launch with `node <path>`.
6
+ */
7
+ import { existsSync, readFileSync, statSync } from 'node:fs';
8
+ import { dirname, isAbsolute, resolve as pathResolve } from 'node:path';
9
+ function findPackageRoot(start) {
10
+ let dir = start;
11
+ for (let i = 0; i < 6; i++) {
12
+ const candidate = pathResolve(dir, 'package.json');
13
+ if (existsSync(candidate)) {
14
+ try {
15
+ const pkg = JSON.parse(readFileSync(candidate, 'utf8'));
16
+ return { dir, pkg };
17
+ }
18
+ catch {
19
+ // unparseable — keep going up
20
+ }
21
+ }
22
+ const parent = dirname(dir);
23
+ if (parent === dir)
24
+ break;
25
+ dir = parent;
26
+ }
27
+ return { dir: start };
28
+ }
29
+ export function resolveLocal(targetPath) {
30
+ const abs = isAbsolute(targetPath) ? targetPath : pathResolve(process.cwd(), targetPath);
31
+ if (!existsSync(abs)) {
32
+ throw new Error(`Local target does not exist: ${abs}`);
33
+ }
34
+ const st = statSync(abs);
35
+ if (!st.isFile()) {
36
+ throw new Error(`Local target must be a file (built JS): ${abs}`);
37
+ }
38
+ const { dir, pkg } = findPackageRoot(dirname(abs));
39
+ const displayName = pkg?.name ?? abs;
40
+ const version = pkg?.version;
41
+ return {
42
+ displayName,
43
+ version,
44
+ command: 'node',
45
+ args: [abs],
46
+ packageDir: dir,
47
+ packageJson: pkg
48
+ };
49
+ }
50
+ //# sourceMappingURL=local-resolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local-resolver.js","sourceRoot":"","sources":["../../src/resolvers/local-resolver.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC7D,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,WAAW,CAAC;AAGxE,SAAS,eAAe,CAAC,KAAa;IACpC,IAAI,GAAG,GAAG,KAAK,CAAC;IAChB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC3B,MAAM,SAAS,GAAG,WAAW,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC;QACnD,IAAI,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;YAC1B,IAAI,CAAC;gBACH,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC;gBACxD,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;YACtB,CAAC;YAAC,MAAM,CAAC;gBACP,8BAA8B;YAChC,CAAC;QACH,CAAC;QACD,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;QAC5B,IAAI,MAAM,KAAK,GAAG;YAAE,MAAM;QAC1B,GAAG,GAAG,MAAM,CAAC;IACf,CAAC;IACD,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC;AACxB,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,UAAkB;IAC7C,MAAM,GAAG,GAAG,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,WAAW,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,UAAU,CAAC,CAAC;IACzF,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACrB,MAAM,IAAI,KAAK,CAAC,gCAAgC,GAAG,EAAE,CAAC,CAAC;IACzD,CAAC;IACD,MAAM,EAAE,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC;IACzB,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CAAC,2CAA2C,GAAG,EAAE,CAAC,CAAC;IACpE,CAAC;IACD,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,eAAe,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;IACnD,MAAM,WAAW,GAAI,GAAG,EAAE,IAA2B,IAAI,GAAG,CAAC;IAC7D,MAAM,OAAO,GAAG,GAAG,EAAE,OAA6B,CAAC;IACnD,OAAO;QACL,WAAW;QACX,OAAO;QACP,OAAO,EAAE,MAAM;QACf,IAAI,EAAE,CAAC,GAAG,CAAC;QACX,UAAU,EAAE,GAAG;QACf,WAAW,EAAE,GAAG;KACjB,CAAC;AACJ,CAAC"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * npm resolver — given a package name (optionally @version), runs `npm pack`
3
+ * into a fresh temp dir, unpacks the tarball, locates the bin from
4
+ * package.json, and returns a ResolvedTarget ready for probing.
5
+ *
6
+ * Security:
7
+ * - works in /tmp/scorecard-work/probe-<random>/, never in the user's HOME.
8
+ * - uses --no-fund --no-audit to keep output clean and avoid any phone-home.
9
+ */
10
+ import type { ResolvedTarget } from '../types.js';
11
+ export declare function resolveNpmPackage(spec: string): Promise<ResolvedTarget>;