revclamp-mcp 1.20.7 → 1.20.9

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 CHANGED
@@ -41,7 +41,7 @@ Add `revclamp-mcp` to your `claude_desktop_config.json` or `.cursor/mcp.json`. B
41
41
  "mcpServers": {
42
42
  "revclamp": {
43
43
  "command": "npx",
44
- "args": ["-y", "github:revclamp/revclamp-mcp"]
44
+ "args": ["-y", "github:lhphong09t2/revclamp-mcp"]
45
45
  }
46
46
  }
47
47
  }
@@ -59,7 +59,7 @@ curl -sS -X POST https://api.revclamp.com/api/mcp \
59
59
 
60
60
  ```bash
61
61
  # Run a <60s local CLI smoke check (verifies all 9 tool schemas & executes a local_engine.mjs sample audit with zero API key)
62
- npx -y github:revclamp/revclamp-mcp#v1.20.7 --self-test
62
+ npx -y github:lhphong09t2/revclamp-mcp#v1.20.9 --self-test
63
63
 
64
64
  # List all 9 MCP tools and JSON schemas (runs locally in-process)
65
65
  node index.mjs --list-tools
package/index.mjs CHANGED
@@ -20,6 +20,7 @@ import { fileURLToPath } from "node:url";
20
20
  import {
21
21
  LOCAL_MCP_TOOLS,
22
22
  MCP_PROTOCOL_VERSION,
23
+ normalizeMcpToolArgs,
23
24
  executeLocalMcpTool,
24
25
  executeLocalMcpJsonRpc,
25
26
  } from "./local_engine.mjs";
@@ -27,11 +28,12 @@ import {
27
28
  export {
28
29
  LOCAL_MCP_TOOLS,
29
30
  MCP_PROTOCOL_VERSION,
31
+ normalizeMcpToolArgs,
30
32
  executeLocalMcpTool,
31
33
  executeLocalMcpJsonRpc,
32
34
  };
33
35
 
34
- export const PACKAGE_VERSION = "1.20.7";
36
+ export const PACKAGE_VERSION = "1.20.9";
35
37
  export const DEFAULT_MCP_ENDPOINT = "https://api.revclamp.com/api/mcp";
36
38
  export const ALLOWED_MCP_ORIGINS = Object.freeze(
37
39
  new Set(["https://api.revclamp.com", "https://revclamp.com"])
@@ -41,7 +43,7 @@ export const MAX_STDIO_LINE_BYTES = MAX_PAYLOAD_BYTES;
41
43
  export const REQUEST_TIMEOUT_MS = 10_000;
42
44
 
43
45
  const LIVE_SECRET_GUARD_RE =
44
- /(?:[sr]k_live_[A-Za-z0-9_-]{4,}|whsec_live_[A-Za-z0-9_-]{4,}|whsec_(?!test_|synth_|sandbox_)[A-Za-z0-9_-]{10,}|shpss_live_[A-Za-z0-9_-]{4,}|shpss_[0-9a-fA-F]{16,}|shp(?:at|ua|ca|pa)_[A-Za-z0-9_-]{8,}|lsq_[A-Za-z0-9_-]{4,}|r[gc]_live_[A-Za-z0-9_-]{4,}|AKIA[0-9A-Z]{12,}|-----BEGIN [A-Z ]*PRIVATE KEY-----)/i;
46
+ /(?:[sr]k_live_[A-Za-z0-9_-]{4,}|whsec_live_[A-Za-z0-9_-]{4,}|whsec_(?!test_|synth_|sandbox_|demo_|sample_|mock_|example_|fake_|dummy_)[A-Za-z0-9_-]{10,}|shpss_live_[A-Za-z0-9_-]{4,}|shpss_[0-9a-fA-F]{16,}|shp(?:at|ua|ca|pa)_[A-Za-z0-9_-]{8,}|lsq_[A-Za-z0-9_-]{4,}|r[gc]_live_[A-Za-z0-9_-]{4,}|AKIA[0-9A-Z]{12,}|-----BEGIN [A-Z ]*PRIVATE KEY-----)/i;
45
47
 
46
48
  export function toSafeRpcId(rawId) {
47
49
  if (typeof rawId === "number" && Number.isFinite(rawId)) {
@@ -314,6 +316,37 @@ export async function forwardMcpJsonRpc(
314
316
  },
315
317
  };
316
318
  }
319
+ if (methodStr === "tools/call" && rpcRequest.params.arguments !== undefined) {
320
+ const normRes = normalizeMcpToolArgs(
321
+ String(rpcRequest.params?.name || "").trim(),
322
+ rpcRequest.params.arguments
323
+ );
324
+ if (!normRes.ok) {
325
+ if (isNotification) {
326
+ return null;
327
+ }
328
+ return {
329
+ jsonrpc: "2.0",
330
+ id: safeId,
331
+ error: {
332
+ code: -32602,
333
+ message: normRes.message,
334
+ data: {
335
+ error: normRes.error,
336
+ reason: normRes.error,
337
+ ...(normRes.canonicalKey ? { canonicalKey: normRes.canonicalKey } : {}),
338
+ },
339
+ },
340
+ };
341
+ }
342
+ rpcRequest = {
343
+ ...rpcRequest,
344
+ params: {
345
+ ...rpcRequest.params,
346
+ arguments: normRes.args,
347
+ },
348
+ };
349
+ }
317
350
  }
318
351
 
319
352
  try {
@@ -841,18 +874,191 @@ export async function runCli(argv = process.argv.slice(2), options = {}) {
841
874
  effectiveOptions.apiUrl ||
842
875
  DEFAULT_MCP_ENDPOINT
843
876
  );
844
- const smokeAudit = executeLocalMcpTool("revclamp_audit_revenue_leakage", { demo: true });
845
- const toolsCount = Array.isArray(LOCAL_MCP_TOOLS) ? LOCAL_MCP_TOOLS.length : 0;
877
+ const expectedToolNames = [
878
+ "revclamp_audit_revenue_leakage",
879
+ "revclamp_evaluate_ghost_usage",
880
+ "revclamp_stage_stripe_dispute_ce3",
881
+ "revclamp_validate_eu_vat_vies",
882
+ "revclamp_reconcile_b2b_net_terms",
883
+ "revclamp_verify_webhook_signature",
884
+ "revclamp_calculate_roi_and_plan_fit",
885
+ "revclamp_simulate_webhook_replay",
886
+ "revclamp_lint_dispute_evidence",
887
+ ];
888
+ const selfTestFixtures = {
889
+ revclamp_audit_revenue_leakage: {
890
+ args: { demo: true },
891
+ verify: (r) => Boolean(r && r.ok === true && r.ghostEventsDetected > 0),
892
+ },
893
+ revclamp_evaluate_ghost_usage: {
894
+ args: {
895
+ customerId: "cus_selftest_01",
896
+ subscriptions: {
897
+ has_more: false,
898
+ data: [
899
+ {
900
+ customer: "cus_selftest_01",
901
+ status: "canceled",
902
+ current_period_end: 1750000000,
903
+ },
904
+ ],
905
+ },
906
+ usageEvent: {
907
+ customer_id: "cus_selftest_01",
908
+ occurred_at_sec: 1760000000,
909
+ },
910
+ },
911
+ verify: (r) =>
912
+ Boolean(
913
+ r &&
914
+ r.ok === true &&
915
+ r.isGhostUsage === true &&
916
+ r.decision === "DISPATCH_SIGNED_REVOKE_WEBHOOK"
917
+ ),
918
+ },
919
+ revclamp_stage_stripe_dispute_ce3: {
920
+ args: {
921
+ disputeId: "du_selftest_01",
922
+ customerId: "cus_selftest_01",
923
+ demo: true,
924
+ },
925
+ verify: (r) =>
926
+ Boolean(
927
+ r &&
928
+ r.ok === true &&
929
+ r.submit === false &&
930
+ typeof r.evidence?.access_activity_log === "string" &&
931
+ r.utf16CodeUnits <= 18000
932
+ ),
933
+ },
934
+ revclamp_validate_eu_vat_vies: {
935
+ args: {
936
+ sellerCountry: "DE",
937
+ buyerVatId: "XI123456789",
938
+ viesMode: "FORMAT_ONLY",
939
+ },
940
+ verify: (r) =>
941
+ Boolean(
942
+ r &&
943
+ r.ok === true &&
944
+ r.formatValid === true &&
945
+ r.crossBorderSupply === true &&
946
+ r.memberState === "XI"
947
+ ),
948
+ },
949
+ revclamp_reconcile_b2b_net_terms: {
950
+ args: {
951
+ orderId: "ord_selftest_01",
952
+ totalOrderCents: 100000,
953
+ paidAmountCents: 30000,
954
+ requiredDepositPercent: 30,
955
+ paymentTermsDays: 30,
956
+ daysElapsedSinceInvoice: 5,
957
+ },
958
+ verify: (r) =>
959
+ Boolean(
960
+ r &&
961
+ r.ok === true &&
962
+ r.fulfillmentAllowed === true &&
963
+ r.doubleEntryBalanced === true &&
964
+ r.remainingBalanceCents === 70000
965
+ ),
966
+ },
967
+ revclamp_verify_webhook_signature: {
968
+ args: {
969
+ provider: "stripe",
970
+ secret: "whsec_test_selftest_secret_2026",
971
+ rawPayload: '{"id":"evt_selftest_01","type":"customer.subscription.deleted"}',
972
+ demo: true,
973
+ },
974
+ verify: (r) =>
975
+ Boolean(
976
+ r &&
977
+ r.ok === true &&
978
+ typeof r.verification?.generatedHeader === "string" &&
979
+ r.verification.generatedHeader.includes("v1=")
980
+ ),
981
+ },
982
+ revclamp_calculate_roi_and_plan_fit: {
983
+ args: {
984
+ monthlyWonDisputeUsd: 10000,
985
+ monthlyGhostBleedUsd: 600,
986
+ contingencyTakeRatePercent: 25,
987
+ monthlyUsageEvents: 250000,
988
+ },
989
+ verify: (r) =>
990
+ Boolean(
991
+ r &&
992
+ r.ok === true &&
993
+ r.zeroTakeRateGuaranteed === true &&
994
+ r.annualNetMarginSavedCents > 0 &&
995
+ r.recommendedTier === "growth_59"
996
+ ),
997
+ },
998
+ revclamp_simulate_webhook_replay: {
999
+ args: {
1000
+ scenarioPreset: "out_of_order_stale_update_after_cancel",
1001
+ demo: true,
1002
+ },
1003
+ verify: (r) =>
1004
+ Boolean(
1005
+ r &&
1006
+ r.ok === true &&
1007
+ r.preventedStateCorruption === true &&
1008
+ r.finalStatus === "canceled"
1009
+ ),
1010
+ },
1011
+ revclamp_lint_dispute_evidence: {
1012
+ args: {
1013
+ preset: "valid_ce3_non_destructive",
1014
+ demo: true,
1015
+ },
1016
+ verify: (r) =>
1017
+ Boolean(
1018
+ r &&
1019
+ r.ok === true &&
1020
+ r.within18kCeiling === true &&
1021
+ r.withinCeiling === true &&
1022
+ r.overallVerdict === "PASS_CE3_READY"
1023
+ ),
1024
+ },
1025
+ };
1026
+
1027
+ const toolsList = Array.isArray(LOCAL_MCP_TOOLS) ? LOCAL_MCP_TOOLS : [];
1028
+ const toolsCount = toolsList.length;
1029
+ const exactCatalogMatch =
1030
+ toolsCount === expectedToolNames.length &&
1031
+ expectedToolNames.every((tName, idx) => toolsList[idx]?.name === tName);
1032
+
1033
+ const toolResults = [];
1034
+ let passedCount = 0;
1035
+ for (const toolDef of toolsList) {
1036
+ const tName = String(toolDef?.name || "");
1037
+ const spec = selfTestFixtures[tName];
1038
+ let itemOk = false;
1039
+ if (spec) {
1040
+ try {
1041
+ const out = executeLocalMcpTool(tName, spec.args);
1042
+ itemOk = Boolean(spec.verify(out));
1043
+ } catch {
1044
+ itemOk = false;
1045
+ }
1046
+ }
1047
+ if (itemOk) passedCount += 1;
1048
+ toolResults.push({ tool: tName, ok: itemOk });
1049
+ }
1050
+
846
1051
  const localEngineVerified =
847
- Boolean(smokeAudit && smokeAudit.ok === true && smokeAudit.ghostEventsDetected > 0) &&
848
- toolsCount === 9;
1052
+ Boolean(exactCatalogMatch) && toolsCount === 9 && passedCount === 9;
849
1053
  console.log(
850
1054
  JSON.stringify({
851
1055
  ok: localEngineVerified,
852
1056
  version: PACKAGE_VERSION,
853
1057
  toolsCount,
1058
+ passedCount,
854
1059
  localEngineVerified,
855
1060
  endpoint: validated,
1061
+ toolResults,
856
1062
  })
857
1063
  );
858
1064
  return localEngineVerified ? 0 : 1;
@@ -1040,6 +1246,9 @@ export async function runCli(argv = process.argv.slice(2), options = {}) {
1040
1246
  "valid_ce3_non_destructive",
1041
1247
  "utf16_overflow_19k",
1042
1248
  "missing_device_and_overwrite_risk",
1249
+ "ce3_24k_truncation_trap",
1250
+ "ce3_clean_compacted_14k",
1251
+ "ce3_missing_device_binding_19k",
1043
1252
  ]);
1044
1253
  const preset = positional[0] || "valid_ce3_non_destructive";
1045
1254
  if (!allowedPresets.has(preset)) {