@fidacy/mcp 0.5.0 → 0.5.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 +6 -0
- package/dist/core.js +1 -1
- package/dist/index.js +21 -5
- package/dist/lib.d.ts +1 -0
- package/dist/lib.js +45 -2
- package/dist/register.d.ts +6 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.5.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Ask for the operator's email at setup, once. An MCP server is a headless subprocess — stdio is the protocol, so it can never prompt a human directly. What it can do is ask the agent to ask: on a first run with no email on record, the handshake instructions now tell the agent to request the operator's email at the start of its next reply and register it. The request disappears from the handshake the moment an email is on record, and if the operator declines the agent is told to drop it permanently. The firewall works either way.
|
|
8
|
+
|
|
3
9
|
## 0.4.2
|
|
4
10
|
|
|
5
11
|
### Patch Changes
|
package/dist/core.js
CHANGED
|
@@ -488,7 +488,7 @@ function resolveMandateRules(cfg) {
|
|
|
488
488
|
}
|
|
489
489
|
|
|
490
490
|
// src/telemetry.ts
|
|
491
|
-
var CLIENT_VERSION = true ? "0.5.
|
|
491
|
+
var CLIENT_VERSION = true ? "0.5.1" : "dev";
|
|
492
492
|
function bandOf(amount) {
|
|
493
493
|
if (typeof amount !== "number" || !Number.isFinite(amount) || amount <= 0) return void 0;
|
|
494
494
|
if (amount < 10) return "lt10";
|
package/dist/index.js
CHANGED
|
@@ -520,7 +520,7 @@ function resolveMandateRules(cfg) {
|
|
|
520
520
|
}
|
|
521
521
|
|
|
522
522
|
// src/telemetry.ts
|
|
523
|
-
var CLIENT_VERSION = true ? "0.5.
|
|
523
|
+
var CLIENT_VERSION = true ? "0.5.1" : "dev";
|
|
524
524
|
function bandOf(amount) {
|
|
525
525
|
if (typeof amount !== "number" || !Number.isFinite(amount) || amount <= 0) return void 0;
|
|
526
526
|
if (amount < 10) return "lt10";
|
|
@@ -882,7 +882,7 @@ async function findArtifacts(sha2562, cfg) {
|
|
|
882
882
|
}
|
|
883
883
|
|
|
884
884
|
// src/provision.ts
|
|
885
|
-
var CLIENT_VERSION2 = true ? "0.5.
|
|
885
|
+
var CLIENT_VERSION2 = true ? "0.5.1" : "dev";
|
|
886
886
|
function provisionEnabled() {
|
|
887
887
|
const v = (process.env.FIDACY_DISABLE_PROVISION ?? "").trim().toLowerCase();
|
|
888
888
|
return !(v === "1" || v === "true" || v === "yes");
|
|
@@ -919,7 +919,7 @@ async function autoProvision() {
|
|
|
919
919
|
}
|
|
920
920
|
|
|
921
921
|
// src/register.ts
|
|
922
|
-
var CLIENT_VERSION3 = true ? "0.5.
|
|
922
|
+
var CLIENT_VERSION3 = true ? "0.5.1" : "dev";
|
|
923
923
|
function endpoint3() {
|
|
924
924
|
const base = (process.env.FIDACY_ENGINE_URL ?? "https://api.fidacy.com").replace(/\/$/, "");
|
|
925
925
|
return `${base}/v1/register`;
|
|
@@ -952,6 +952,11 @@ async function registerEmail(email, shell = "mcp") {
|
|
|
952
952
|
return "failed";
|
|
953
953
|
}
|
|
954
954
|
}
|
|
955
|
+
function needsOperatorEmail() {
|
|
956
|
+
const cfg = readConfig();
|
|
957
|
+
if (!cfg) return false;
|
|
958
|
+
return !cfg.registered_email && !operatorEmail();
|
|
959
|
+
}
|
|
955
960
|
async function autoRegister(shell = "mcp") {
|
|
956
961
|
const email = operatorEmail();
|
|
957
962
|
if (!email) return "skipped";
|
|
@@ -1423,7 +1428,7 @@ function renderAlertLine(alerts) {
|
|
|
1423
1428
|
var state = ensureState();
|
|
1424
1429
|
var core = makeCore();
|
|
1425
1430
|
var subject = process.env.FIDACY_SUBJECT ?? "agent:demo";
|
|
1426
|
-
var SERVER_VERSION = true ? "0.5.
|
|
1431
|
+
var SERVER_VERSION = true ? "0.5.1" : "dev";
|
|
1427
1432
|
var bootClaim = claimUrl();
|
|
1428
1433
|
var server = new McpServer(
|
|
1429
1434
|
// The commercial identity. `name` is the stable slug hosts key on; `title` is
|
|
@@ -1432,7 +1437,18 @@ var server = new McpServer(
|
|
|
1432
1437
|
// download history for nothing, since what people SEE is this.
|
|
1433
1438
|
{ name: "fidacy-ai-agent-firewall", title: "Fidacy AI Agent Firewall", version: SERVER_VERSION },
|
|
1434
1439
|
{
|
|
1435
|
-
|
|
1440
|
+
// An MCP server is a headless subprocess: stdio IS the protocol, so it can
|
|
1441
|
+
// never prompt the operator for anything. `instructions` is the one channel
|
|
1442
|
+
// the host reliably hands to the MODEL, which makes the agent the only thing
|
|
1443
|
+
// that can ask a human a question on our behalf. On a FIRST RUN with no email
|
|
1444
|
+
// on record we therefore ask it to collect one — the closest thing to an
|
|
1445
|
+
// install-time field this transport allows. Asked once, never nagged: the
|
|
1446
|
+
// sentence disappears from the handshake as soon as an email is registered.
|
|
1447
|
+
instructions: [
|
|
1448
|
+
`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`,
|
|
1449
|
+
bootClaim ? ` (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_ENGINE_API_KEY).`,
|
|
1450
|
+
needsOperatorEmail() ? ` SETUP, do this once at the start of your next reply: ask the human operator for their email so this agent's protection history can be kept and moved into their free account, then call register_email with it. If they decline or ignore it, drop the subject and never ask again \u2014 the firewall works either way.` : ""
|
|
1451
|
+
].join("")
|
|
1436
1452
|
}
|
|
1437
1453
|
);
|
|
1438
1454
|
server.registerTool(
|
package/dist/lib.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ export { autoProvision } from "./provision.js";
|
|
|
6
6
|
export { recordInstall, recordAgentActive, setTelemetryShell, flush as flushTelemetry } from "./telemetry.js";
|
|
7
7
|
export { decisionNudge, weekOneBootNudge, nudgeOnce, installAgeDays, claimUrl, noKeyCta, hostedWallCta } from "./nudges.js";
|
|
8
8
|
export { FREE_DECISIONS, activationGate, activationBootLine, trialCountdownLine, hasEngineKey, remainingFree, decisionsUsed } from "./activation.js";
|
|
9
|
+
export { registerEmail, autoRegister, operatorEmail } from "./register.js";
|
|
9
10
|
export { BRAND, protectionBadge, protectionWarning, protectionBootLine, protectionState, markHostedLapsed, clearHostedLapsed, isHostedLapsed, } from "./protection.js";
|
|
10
11
|
export { summarize, renderSummary, toRows, renderRows, explainRule, withinDays } from "./reporting.js";
|
|
11
12
|
export type { SpendSummary, DecisionRow } from "./reporting.js";
|
package/dist/lib.js
CHANGED
|
@@ -643,7 +643,7 @@ function resolveMandateRules(cfg) {
|
|
|
643
643
|
}
|
|
644
644
|
|
|
645
645
|
// src/telemetry.ts
|
|
646
|
-
var CLIENT_VERSION = true ? "0.5.
|
|
646
|
+
var CLIENT_VERSION = true ? "0.5.1" : "dev";
|
|
647
647
|
function bandOf(amount) {
|
|
648
648
|
if (typeof amount !== "number" || !Number.isFinite(amount) || amount <= 0) return void 0;
|
|
649
649
|
if (amount < 10) return "lt10";
|
|
@@ -831,7 +831,7 @@ function requestUpgrade() {
|
|
|
831
831
|
}
|
|
832
832
|
|
|
833
833
|
// src/provision.ts
|
|
834
|
-
var CLIENT_VERSION2 = true ? "0.5.
|
|
834
|
+
var CLIENT_VERSION2 = true ? "0.5.1" : "dev";
|
|
835
835
|
function provisionEnabled() {
|
|
836
836
|
const v = (process.env.FIDACY_DISABLE_PROVISION ?? "").trim().toLowerCase();
|
|
837
837
|
return !(v === "1" || v === "true" || v === "yes");
|
|
@@ -993,6 +993,46 @@ function activationBootLine() {
|
|
|
993
993
|
return ` Anonymous trial: ${used}/${FREE_DECISIONS} free decisions used; after that the firewall requires a free API key.`;
|
|
994
994
|
}
|
|
995
995
|
|
|
996
|
+
// src/register.ts
|
|
997
|
+
var CLIENT_VERSION3 = true ? "0.5.1" : "dev";
|
|
998
|
+
function endpoint3() {
|
|
999
|
+
const base = (process.env.FIDACY_ENGINE_URL ?? "https://api.fidacy.com").replace(/\/$/, "");
|
|
1000
|
+
return `${base}/v1/register`;
|
|
1001
|
+
}
|
|
1002
|
+
function looksLikeEmail(s) {
|
|
1003
|
+
return /^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(s);
|
|
1004
|
+
}
|
|
1005
|
+
function operatorEmail(override) {
|
|
1006
|
+
const raw = (override ?? process.env.FIDACY_OPERATOR_EMAIL ?? readConfig()?.operator_email ?? "").trim();
|
|
1007
|
+
return raw && looksLikeEmail(raw) ? raw : null;
|
|
1008
|
+
}
|
|
1009
|
+
async function registerEmail(email, shell = "mcp") {
|
|
1010
|
+
const cfg = readConfig();
|
|
1011
|
+
if (!cfg) return "skipped";
|
|
1012
|
+
const clean = email.trim();
|
|
1013
|
+
if (!looksLikeEmail(clean)) return "skipped";
|
|
1014
|
+
if (cfg.registered_email && cfg.registered_email.toLowerCase() === clean.toLowerCase()) return "skipped";
|
|
1015
|
+
try {
|
|
1016
|
+
const res = await fetch(endpoint3(), {
|
|
1017
|
+
method: "POST",
|
|
1018
|
+
headers: { "content-type": "application/json" },
|
|
1019
|
+
body: JSON.stringify({ anon_id: cfg.anon_id, email: clean, client_version: CLIENT_VERSION3, shell })
|
|
1020
|
+
});
|
|
1021
|
+
if (res.status === 429) return "rate_limited";
|
|
1022
|
+
if (!res.ok) return "failed";
|
|
1023
|
+
const fresh = readConfig() ?? cfg;
|
|
1024
|
+
writeConfig({ ...fresh, operator_email: clean, registered_email: clean });
|
|
1025
|
+
return "registered";
|
|
1026
|
+
} catch {
|
|
1027
|
+
return "failed";
|
|
1028
|
+
}
|
|
1029
|
+
}
|
|
1030
|
+
async function autoRegister(shell = "mcp") {
|
|
1031
|
+
const email = operatorEmail();
|
|
1032
|
+
if (!email) return "skipped";
|
|
1033
|
+
return registerEmail(email, shell);
|
|
1034
|
+
}
|
|
1035
|
+
|
|
996
1036
|
// src/protection.ts
|
|
997
1037
|
var BRAND = "Fidacy AI Agent Firewall";
|
|
998
1038
|
var FREE_MONTHLY_VERDICTS = 300;
|
|
@@ -1269,6 +1309,7 @@ export {
|
|
|
1269
1309
|
activationGate,
|
|
1270
1310
|
assessPattern,
|
|
1271
1311
|
autoProvision,
|
|
1312
|
+
autoRegister,
|
|
1272
1313
|
canonInvoice,
|
|
1273
1314
|
claimUrl,
|
|
1274
1315
|
clearHostedLapsed,
|
|
@@ -1289,6 +1330,7 @@ export {
|
|
|
1289
1330
|
markHostedLapsed,
|
|
1290
1331
|
noKeyCta,
|
|
1291
1332
|
nudgeOnce,
|
|
1333
|
+
operatorEmail,
|
|
1292
1334
|
protectionBadge,
|
|
1293
1335
|
protectionBootLine,
|
|
1294
1336
|
protectionState,
|
|
@@ -1297,6 +1339,7 @@ export {
|
|
|
1297
1339
|
readConfig,
|
|
1298
1340
|
recordAgentActive,
|
|
1299
1341
|
recordInstall,
|
|
1342
|
+
registerEmail,
|
|
1300
1343
|
remainingFree,
|
|
1301
1344
|
renderAlertLine,
|
|
1302
1345
|
renderRows,
|
package/dist/register.d.ts
CHANGED
|
@@ -6,6 +6,12 @@ export declare function operatorEmail(override?: string): string | null;
|
|
|
6
6
|
* we do not re-send every boot. Returns the outcome for tests/logs.
|
|
7
7
|
*/
|
|
8
8
|
export declare function registerEmail(email: string, shell?: string): Promise<"registered" | "skipped" | "rate_limited" | "failed">;
|
|
9
|
+
/**
|
|
10
|
+
* True when nobody has given us an email for this install yet — the signal the
|
|
11
|
+
* boot instructions use to have the agent ask ONCE. Goes false the moment an
|
|
12
|
+
* address is provided or registered, so the ask never becomes a nag.
|
|
13
|
+
*/
|
|
14
|
+
export declare function needsOperatorEmail(): boolean;
|
|
9
15
|
/**
|
|
10
16
|
* Boot-time auto-register: if the operator set FIDACY_OPERATOR_EMAIL (or the
|
|
11
17
|
* config field) and we have not sent it yet, register in the background. NEVER
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fidacy/mcp",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.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)",
|