@fidacy/mcp 0.2.9 → 0.3.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/CHANGELOG.md +28 -0
- package/dist/core.js +4 -3
- package/dist/index.js +18 -10
- package/dist/lib.js +11 -9
- package/dist/telemetry.d.ts +7 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,33 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.3.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 0a1bf9e: Anonymous telemetry now counts tool usage: a `tool_use` event with which tool ran (assess, anchor, check, verify, explain) and nothing else. Same privacy invariant as every other event: an allowlisted enum on the wire, never the tool's content, payee, amount, hash or mandate. Opt out as always with FIDACY_DISABLE_TELEMETRY=1.
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- 0a1bf9e: Fix the free-trial decision counter being wiped by the background auto-provision write. The provision task captured config.json before its network call and wrote that stale snapshot back after, erasing every decision counted in between, so the 20-decision anonymous trial reset on every process restart. The provision write now merges the key onto a fresh read, and the counter write self-heals from the in-process floor. The wall now holds across restarts: 20 free decisions per install, as designed.
|
|
12
|
+
|
|
13
|
+
## 0.2.10
|
|
14
|
+
|
|
15
|
+
### Patch Changes
|
|
16
|
+
|
|
17
|
+
- 2e846a7: Funnel: move the strongest claim nudge before the activation wall, and make the
|
|
18
|
+
first-block nudge scary-but-true.
|
|
19
|
+
|
|
20
|
+
The proof-teaser nudge fired at decision 25, stranded behind the 20-decision
|
|
21
|
+
activation wall: once the firewall fails closed at 20, denied calls stop
|
|
22
|
+
advancing the counter, so 25 was never reached and the single strongest reason
|
|
23
|
+
to claim (the history you already built) never showed. It now fires at 15, five
|
|
24
|
+
decisions before the wall — carrot before stick, which is the highest-converting
|
|
25
|
+
moment the PLG research points to.
|
|
26
|
+
|
|
27
|
+
The first-deny nudge now cites the real $441,788 agent incident. Grounded fear,
|
|
28
|
+
never manufactured: for a company whose pitch is verify-don't-trust, a cited
|
|
29
|
+
fact converts and a fabricated panic would be self-refuting.
|
|
30
|
+
|
|
3
31
|
## 0.2.9
|
|
4
32
|
|
|
5
33
|
### Patch Changes
|
package/dist/core.js
CHANGED
|
@@ -461,7 +461,7 @@ function resolveMandateRules(cfg) {
|
|
|
461
461
|
}
|
|
462
462
|
|
|
463
463
|
// src/telemetry.ts
|
|
464
|
-
var CLIENT_VERSION = true ? "0.
|
|
464
|
+
var CLIENT_VERSION = true ? "0.3.0" : "dev";
|
|
465
465
|
function bandOf(amount) {
|
|
466
466
|
if (typeof amount !== "number" || !Number.isFinite(amount) || amount <= 0) return void 0;
|
|
467
467
|
if (amount < 10) return "lt10";
|
|
@@ -509,7 +509,7 @@ function resultOf(status, violatedRule) {
|
|
|
509
509
|
if (r.startsWith("non_positive_amount") || r.startsWith("invalid_")) return "deny_invalid";
|
|
510
510
|
return "deny_scope";
|
|
511
511
|
}
|
|
512
|
-
function record(type, result, band, capRatio) {
|
|
512
|
+
function record(type, result, band, capRatio, action) {
|
|
513
513
|
if (!telemetryEnabled()) return;
|
|
514
514
|
buffer.push({
|
|
515
515
|
type,
|
|
@@ -518,7 +518,8 @@ function record(type, result, band, capRatio) {
|
|
|
518
518
|
shell: currentShell,
|
|
519
519
|
...result ? { result } : {},
|
|
520
520
|
...band ? { band } : {},
|
|
521
|
-
...capRatio ? { cap_ratio: capRatio } : {}
|
|
521
|
+
...capRatio ? { cap_ratio: capRatio } : {},
|
|
522
|
+
...action ? { action } : {}
|
|
522
523
|
});
|
|
523
524
|
if (!flushTimer) {
|
|
524
525
|
flushTimer = setTimeout(() => {
|
package/dist/index.js
CHANGED
|
@@ -490,7 +490,7 @@ function resolveMandateRules(cfg) {
|
|
|
490
490
|
}
|
|
491
491
|
|
|
492
492
|
// src/telemetry.ts
|
|
493
|
-
var CLIENT_VERSION = true ? "0.
|
|
493
|
+
var CLIENT_VERSION = true ? "0.3.0" : "dev";
|
|
494
494
|
function bandOf(amount) {
|
|
495
495
|
if (typeof amount !== "number" || !Number.isFinite(amount) || amount <= 0) return void 0;
|
|
496
496
|
if (amount < 10) return "lt10";
|
|
@@ -538,7 +538,7 @@ function resultOf(status, violatedRule) {
|
|
|
538
538
|
if (r.startsWith("non_positive_amount") || r.startsWith("invalid_")) return "deny_invalid";
|
|
539
539
|
return "deny_scope";
|
|
540
540
|
}
|
|
541
|
-
function record(type, result, band, capRatio) {
|
|
541
|
+
function record(type, result, band, capRatio, action) {
|
|
542
542
|
if (!telemetryEnabled()) return;
|
|
543
543
|
buffer.push({
|
|
544
544
|
type,
|
|
@@ -547,7 +547,8 @@ function record(type, result, band, capRatio) {
|
|
|
547
547
|
shell: currentShell,
|
|
548
548
|
...result ? { result } : {},
|
|
549
549
|
...band ? { band } : {},
|
|
550
|
-
...capRatio ? { cap_ratio: capRatio } : {}
|
|
550
|
+
...capRatio ? { cap_ratio: capRatio } : {},
|
|
551
|
+
...action ? { action } : {}
|
|
551
552
|
});
|
|
552
553
|
if (!flushTimer) {
|
|
553
554
|
flushTimer = setTimeout(() => {
|
|
@@ -560,6 +561,7 @@ var recordInstall = () => record("install");
|
|
|
560
561
|
var recordAgentActive = () => record("agent_active");
|
|
561
562
|
var recordDecision = (status, violatedRule, amount, perTxMax) => record("decision", resultOf(status, violatedRule), bandOf(amount), capRatioOf(amount, perTxMax));
|
|
562
563
|
var recordUpgradeIntent = () => record("upgrade_intent");
|
|
564
|
+
var recordToolUse = (action) => record("tool_use", void 0, void 0, void 0, action);
|
|
563
565
|
async function flush() {
|
|
564
566
|
if (flushTimer) {
|
|
565
567
|
clearTimeout(flushTimer);
|
|
@@ -834,7 +836,7 @@ async function findArtifacts(sha2562, cfg) {
|
|
|
834
836
|
}
|
|
835
837
|
|
|
836
838
|
// src/provision.ts
|
|
837
|
-
var CLIENT_VERSION2 = true ? "0.
|
|
839
|
+
var CLIENT_VERSION2 = true ? "0.3.0" : "dev";
|
|
838
840
|
function provisionEnabled() {
|
|
839
841
|
const v = (process.env.FIDACY_DISABLE_PROVISION ?? "").trim().toLowerCase();
|
|
840
842
|
return !(v === "1" || v === "true" || v === "yes");
|
|
@@ -858,8 +860,9 @@ async function autoProvision() {
|
|
|
858
860
|
if (!res.ok) return "failed";
|
|
859
861
|
const data = await res.json();
|
|
860
862
|
if (typeof data.api_key !== "string" || !data.api_key) return "failed";
|
|
863
|
+
const fresh = readConfig() ?? cfg;
|
|
861
864
|
writeConfig({
|
|
862
|
-
...
|
|
865
|
+
...fresh,
|
|
863
866
|
api_key: data.api_key,
|
|
864
867
|
tier: data.tier === "paid" ? "paid" : "free"
|
|
865
868
|
});
|
|
@@ -906,7 +909,7 @@ function bumpDecisionCount() {
|
|
|
906
909
|
sessionDecisions += 1;
|
|
907
910
|
const cfg = readConfig();
|
|
908
911
|
if (!cfg) return sessionDecisions;
|
|
909
|
-
const n = (cfg.decisions_count ?? 0) + 1;
|
|
912
|
+
const n = Math.max((cfg.decisions_count ?? 0) + 1, sessionDecisions);
|
|
910
913
|
cfg.decisions_count = n;
|
|
911
914
|
try {
|
|
912
915
|
writeConfig(cfg);
|
|
@@ -927,13 +930,13 @@ function decisionNudge(status, violatedRule, upgradeToolName) {
|
|
|
927
930
|
return `That was a duplicate-invoice (BEC) catch, the #1 payment fraud. For your operator: ${claimPath}. On a hosted account every block like this is server-signed and anchored to Bitcoin: court-grade evidence.`;
|
|
928
931
|
}
|
|
929
932
|
if (status === "DENY" && nudgeOnce("first_deny")) {
|
|
930
|
-
return `Fidacy just blocked this for
|
|
933
|
+
return `Fidacy just blocked this payment before it moved. This is the failure it exists for: last week an AI agent sent $441,788 to a stranger who posted a fake story with a wallet address. Nothing was checking it. For your operator: ${claimPath}.`;
|
|
931
934
|
}
|
|
932
935
|
if (status === "ALLOW" && nudgeOnce("first_allow")) {
|
|
933
936
|
return `Fidacy authorized this and signed the decision. For your operator: ${claimPath}.`;
|
|
934
937
|
}
|
|
935
|
-
if (count ===
|
|
936
|
-
return `
|
|
938
|
+
if (count === 15 && nudgeOnce("proof_teaser")) {
|
|
939
|
+
return `Fidacy has now checked ${count} payments on this agent and stands between it and the wrong one, the prompt-injected payee, the duplicate, the over-limit charge. That protection pauses after 20 decisions without a free key. Keep the agent covered: ${claimPath}.`;
|
|
937
940
|
}
|
|
938
941
|
if (count === 10 && nudgeOnce("milestone_10")) {
|
|
939
942
|
return `That's 10 actions gated on this install. For your operator: ${claimPath}.`;
|
|
@@ -1264,7 +1267,7 @@ function renderAlertLine(alerts) {
|
|
|
1264
1267
|
var state = ensureState();
|
|
1265
1268
|
var core = makeCore();
|
|
1266
1269
|
var subject = process.env.FIDACY_SUBJECT ?? "agent:demo";
|
|
1267
|
-
var SERVER_VERSION = true ? "0.
|
|
1270
|
+
var SERVER_VERSION = true ? "0.3.0" : "dev";
|
|
1268
1271
|
var bootClaim = claimUrl();
|
|
1269
1272
|
var server = new McpServer(
|
|
1270
1273
|
{ name: "fidacy", version: SERVER_VERSION },
|
|
@@ -1331,6 +1334,7 @@ server.registerTool(
|
|
|
1331
1334
|
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false }
|
|
1332
1335
|
},
|
|
1333
1336
|
async () => {
|
|
1337
|
+
recordToolUse("verify");
|
|
1334
1338
|
const m = await core.getMandate(subject);
|
|
1335
1339
|
const payload = { mandate: m, fidacyPublicKey: core.publicKey() };
|
|
1336
1340
|
const claim = process.env.FIDACY_ENGINE_API_KEY ? null : claimUrl();
|
|
@@ -1409,6 +1413,7 @@ server.registerTool(
|
|
|
1409
1413
|
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false }
|
|
1410
1414
|
},
|
|
1411
1415
|
async ({ decisionId }) => {
|
|
1416
|
+
recordToolUse("explain");
|
|
1412
1417
|
const records = await core.history(5e3);
|
|
1413
1418
|
const record2 = records.find((r) => r.decisionId === decisionId);
|
|
1414
1419
|
if (!record2) {
|
|
@@ -1469,6 +1474,7 @@ server.registerTool(
|
|
|
1469
1474
|
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true }
|
|
1470
1475
|
},
|
|
1471
1476
|
async ({ kind, mandate, mandateType, idempotencyKey, spendingMandate, a2a }) => {
|
|
1477
|
+
recordToolUse("assess");
|
|
1472
1478
|
const engineUrl = process.env.FIDACY_ENGINE_URL ?? "https://api.fidacy.com";
|
|
1473
1479
|
const apiKey = (process.env.FIDACY_ENGINE_API_KEY ?? "").trim();
|
|
1474
1480
|
if (!apiKey) {
|
|
@@ -1519,6 +1525,7 @@ server.registerTool(
|
|
|
1519
1525
|
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true }
|
|
1520
1526
|
},
|
|
1521
1527
|
async ({ path, sha256: sha2562, kind, label, subject: subj }) => {
|
|
1528
|
+
recordToolUse("anchor");
|
|
1522
1529
|
const engineUrl = process.env.FIDACY_ENGINE_URL ?? "https://api.fidacy.com";
|
|
1523
1530
|
const apiKey = (process.env.FIDACY_ENGINE_API_KEY ?? "").trim();
|
|
1524
1531
|
if (!apiKey) {
|
|
@@ -1573,6 +1580,7 @@ server.registerTool(
|
|
|
1573
1580
|
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true }
|
|
1574
1581
|
},
|
|
1575
1582
|
async ({ path, sha256: sha2562 }) => {
|
|
1583
|
+
recordToolUse("check");
|
|
1576
1584
|
const engineUrl = process.env.FIDACY_ENGINE_URL ?? "https://api.fidacy.com";
|
|
1577
1585
|
const apiKey = (process.env.FIDACY_ENGINE_API_KEY ?? "").trim();
|
|
1578
1586
|
if (!apiKey) {
|
package/dist/lib.js
CHANGED
|
@@ -613,7 +613,7 @@ function resolveMandateRules(cfg) {
|
|
|
613
613
|
}
|
|
614
614
|
|
|
615
615
|
// src/telemetry.ts
|
|
616
|
-
var CLIENT_VERSION = true ? "0.
|
|
616
|
+
var CLIENT_VERSION = true ? "0.3.0" : "dev";
|
|
617
617
|
function bandOf(amount) {
|
|
618
618
|
if (typeof amount !== "number" || !Number.isFinite(amount) || amount <= 0) return void 0;
|
|
619
619
|
if (amount < 10) return "lt10";
|
|
@@ -664,7 +664,7 @@ function resultOf(status, violatedRule) {
|
|
|
664
664
|
if (r.startsWith("non_positive_amount") || r.startsWith("invalid_")) return "deny_invalid";
|
|
665
665
|
return "deny_scope";
|
|
666
666
|
}
|
|
667
|
-
function record(type, result, band, capRatio) {
|
|
667
|
+
function record(type, result, band, capRatio, action) {
|
|
668
668
|
if (!telemetryEnabled()) return;
|
|
669
669
|
buffer.push({
|
|
670
670
|
type,
|
|
@@ -673,7 +673,8 @@ function record(type, result, band, capRatio) {
|
|
|
673
673
|
shell: currentShell,
|
|
674
674
|
...result ? { result } : {},
|
|
675
675
|
...band ? { band } : {},
|
|
676
|
-
...capRatio ? { cap_ratio: capRatio } : {}
|
|
676
|
+
...capRatio ? { cap_ratio: capRatio } : {},
|
|
677
|
+
...action ? { action } : {}
|
|
677
678
|
});
|
|
678
679
|
if (!flushTimer) {
|
|
679
680
|
flushTimer = setTimeout(() => {
|
|
@@ -791,7 +792,7 @@ function requestUpgrade() {
|
|
|
791
792
|
}
|
|
792
793
|
|
|
793
794
|
// src/provision.ts
|
|
794
|
-
var CLIENT_VERSION2 = true ? "0.
|
|
795
|
+
var CLIENT_VERSION2 = true ? "0.3.0" : "dev";
|
|
795
796
|
function provisionEnabled() {
|
|
796
797
|
const v = (process.env.FIDACY_DISABLE_PROVISION ?? "").trim().toLowerCase();
|
|
797
798
|
return !(v === "1" || v === "true" || v === "yes");
|
|
@@ -815,8 +816,9 @@ async function autoProvision() {
|
|
|
815
816
|
if (!res.ok) return "failed";
|
|
816
817
|
const data = await res.json();
|
|
817
818
|
if (typeof data.api_key !== "string" || !data.api_key) return "failed";
|
|
819
|
+
const fresh = readConfig() ?? cfg;
|
|
818
820
|
writeConfig({
|
|
819
|
-
...
|
|
821
|
+
...fresh,
|
|
820
822
|
api_key: data.api_key,
|
|
821
823
|
tier: data.tier === "paid" ? "paid" : "free"
|
|
822
824
|
});
|
|
@@ -851,7 +853,7 @@ function bumpDecisionCount() {
|
|
|
851
853
|
sessionDecisions += 1;
|
|
852
854
|
const cfg = readConfig();
|
|
853
855
|
if (!cfg) return sessionDecisions;
|
|
854
|
-
const n = (cfg.decisions_count ?? 0) + 1;
|
|
856
|
+
const n = Math.max((cfg.decisions_count ?? 0) + 1, sessionDecisions);
|
|
855
857
|
cfg.decisions_count = n;
|
|
856
858
|
try {
|
|
857
859
|
writeConfig(cfg);
|
|
@@ -872,13 +874,13 @@ function decisionNudge(status, violatedRule, upgradeToolName) {
|
|
|
872
874
|
return `That was a duplicate-invoice (BEC) catch, the #1 payment fraud. For your operator: ${claimPath}. On a hosted account every block like this is server-signed and anchored to Bitcoin: court-grade evidence.`;
|
|
873
875
|
}
|
|
874
876
|
if (status === "DENY" && nudgeOnce("first_deny")) {
|
|
875
|
-
return `Fidacy just blocked this for
|
|
877
|
+
return `Fidacy just blocked this payment before it moved. This is the failure it exists for: last week an AI agent sent $441,788 to a stranger who posted a fake story with a wallet address. Nothing was checking it. For your operator: ${claimPath}.`;
|
|
876
878
|
}
|
|
877
879
|
if (status === "ALLOW" && nudgeOnce("first_allow")) {
|
|
878
880
|
return `Fidacy authorized this and signed the decision. For your operator: ${claimPath}.`;
|
|
879
881
|
}
|
|
880
|
-
if (count ===
|
|
881
|
-
return `
|
|
882
|
+
if (count === 15 && nudgeOnce("proof_teaser")) {
|
|
883
|
+
return `Fidacy has now checked ${count} payments on this agent and stands between it and the wrong one, the prompt-injected payee, the duplicate, the over-limit charge. That protection pauses after 20 decisions without a free key. Keep the agent covered: ${claimPath}.`;
|
|
882
884
|
}
|
|
883
885
|
if (count === 10 && nudgeOnce("milestone_10")) {
|
|
884
886
|
return `That's 10 actions gated on this install. For your operator: ${claimPath}.`;
|
package/dist/telemetry.d.ts
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
export type TelemetryEventType = "install" | "agent_active" | "decision" | "upgrade_intent";
|
|
1
|
+
export type TelemetryEventType = "install" | "agent_active" | "decision" | "upgrade_intent" | "tool_use";
|
|
2
|
+
/** Which tool a tool_use event counts (0059). An ENUM mirrored by the ingest
|
|
3
|
+
* allowlist: which tool ran, never what it ran on. */
|
|
4
|
+
export type ToolAction = "assess" | "anchor" | "check" | "verify" | "explain";
|
|
2
5
|
export type DecisionResult = "allow" | "deny_cap" | "deny_payee" | "deny_scope" | "deny_lookalike" | "deny_duplicate" | "deny_window" | "deny_invalid";
|
|
3
6
|
/** Which shell this engine is embedded in. An ENUM mirrored by the ingest allowlist
|
|
4
7
|
* and the DB CHECK — never a free-form string, so it can't become a PII channel. */
|
|
@@ -18,10 +21,12 @@ export declare function telemetryEnabled(): boolean;
|
|
|
18
21
|
/** Map a firewall violatedRule to the coarse, PII-free decision result enum. */
|
|
19
22
|
export declare function resultOf(status: "ALLOW" | "DENY", violatedRule?: string): DecisionResult;
|
|
20
23
|
/** Buffer an event (sync, never blocks, never throws). Auto-flushes shortly after. */
|
|
21
|
-
export declare function record(type: TelemetryEventType, result?: DecisionResult, band?: AmountBand, capRatio?: CapRatioBand): void;
|
|
24
|
+
export declare function record(type: TelemetryEventType, result?: DecisionResult, band?: AmountBand, capRatio?: CapRatioBand, action?: ToolAction): void;
|
|
22
25
|
export declare const recordInstall: () => void;
|
|
23
26
|
export declare const recordAgentActive: () => void;
|
|
24
27
|
export declare const recordDecision: (status: "ALLOW" | "DENY", violatedRule?: string, amount?: number, perTxMax?: number) => void;
|
|
25
28
|
export declare const recordUpgradeIntent: () => void;
|
|
29
|
+
/** Count a tool invocation (which tool, never its content) — the agent-activity profile. */
|
|
30
|
+
export declare const recordToolUse: (action: ToolAction) => void;
|
|
26
31
|
/** Send the buffered batch fire-and-forget. Swallows all errors. Best-effort. */
|
|
27
32
|
export declare function flush(): Promise<void>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fidacy/mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Fidacy action firewall for AI agents. Mandate-gated payment authorization as an MCP server.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "Fidacy (ZeepCode Group Technology LLC) <hello@fidacy.com> (https://fidacy.com)",
|