mcp-proof 0.3.19 → 0.3.20

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/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.3.20
4
+
5
+ - **Fix: `--inspect-call` in the default (human-readable) mode crashed** with
6
+ `Cannot read properties of undefined (reading 'toFixed')` (exit 65) for every
7
+ input; only `--json` worked. It now prints a verdict and reasons and keeps the
8
+ exit codes (0 allow, 1 warn, 2 block).
9
+ - `--inspect-call` now accepts a plain `{"name": ..., "arguments": ...}` payload as well as
10
+ `{"tool": ...}` and JSON-RPC `{"params": {"name": ...}}`; previously `name` at the top
11
+ level gave an empty tool name.
12
+ - Two regression tests added (22 public checks). Decisions and scores for `tools/list`
13
+ scans are unchanged. `vetokernel-client.js` still does not ship (see 0.3.19).
14
+
3
15
  ## 0.3.19
4
16
 
5
17
  Readiness hardening — closes the audit findings, keeps all decisions and
package/bin/mcp-proof.js CHANGED
@@ -776,7 +776,18 @@ function renderMulti(output) {
776
776
  process.stdout.write(` ${c.bold}Overall${c.reset} ${output.decision.toUpperCase()}\n\n`);
777
777
  }
778
778
 
779
+ function renderInspectCall(r) {
780
+ const c = COLORS;
781
+ const color = r.decision === 'allow' ? c.green : r.decision === 'warn' ? c.yellow : c.red;
782
+ const lines = ['', ` ${c.bold}mcp-proof${c.reset} ${c.dim}— inspect-call${r.tool ? ` ${r.tool}` : ''}, ${r.durationMs || 0}ms${c.reset}`, '',
783
+ ` Verdict ${color}${c.bold}${String(r.decision).toUpperCase()}${c.reset}`, '', ` ${c.bold}Why${c.reset}`];
784
+ for (const reason of r.reasons) lines.push(` - ${reason}`);
785
+ if (!r.reasons.length) lines.push(' - no runtime-payload patterns detected');
786
+ process.stdout.write(lines.join('\n') + '\n\n');
787
+ }
788
+
779
789
  function renderHumanReadable(r, toolCount, label = '') {
790
+ if (r.mode === 'inspect-call') return renderInspectCall(r);
780
791
  const c = COLORS;
781
792
  const verdict = r.decision.toUpperCase();
782
793
  const verdictColor = r.decision === 'allow' ? c.green : r.decision === 'warn' ? c.yellow : c.red;
package/engine.js CHANGED
@@ -756,7 +756,7 @@ function scanCall(toolName, args) {
756
756
 
757
757
  function evaluateCall(req) {
758
758
  const start = Date.now();
759
- const toolName = req.tool || (req.params && req.params.name) || '';
759
+ const toolName = req.tool || req.name || (req.params && req.params.name) || '';
760
760
  const args = req.arguments || (req.params && req.params.arguments) || {};
761
761
  const scan = scanCall(toolName, args);
762
762
  const score = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mcp-proof",
3
- "version": "0.3.19",
3
+ "version": "0.3.20",
4
4
  "description": "Auditable, privacy-preserving MCP (Model Context Protocol) server verifier with local Trust Cards and SARIF output — test servers before connecting them to an AI system.",
5
5
  "main": "engine.js",
6
6
  "bin": {
@@ -22,7 +22,7 @@
22
22
  "access": "public"
23
23
  },
24
24
  "scripts": {
25
- "test": "node test.js",
25
+ "test": "node test.js && node test-canonical.js",
26
26
  "test:private": "node test-private.js",
27
27
  "test:all": "node test.js && node test-private.js",
28
28
  "campaign:validate": "node campaign/campaign-tools.js validate",
package/test.js CHANGED
@@ -295,5 +295,14 @@ check(
295
295
  `decision=${benignSkillResult.decision} ${JSON.stringify(benignSkillResult.toolPoisoning)}`,
296
296
  );
297
297
 
298
+ // --inspect-call in human-readable mode must render (it used to crash on a missing TrustScore) and keep the block/allow exit codes.
299
+ for (const [label, call, wantStatus, wantText] of [
300
+ ['blocked call', { name: 'read_file', arguments: { path: '~/.ssh/id_rsa' } }, 2, 'BLOCK'],
301
+ ['clean call', { name: 'get_weather', arguments: { city: 'Paris' } }, 0, 'ALLOW'],
302
+ ]) {
303
+ const r = require('child_process').spawnSync(process.execPath, [require('path').join(__dirname, 'bin', 'mcp-proof.js'), '--inspect-call'], { input: JSON.stringify(call), encoding: 'utf8' });
304
+ check(r.status === wantStatus && r.stdout.includes(wantText) && r.stdout.includes(call.name), `--inspect-call human output: ${label}`, `status=${r.status} stderr=${(r.stderr || '').slice(0, 80)}`);
305
+ }
306
+
298
307
  console.log(`\n${pass}/${pass + fail} public tests passed`);
299
308
  process.exit(fail === 0 ? 0 : 1);