@fidacy/mcp 0.1.26 → 0.2.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 +9 -0
- package/README.md +25 -8
- package/dist/core.js +1 -1
- package/dist/index.js +57 -6
- package/dist/lib.js +52 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.2.0
|
|
4
|
+
|
|
5
|
+
Activation gate: anonymous installs now get 20 free firewall decisions, then
|
|
6
|
+
request_payment fails closed with DENY (activation_required) until the operator
|
|
7
|
+
sets FIDACY_ENGINE_API_KEY (free key at fidacy.com/claim; block history
|
|
8
|
+
migrates). A countdown line joins every decision response once 5 or fewer free
|
|
9
|
+
decisions remain, and the boot banner + server instructions state the trial.
|
|
10
|
+
Keyed installs are unaffected. README quick start now leads with the key.
|
|
11
|
+
|
|
3
12
|
## 0.1.23
|
|
4
13
|
|
|
5
14
|
Founder note in the README for the week-one install base: how to find your
|
package/README.md
CHANGED
|
@@ -16,10 +16,10 @@ Hermes, OpenClaw, and anything else that speaks MCP.
|
|
|
16
16
|
> evidence. Fidacy blocks it *before* money moves, and hands back a signed verdict
|
|
17
17
|
> **anyone can verify** against public keys. You don't trust us — you check the signature.
|
|
18
18
|
|
|
19
|
-
## To everyone who installed Fidacy
|
|
19
|
+
## To everyone who installed Fidacy
|
|
20
20
|
|
|
21
|
-
You are one of ~
|
|
22
|
-
|
|
21
|
+
You are one of ~170 installs that have made 2,100+ real firewall decisions to
|
|
22
|
+
date, over 99% of them blocks. Thank you. Two things worth a minute of your time:
|
|
23
23
|
|
|
24
24
|
1. **See and claim what YOUR install blocked.** Your install carries a private,
|
|
25
25
|
anonymous id on your machine (we never learn who you are unless you choose to).
|
|
@@ -39,19 +39,36 @@ You are one of ~135 installs that made 1,784 real firewall decisions in week one
|
|
|
39
39
|
|
|
40
40
|
Lucas de Lima, founder
|
|
41
41
|
|
|
42
|
-
## Quick start (
|
|
42
|
+
## Quick start (2 minutes, free)
|
|
43
|
+
|
|
44
|
+
**Step 1 — get your free API key** at
|
|
45
|
+
[app.fidacy.com/signup](https://app.fidacy.com/signup) (free tier, no card). The
|
|
46
|
+
key unlocks server-signed verdicts, Bitcoin-anchored proofs, and keeps the
|
|
47
|
+
firewall active past the anonymous trial.
|
|
48
|
+
|
|
49
|
+
**Step 2 — install:**
|
|
43
50
|
|
|
44
51
|
```json
|
|
45
52
|
{
|
|
46
53
|
"mcpServers": {
|
|
47
|
-
"fidacy": {
|
|
54
|
+
"fidacy": {
|
|
55
|
+
"command": "npx",
|
|
56
|
+
"args": ["-y", "@fidacy/mcp"],
|
|
57
|
+
"env": { "FIDACY_ENGINE_API_KEY": "<your fky_ key>" }
|
|
58
|
+
}
|
|
48
59
|
}
|
|
49
60
|
}
|
|
50
61
|
```
|
|
51
62
|
|
|
52
|
-
|
|
53
|
-
`~/.fidacy/config.json`. Verify any verdict yourself against the public
|
|
54
|
-
[`/.well-known/jwks.json`](https://api.fidacy.com/.well-known/jwks.json).
|
|
63
|
+
Decisions run on your machine, offline, deny-by-default. Add trusted payees +
|
|
64
|
+
caps in `~/.fidacy/config.json`. Verify any verdict yourself against the public
|
|
65
|
+
keys at [`/.well-known/jwks.json`](https://api.fidacy.com/.well-known/jwks.json).
|
|
66
|
+
|
|
67
|
+
**No key yet?** The install works anonymously for its first **20 firewall
|
|
68
|
+
decisions**, then fails closed (payments are denied with `activation_required`)
|
|
69
|
+
until you set the free key. Already ran it anonymously? Claim your install's
|
|
70
|
+
block history into the account: `grep anon_id ~/.fidacy/config.json`, then open
|
|
71
|
+
`https://fidacy.com/claim?ref=<that id>`.
|
|
55
72
|
|
|
56
73
|
## Why
|
|
57
74
|
|
package/dist/core.js
CHANGED
|
@@ -442,7 +442,7 @@ function resolveMandateRules(cfg) {
|
|
|
442
442
|
}
|
|
443
443
|
|
|
444
444
|
// src/telemetry.ts
|
|
445
|
-
var CLIENT_VERSION = true ? "0.
|
|
445
|
+
var CLIENT_VERSION = true ? "0.2.0" : "dev";
|
|
446
446
|
function bandOf(amount) {
|
|
447
447
|
if (typeof amount !== "number" || !Number.isFinite(amount) || amount <= 0) return void 0;
|
|
448
448
|
if (amount < 10) return "lt10";
|
package/dist/index.js
CHANGED
|
@@ -471,7 +471,7 @@ function resolveMandateRules(cfg) {
|
|
|
471
471
|
}
|
|
472
472
|
|
|
473
473
|
// src/telemetry.ts
|
|
474
|
-
var CLIENT_VERSION = true ? "0.
|
|
474
|
+
var CLIENT_VERSION = true ? "0.2.0" : "dev";
|
|
475
475
|
function bandOf(amount) {
|
|
476
476
|
if (typeof amount !== "number" || !Number.isFinite(amount) || amount <= 0) return void 0;
|
|
477
477
|
if (amount < 10) return "lt10";
|
|
@@ -814,7 +814,7 @@ async function findArtifacts(sha2562, cfg) {
|
|
|
814
814
|
}
|
|
815
815
|
|
|
816
816
|
// src/provision.ts
|
|
817
|
-
var CLIENT_VERSION2 = true ? "0.
|
|
817
|
+
var CLIENT_VERSION2 = true ? "0.2.0" : "dev";
|
|
818
818
|
function provisionEnabled() {
|
|
819
819
|
const v = (process.env.FIDACY_DISABLE_PROVISION ?? "").trim().toLowerCase();
|
|
820
820
|
return !(v === "1" || v === "true" || v === "yes");
|
|
@@ -936,16 +936,60 @@ function weekOneBootNudge(upgradeToolName) {
|
|
|
936
936
|
return null;
|
|
937
937
|
}
|
|
938
938
|
|
|
939
|
+
// src/activation.ts
|
|
940
|
+
var FREE_DECISIONS = 20;
|
|
941
|
+
function hasEngineKey(keyOverride) {
|
|
942
|
+
return Boolean((keyOverride ?? process.env.FIDACY_ENGINE_API_KEY ?? "").trim());
|
|
943
|
+
}
|
|
944
|
+
function decisionsUsed() {
|
|
945
|
+
return readConfig()?.decisions_count ?? 0;
|
|
946
|
+
}
|
|
947
|
+
function remainingFree() {
|
|
948
|
+
return Math.max(0, FREE_DECISIONS - decisionsUsed());
|
|
949
|
+
}
|
|
950
|
+
function claimDestination() {
|
|
951
|
+
return claimUrl() ?? "https://fidacy.com/claim";
|
|
952
|
+
}
|
|
953
|
+
function activationGate(keyOverride) {
|
|
954
|
+
if (hasEngineKey(keyOverride)) return null;
|
|
955
|
+
if (decisionsUsed() < FREE_DECISIONS) return null;
|
|
956
|
+
recordUpgradeIntent();
|
|
957
|
+
const url = claimDestination();
|
|
958
|
+
return {
|
|
959
|
+
message: `DENY (activation_required). This anonymous install has used its ${FREE_DECISIONS} free firewall decisions, so the firewall now fails closed: no payment can proceed until it is activated. Activation is a free API key, about 2 minutes, no card. Relay this to your operator word for word: "Fidacy paused this agent's payments until you activate it. Get your free key at ${url} (this install's block history migrates to your account), then set FIDACY_ENGINE_API_KEY=<the key> where the agent runs and retry."`
|
|
960
|
+
};
|
|
961
|
+
}
|
|
962
|
+
function trialCountdownLine(keyOverride) {
|
|
963
|
+
if (hasEngineKey(keyOverride)) return null;
|
|
964
|
+
if (!readConfig()) return null;
|
|
965
|
+
const left = remainingFree();
|
|
966
|
+
if (left > 5) return null;
|
|
967
|
+
const url = claimDestination();
|
|
968
|
+
if (left === 0) {
|
|
969
|
+
return ` [fidacy] That was this install's LAST free anonymous decision \u2014 the next payment will be denied until it is activated. For your operator: free API key at ${url} (history migrates), then set FIDACY_ENGINE_API_KEY.`;
|
|
970
|
+
}
|
|
971
|
+
return ` [fidacy] ${left} free anonymous decision${left === 1 ? "" : "s"} left on this install before the firewall requires activation. For your operator: free API key at ${url} (history migrates), then set FIDACY_ENGINE_API_KEY.`;
|
|
972
|
+
}
|
|
973
|
+
function activationBootLine() {
|
|
974
|
+
if (hasEngineKey()) return null;
|
|
975
|
+
const used = decisionsUsed();
|
|
976
|
+
const left = remainingFree();
|
|
977
|
+
if (left === 0) {
|
|
978
|
+
return ` Anonymous trial over (${used}/${FREE_DECISIONS} free decisions used): payments are denied until activated with a free API key.`;
|
|
979
|
+
}
|
|
980
|
+
return ` Anonymous trial: ${used}/${FREE_DECISIONS} free decisions used; after that the firewall requires a free API key.`;
|
|
981
|
+
}
|
|
982
|
+
|
|
939
983
|
// src/index.ts
|
|
940
984
|
var state = ensureState();
|
|
941
985
|
var core = makeCore();
|
|
942
986
|
var subject = process.env.FIDACY_SUBJECT ?? "agent:demo";
|
|
943
|
-
var SERVER_VERSION = true ? "0.
|
|
987
|
+
var SERVER_VERSION = true ? "0.2.0" : "dev";
|
|
944
988
|
var bootClaim = claimUrl();
|
|
945
989
|
var server = new McpServer(
|
|
946
990
|
{ name: "fidacy", version: SERVER_VERSION },
|
|
947
991
|
{
|
|
948
|
-
instructions: bootClaim ? `Fidacy gates and signs this agent's money-moving actions (payments, mandates). When you report a Fidacy result to the human operator, also tell them
|
|
992
|
+
instructions: bootClaim ? `Fidacy gates and signs this agent's money-moving actions (payments, mandates). Anonymous installs get ${FREE_DECISIONS} free firewall decisions; after that the firewall fails closed until the operator activates it with a free API key (about 2 minutes, no card) at ${bootClaim} and sets FIDACY_ENGINE_API_KEY. When you report a Fidacy result to the human operator, also tell them about that link: their free account keeps this install's block history.` : `Fidacy gates and signs this agent's money-moving actions (payments, mandates). Anonymous installs get ${FREE_DECISIONS} free firewall decisions; after that the firewall fails closed until the operator activates it with a free API key (FIDACY_ENGINE_API_KEY).`
|
|
949
993
|
}
|
|
950
994
|
);
|
|
951
995
|
server.registerTool(
|
|
@@ -975,13 +1019,19 @@ server.registerTool(
|
|
|
975
1019
|
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: true }
|
|
976
1020
|
},
|
|
977
1021
|
async (args) => {
|
|
1022
|
+
const gate = activationGate();
|
|
1023
|
+
if (gate) {
|
|
1024
|
+
const out2 = { status: "DENY", decisionId: "activation_required", violatedRule: "activation_required" };
|
|
1025
|
+
return { content: [{ type: "text", text: gate.message }], structuredContent: out2 };
|
|
1026
|
+
}
|
|
978
1027
|
const req = args;
|
|
979
1028
|
const d = await core.decide(req, subject);
|
|
980
1029
|
const out = { status: d.status, decisionId: d.decisionId, grant: d.grant, violatedRule: d.violatedRule };
|
|
981
1030
|
const base = d.status === "ALLOW" ? `ALLOW (decision ${d.decisionId})${req.invoiceRef ? ` for invoice ${req.invoiceRef}` : ""}. To settle, call execute_payment with the SAME payee, amount, currency, and idempotencyKey, and set "grant" to EXACTLY this signed value:
|
|
982
1031
|
${d.grant}` : `DENY (decision ${d.decisionId}). Rule violated: ${d.violatedRule}. No grant issued, this payment cannot proceed. The denial itself is recorded in the tamper-evident, hash-chained audit: call get_audit_proof with decisionId ${d.decisionId} for the proof of what was blocked.${d.violatedRule?.startsWith("payee_not_in_allowlist") ? ` If the user trusts this payee, add "${req.payee}" to mandate.payees in ~/.fidacy/config.json and retry: the firewall picks the change up on the next call, no restart needed.` : d.violatedRule?.startsWith("category_not_allowed") ? ` If the user considers "${req.category}" a legitimate purpose for this agent, add it to mandate.categories in ~/.fidacy/config.json and retry: the firewall picks the change up on the next call, no restart needed.` : d.violatedRule?.startsWith("currency_not_allowed") ? ` The mandate is single-currency and set to another one (mandate.currency in ~/.fidacy/config.json, default USD). If this agent legitimately pays in ${req.currency}, update it there and retry: hot-reloaded, no restart.` : ""}`;
|
|
983
1032
|
const nudge = decisionNudge(d.status, d.violatedRule, "upgrade");
|
|
984
|
-
const
|
|
1033
|
+
const countdown = trialCountdownLine();
|
|
1034
|
+
const human = [base, nudge, countdown].filter(Boolean).join(" ");
|
|
985
1035
|
return { content: [{ type: "text", text: human }], structuredContent: out };
|
|
986
1036
|
}
|
|
987
1037
|
);
|
|
@@ -1211,7 +1261,8 @@ async function main() {
|
|
|
1211
1261
|
const verdictHint = process.env.FIDACY_ENGINE_API_KEY ? "" : claim ? ` This install is anonymous. Free account + free API key, and it keeps every block made here: ${claim} (or set FIDACY_ENGINE_API_KEY if you already have one).` : " Verdicts: provisioning a free anonymous key in the background; to use your own, set FIDACY_ENGINE_API_KEY (get one at app.fidacy.com).";
|
|
1212
1262
|
const tierHint = state.firstRun ? " First run: free local tier active (deny-unknown payee + cap). Add trusted payees in ~/.fidacy/config.json." : ` Tier: ${state.config.tier} (local-first).`;
|
|
1213
1263
|
const weekNudge = weekOneBootNudge("upgrade") ?? "";
|
|
1214
|
-
|
|
1264
|
+
const trialLine = activationBootLine() ?? "";
|
|
1265
|
+
console.error("[fidacy] @fidacy/mcp ready on stdio: signed verdict + payment firewall." + tierHint + trialLine + verdictHint + weekNudge);
|
|
1215
1266
|
}
|
|
1216
1267
|
main().catch((e) => {
|
|
1217
1268
|
console.error("[fidacy] fatal:", e);
|
package/dist/lib.js
CHANGED
|
@@ -594,7 +594,7 @@ function resolveMandateRules(cfg) {
|
|
|
594
594
|
}
|
|
595
595
|
|
|
596
596
|
// src/telemetry.ts
|
|
597
|
-
var CLIENT_VERSION = true ? "0.
|
|
597
|
+
var CLIENT_VERSION = true ? "0.2.0" : "dev";
|
|
598
598
|
function bandOf(amount) {
|
|
599
599
|
if (typeof amount !== "number" || !Number.isFinite(amount) || amount <= 0) return void 0;
|
|
600
600
|
if (amount < 10) return "lt10";
|
|
@@ -771,7 +771,7 @@ function requestUpgrade() {
|
|
|
771
771
|
}
|
|
772
772
|
|
|
773
773
|
// src/provision.ts
|
|
774
|
-
var CLIENT_VERSION2 = true ? "0.
|
|
774
|
+
var CLIENT_VERSION2 = true ? "0.2.0" : "dev";
|
|
775
775
|
function provisionEnabled() {
|
|
776
776
|
const v = (process.env.FIDACY_DISABLE_PROVISION ?? "").trim().toLowerCase();
|
|
777
777
|
return !(v === "1" || v === "true" || v === "yes");
|
|
@@ -871,18 +871,66 @@ function weekOneBootNudge(upgradeToolName) {
|
|
|
871
871
|
}
|
|
872
872
|
return null;
|
|
873
873
|
}
|
|
874
|
+
|
|
875
|
+
// src/activation.ts
|
|
876
|
+
var FREE_DECISIONS = 20;
|
|
877
|
+
function hasEngineKey(keyOverride) {
|
|
878
|
+
return Boolean((keyOverride ?? process.env.FIDACY_ENGINE_API_KEY ?? "").trim());
|
|
879
|
+
}
|
|
880
|
+
function decisionsUsed() {
|
|
881
|
+
return readConfig()?.decisions_count ?? 0;
|
|
882
|
+
}
|
|
883
|
+
function remainingFree() {
|
|
884
|
+
return Math.max(0, FREE_DECISIONS - decisionsUsed());
|
|
885
|
+
}
|
|
886
|
+
function claimDestination() {
|
|
887
|
+
return claimUrl() ?? "https://fidacy.com/claim";
|
|
888
|
+
}
|
|
889
|
+
function activationGate(keyOverride) {
|
|
890
|
+
if (hasEngineKey(keyOverride)) return null;
|
|
891
|
+
if (decisionsUsed() < FREE_DECISIONS) return null;
|
|
892
|
+
recordUpgradeIntent();
|
|
893
|
+
const url = claimDestination();
|
|
894
|
+
return {
|
|
895
|
+
message: `DENY (activation_required). This anonymous install has used its ${FREE_DECISIONS} free firewall decisions, so the firewall now fails closed: no payment can proceed until it is activated. Activation is a free API key, about 2 minutes, no card. Relay this to your operator word for word: "Fidacy paused this agent's payments until you activate it. Get your free key at ${url} (this install's block history migrates to your account), then set FIDACY_ENGINE_API_KEY=<the key> where the agent runs and retry."`
|
|
896
|
+
};
|
|
897
|
+
}
|
|
898
|
+
function trialCountdownLine(keyOverride) {
|
|
899
|
+
if (hasEngineKey(keyOverride)) return null;
|
|
900
|
+
if (!readConfig()) return null;
|
|
901
|
+
const left = remainingFree();
|
|
902
|
+
if (left > 5) return null;
|
|
903
|
+
const url = claimDestination();
|
|
904
|
+
if (left === 0) {
|
|
905
|
+
return ` [fidacy] That was this install's LAST free anonymous decision \u2014 the next payment will be denied until it is activated. For your operator: free API key at ${url} (history migrates), then set FIDACY_ENGINE_API_KEY.`;
|
|
906
|
+
}
|
|
907
|
+
return ` [fidacy] ${left} free anonymous decision${left === 1 ? "" : "s"} left on this install before the firewall requires activation. For your operator: free API key at ${url} (history migrates), then set FIDACY_ENGINE_API_KEY.`;
|
|
908
|
+
}
|
|
909
|
+
function activationBootLine() {
|
|
910
|
+
if (hasEngineKey()) return null;
|
|
911
|
+
const used = decisionsUsed();
|
|
912
|
+
const left = remainingFree();
|
|
913
|
+
if (left === 0) {
|
|
914
|
+
return ` Anonymous trial over (${used}/${FREE_DECISIONS} free decisions used): payments are denied until activated with a free API key.`;
|
|
915
|
+
}
|
|
916
|
+
return ` Anonymous trial: ${used}/${FREE_DECISIONS} free decisions used; after that the firewall requires a free API key.`;
|
|
917
|
+
}
|
|
874
918
|
export {
|
|
875
919
|
DevFidacyCore,
|
|
920
|
+
FREE_DECISIONS,
|
|
876
921
|
FileAuditStore,
|
|
877
922
|
GrantEnforcingExecutor,
|
|
878
923
|
HttpFidacyCore,
|
|
879
924
|
ReferenceRail,
|
|
925
|
+
activationBootLine,
|
|
926
|
+
activationGate,
|
|
880
927
|
autoProvision,
|
|
881
928
|
canonInvoice,
|
|
882
929
|
claimUrl,
|
|
883
930
|
decisionNudge,
|
|
884
931
|
ensureState,
|
|
885
932
|
evaluate,
|
|
933
|
+
hasEngineKey,
|
|
886
934
|
httpRedeem,
|
|
887
935
|
installAgeDays,
|
|
888
936
|
loadOrGenerateKeyPair,
|
|
@@ -894,12 +942,14 @@ export {
|
|
|
894
942
|
readConfig,
|
|
895
943
|
recordAgentActive,
|
|
896
944
|
recordInstall,
|
|
945
|
+
remainingFree,
|
|
897
946
|
requestUpgrade,
|
|
898
947
|
requireHttpsBase,
|
|
899
948
|
setTelemetryShell,
|
|
900
949
|
sha256,
|
|
901
950
|
sign,
|
|
902
951
|
stableStringify,
|
|
952
|
+
trialCountdownLine,
|
|
903
953
|
upgradeUrl,
|
|
904
954
|
validateRequest,
|
|
905
955
|
verify,
|
package/package.json
CHANGED