@fidacy/mcp 0.2.10 → 0.3.1
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 +16 -0
- package/dist/core.js +13 -3
- package/dist/index.js +24 -7
- package/dist/lib.d.ts +1 -1
- package/dist/lib.js +18 -6
- package/dist/telemetry.d.ts +7 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.3.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 01f0734: Telemetry now flushes on process exit. The 2s flush timer is unref'd so a short-lived process could exit with a full buffer and silently lose it, which is exactly how plugin-channel installs went uncounted. A beforeExit hook sends the last batch, best-effort as always.
|
|
8
|
+
|
|
9
|
+
## 0.3.0
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- 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.
|
|
14
|
+
|
|
15
|
+
### Patch Changes
|
|
16
|
+
|
|
17
|
+
- 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.
|
|
18
|
+
|
|
3
19
|
## 0.2.10
|
|
4
20
|
|
|
5
21
|
### 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.1" : "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";
|
|
@@ -497,6 +497,14 @@ function anonId() {
|
|
|
497
497
|
}
|
|
498
498
|
var buffer = [];
|
|
499
499
|
var flushTimer = null;
|
|
500
|
+
var exitHookArmed = false;
|
|
501
|
+
function armExitFlush() {
|
|
502
|
+
if (exitHookArmed || typeof process === "undefined" || typeof process.once !== "function") return;
|
|
503
|
+
exitHookArmed = true;
|
|
504
|
+
process.once("beforeExit", () => {
|
|
505
|
+
if (buffer.length > 0) void flush();
|
|
506
|
+
});
|
|
507
|
+
}
|
|
500
508
|
function resultOf(status, violatedRule) {
|
|
501
509
|
if (status === "ALLOW") return "allow";
|
|
502
510
|
const r = violatedRule ?? "";
|
|
@@ -509,8 +517,9 @@ function resultOf(status, violatedRule) {
|
|
|
509
517
|
if (r.startsWith("non_positive_amount") || r.startsWith("invalid_")) return "deny_invalid";
|
|
510
518
|
return "deny_scope";
|
|
511
519
|
}
|
|
512
|
-
function record(type, result, band, capRatio) {
|
|
520
|
+
function record(type, result, band, capRatio, action) {
|
|
513
521
|
if (!telemetryEnabled()) return;
|
|
522
|
+
armExitFlush();
|
|
514
523
|
buffer.push({
|
|
515
524
|
type,
|
|
516
525
|
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -518,7 +527,8 @@ function record(type, result, band, capRatio) {
|
|
|
518
527
|
shell: currentShell,
|
|
519
528
|
...result ? { result } : {},
|
|
520
529
|
...band ? { band } : {},
|
|
521
|
-
...capRatio ? { cap_ratio: capRatio } : {}
|
|
530
|
+
...capRatio ? { cap_ratio: capRatio } : {},
|
|
531
|
+
...action ? { action } : {}
|
|
522
532
|
});
|
|
523
533
|
if (!flushTimer) {
|
|
524
534
|
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.1" : "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";
|
|
@@ -526,6 +526,14 @@ function anonId() {
|
|
|
526
526
|
}
|
|
527
527
|
var buffer = [];
|
|
528
528
|
var flushTimer = null;
|
|
529
|
+
var exitHookArmed = false;
|
|
530
|
+
function armExitFlush() {
|
|
531
|
+
if (exitHookArmed || typeof process === "undefined" || typeof process.once !== "function") return;
|
|
532
|
+
exitHookArmed = true;
|
|
533
|
+
process.once("beforeExit", () => {
|
|
534
|
+
if (buffer.length > 0) void flush();
|
|
535
|
+
});
|
|
536
|
+
}
|
|
529
537
|
function resultOf(status, violatedRule) {
|
|
530
538
|
if (status === "ALLOW") return "allow";
|
|
531
539
|
const r = violatedRule ?? "";
|
|
@@ -538,8 +546,9 @@ function resultOf(status, violatedRule) {
|
|
|
538
546
|
if (r.startsWith("non_positive_amount") || r.startsWith("invalid_")) return "deny_invalid";
|
|
539
547
|
return "deny_scope";
|
|
540
548
|
}
|
|
541
|
-
function record(type, result, band, capRatio) {
|
|
549
|
+
function record(type, result, band, capRatio, action) {
|
|
542
550
|
if (!telemetryEnabled()) return;
|
|
551
|
+
armExitFlush();
|
|
543
552
|
buffer.push({
|
|
544
553
|
type,
|
|
545
554
|
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -547,7 +556,8 @@ function record(type, result, band, capRatio) {
|
|
|
547
556
|
shell: currentShell,
|
|
548
557
|
...result ? { result } : {},
|
|
549
558
|
...band ? { band } : {},
|
|
550
|
-
...capRatio ? { cap_ratio: capRatio } : {}
|
|
559
|
+
...capRatio ? { cap_ratio: capRatio } : {},
|
|
560
|
+
...action ? { action } : {}
|
|
551
561
|
});
|
|
552
562
|
if (!flushTimer) {
|
|
553
563
|
flushTimer = setTimeout(() => {
|
|
@@ -560,6 +570,7 @@ var recordInstall = () => record("install");
|
|
|
560
570
|
var recordAgentActive = () => record("agent_active");
|
|
561
571
|
var recordDecision = (status, violatedRule, amount, perTxMax) => record("decision", resultOf(status, violatedRule), bandOf(amount), capRatioOf(amount, perTxMax));
|
|
562
572
|
var recordUpgradeIntent = () => record("upgrade_intent");
|
|
573
|
+
var recordToolUse = (action) => record("tool_use", void 0, void 0, void 0, action);
|
|
563
574
|
async function flush() {
|
|
564
575
|
if (flushTimer) {
|
|
565
576
|
clearTimeout(flushTimer);
|
|
@@ -834,7 +845,7 @@ async function findArtifacts(sha2562, cfg) {
|
|
|
834
845
|
}
|
|
835
846
|
|
|
836
847
|
// src/provision.ts
|
|
837
|
-
var CLIENT_VERSION2 = true ? "0.
|
|
848
|
+
var CLIENT_VERSION2 = true ? "0.3.1" : "dev";
|
|
838
849
|
function provisionEnabled() {
|
|
839
850
|
const v = (process.env.FIDACY_DISABLE_PROVISION ?? "").trim().toLowerCase();
|
|
840
851
|
return !(v === "1" || v === "true" || v === "yes");
|
|
@@ -858,8 +869,9 @@ async function autoProvision() {
|
|
|
858
869
|
if (!res.ok) return "failed";
|
|
859
870
|
const data = await res.json();
|
|
860
871
|
if (typeof data.api_key !== "string" || !data.api_key) return "failed";
|
|
872
|
+
const fresh = readConfig() ?? cfg;
|
|
861
873
|
writeConfig({
|
|
862
|
-
...
|
|
874
|
+
...fresh,
|
|
863
875
|
api_key: data.api_key,
|
|
864
876
|
tier: data.tier === "paid" ? "paid" : "free"
|
|
865
877
|
});
|
|
@@ -906,7 +918,7 @@ function bumpDecisionCount() {
|
|
|
906
918
|
sessionDecisions += 1;
|
|
907
919
|
const cfg = readConfig();
|
|
908
920
|
if (!cfg) return sessionDecisions;
|
|
909
|
-
const n = (cfg.decisions_count ?? 0) + 1;
|
|
921
|
+
const n = Math.max((cfg.decisions_count ?? 0) + 1, sessionDecisions);
|
|
910
922
|
cfg.decisions_count = n;
|
|
911
923
|
try {
|
|
912
924
|
writeConfig(cfg);
|
|
@@ -1264,7 +1276,7 @@ function renderAlertLine(alerts) {
|
|
|
1264
1276
|
var state = ensureState();
|
|
1265
1277
|
var core = makeCore();
|
|
1266
1278
|
var subject = process.env.FIDACY_SUBJECT ?? "agent:demo";
|
|
1267
|
-
var SERVER_VERSION = true ? "0.
|
|
1279
|
+
var SERVER_VERSION = true ? "0.3.1" : "dev";
|
|
1268
1280
|
var bootClaim = claimUrl();
|
|
1269
1281
|
var server = new McpServer(
|
|
1270
1282
|
{ name: "fidacy", version: SERVER_VERSION },
|
|
@@ -1331,6 +1343,7 @@ server.registerTool(
|
|
|
1331
1343
|
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false }
|
|
1332
1344
|
},
|
|
1333
1345
|
async () => {
|
|
1346
|
+
recordToolUse("verify");
|
|
1334
1347
|
const m = await core.getMandate(subject);
|
|
1335
1348
|
const payload = { mandate: m, fidacyPublicKey: core.publicKey() };
|
|
1336
1349
|
const claim = process.env.FIDACY_ENGINE_API_KEY ? null : claimUrl();
|
|
@@ -1409,6 +1422,7 @@ server.registerTool(
|
|
|
1409
1422
|
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false }
|
|
1410
1423
|
},
|
|
1411
1424
|
async ({ decisionId }) => {
|
|
1425
|
+
recordToolUse("explain");
|
|
1412
1426
|
const records = await core.history(5e3);
|
|
1413
1427
|
const record2 = records.find((r) => r.decisionId === decisionId);
|
|
1414
1428
|
if (!record2) {
|
|
@@ -1469,6 +1483,7 @@ server.registerTool(
|
|
|
1469
1483
|
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true }
|
|
1470
1484
|
},
|
|
1471
1485
|
async ({ kind, mandate, mandateType, idempotencyKey, spendingMandate, a2a }) => {
|
|
1486
|
+
recordToolUse("assess");
|
|
1472
1487
|
const engineUrl = process.env.FIDACY_ENGINE_URL ?? "https://api.fidacy.com";
|
|
1473
1488
|
const apiKey = (process.env.FIDACY_ENGINE_API_KEY ?? "").trim();
|
|
1474
1489
|
if (!apiKey) {
|
|
@@ -1519,6 +1534,7 @@ server.registerTool(
|
|
|
1519
1534
|
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true }
|
|
1520
1535
|
},
|
|
1521
1536
|
async ({ path, sha256: sha2562, kind, label, subject: subj }) => {
|
|
1537
|
+
recordToolUse("anchor");
|
|
1522
1538
|
const engineUrl = process.env.FIDACY_ENGINE_URL ?? "https://api.fidacy.com";
|
|
1523
1539
|
const apiKey = (process.env.FIDACY_ENGINE_API_KEY ?? "").trim();
|
|
1524
1540
|
if (!apiKey) {
|
|
@@ -1573,6 +1589,7 @@ server.registerTool(
|
|
|
1573
1589
|
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true }
|
|
1574
1590
|
},
|
|
1575
1591
|
async ({ path, sha256: sha2562 }) => {
|
|
1592
|
+
recordToolUse("check");
|
|
1576
1593
|
const engineUrl = process.env.FIDACY_ENGINE_URL ?? "https://api.fidacy.com";
|
|
1577
1594
|
const apiKey = (process.env.FIDACY_ENGINE_API_KEY ?? "").trim();
|
|
1578
1595
|
if (!apiKey) {
|
package/dist/lib.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ export { makeCore } from "./core.js";
|
|
|
3
3
|
export { ensureState, readConfig } from "./config.js";
|
|
4
4
|
export { requestUpgrade, upgradeUrl } from "./upgrade.js";
|
|
5
5
|
export { autoProvision } from "./provision.js";
|
|
6
|
-
export { recordInstall, recordAgentActive, setTelemetryShell } from "./telemetry.js";
|
|
6
|
+
export { recordInstall, recordAgentActive, setTelemetryShell, flush as flushTelemetry } from "./telemetry.js";
|
|
7
7
|
export { decisionNudge, weekOneBootNudge, nudgeOnce, installAgeDays, claimUrl, noKeyCta } from "./nudges.js";
|
|
8
8
|
export { FREE_DECISIONS, activationGate, activationBootLine, trialCountdownLine, hasEngineKey, remainingFree } from "./activation.js";
|
|
9
9
|
export { summarize, renderSummary, toRows, renderRows, explainRule, withinDays } from "./reporting.js";
|
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.1" : "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";
|
|
@@ -652,6 +652,14 @@ function anonId() {
|
|
|
652
652
|
}
|
|
653
653
|
var buffer = [];
|
|
654
654
|
var flushTimer = null;
|
|
655
|
+
var exitHookArmed = false;
|
|
656
|
+
function armExitFlush() {
|
|
657
|
+
if (exitHookArmed || typeof process === "undefined" || typeof process.once !== "function") return;
|
|
658
|
+
exitHookArmed = true;
|
|
659
|
+
process.once("beforeExit", () => {
|
|
660
|
+
if (buffer.length > 0) void flush();
|
|
661
|
+
});
|
|
662
|
+
}
|
|
655
663
|
function resultOf(status, violatedRule) {
|
|
656
664
|
if (status === "ALLOW") return "allow";
|
|
657
665
|
const r = violatedRule ?? "";
|
|
@@ -664,8 +672,9 @@ function resultOf(status, violatedRule) {
|
|
|
664
672
|
if (r.startsWith("non_positive_amount") || r.startsWith("invalid_")) return "deny_invalid";
|
|
665
673
|
return "deny_scope";
|
|
666
674
|
}
|
|
667
|
-
function record(type, result, band, capRatio) {
|
|
675
|
+
function record(type, result, band, capRatio, action) {
|
|
668
676
|
if (!telemetryEnabled()) return;
|
|
677
|
+
armExitFlush();
|
|
669
678
|
buffer.push({
|
|
670
679
|
type,
|
|
671
680
|
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -673,7 +682,8 @@ function record(type, result, band, capRatio) {
|
|
|
673
682
|
shell: currentShell,
|
|
674
683
|
...result ? { result } : {},
|
|
675
684
|
...band ? { band } : {},
|
|
676
|
-
...capRatio ? { cap_ratio: capRatio } : {}
|
|
685
|
+
...capRatio ? { cap_ratio: capRatio } : {},
|
|
686
|
+
...action ? { action } : {}
|
|
677
687
|
});
|
|
678
688
|
if (!flushTimer) {
|
|
679
689
|
flushTimer = setTimeout(() => {
|
|
@@ -791,7 +801,7 @@ function requestUpgrade() {
|
|
|
791
801
|
}
|
|
792
802
|
|
|
793
803
|
// src/provision.ts
|
|
794
|
-
var CLIENT_VERSION2 = true ? "0.
|
|
804
|
+
var CLIENT_VERSION2 = true ? "0.3.1" : "dev";
|
|
795
805
|
function provisionEnabled() {
|
|
796
806
|
const v = (process.env.FIDACY_DISABLE_PROVISION ?? "").trim().toLowerCase();
|
|
797
807
|
return !(v === "1" || v === "true" || v === "yes");
|
|
@@ -815,8 +825,9 @@ async function autoProvision() {
|
|
|
815
825
|
if (!res.ok) return "failed";
|
|
816
826
|
const data = await res.json();
|
|
817
827
|
if (typeof data.api_key !== "string" || !data.api_key) return "failed";
|
|
828
|
+
const fresh = readConfig() ?? cfg;
|
|
818
829
|
writeConfig({
|
|
819
|
-
...
|
|
830
|
+
...fresh,
|
|
820
831
|
api_key: data.api_key,
|
|
821
832
|
tier: data.tier === "paid" ? "paid" : "free"
|
|
822
833
|
});
|
|
@@ -851,7 +862,7 @@ function bumpDecisionCount() {
|
|
|
851
862
|
sessionDecisions += 1;
|
|
852
863
|
const cfg = readConfig();
|
|
853
864
|
if (!cfg) return sessionDecisions;
|
|
854
|
-
const n = (cfg.decisions_count ?? 0) + 1;
|
|
865
|
+
const n = Math.max((cfg.decisions_count ?? 0) + 1, sessionDecisions);
|
|
855
866
|
cfg.decisions_count = n;
|
|
856
867
|
try {
|
|
857
868
|
writeConfig(cfg);
|
|
@@ -1154,6 +1165,7 @@ export {
|
|
|
1154
1165
|
ensureState,
|
|
1155
1166
|
evaluate,
|
|
1156
1167
|
explainRule,
|
|
1168
|
+
flush as flushTelemetry,
|
|
1157
1169
|
hasEngineKey,
|
|
1158
1170
|
httpRedeem,
|
|
1159
1171
|
installAgeDays,
|
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.1",
|
|
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)",
|