@aspect-warden/mcp-server 0.4.1 → 0.5.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/dist/index.js +95 -42
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -64,18 +64,58 @@ function decrypt(payload, passphrase) {
|
|
|
64
64
|
return decrypted;
|
|
65
65
|
}
|
|
66
66
|
const STORAGE_KEY = process.env.WARDEN_STORAGE_KEY || `warden-${homedir()}`;
|
|
67
|
-
function
|
|
67
|
+
function ensureStorageDir() {
|
|
68
|
+
if (!existsSync(STORAGE_DIR)) {
|
|
69
|
+
mkdirSync(STORAGE_DIR, { recursive: true, mode: 0o700 });
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
function saveFullState() {
|
|
73
|
+
if (!storedPrivateKey || !policyEngine)
|
|
74
|
+
return;
|
|
68
75
|
try {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
76
|
+
ensureStorageDir();
|
|
77
|
+
const p = policyEngine.getPolicy();
|
|
78
|
+
const state = {
|
|
79
|
+
privateKey: storedPrivateKey,
|
|
80
|
+
agentId: p.agentId,
|
|
81
|
+
policy: {
|
|
82
|
+
maxPerTx: p.maxPerTx.toString(),
|
|
83
|
+
dailyLimit: p.dailyLimit.toString(),
|
|
84
|
+
requireApprovalAbove: p.requireApprovalAbove.toString(),
|
|
85
|
+
cooldownMs: p.cooldownMs,
|
|
86
|
+
allowedTokens: p.allowedTokens,
|
|
87
|
+
blockedTokens: p.blockedTokens,
|
|
88
|
+
allowedRecipients: p.allowedRecipients,
|
|
89
|
+
blockedRecipients: p.blockedRecipients,
|
|
90
|
+
allowedChains: p.allowedChains,
|
|
91
|
+
},
|
|
92
|
+
tracker: policyEngine.exportTracker(),
|
|
93
|
+
auditLog: auditLogger?.exportEntries() ?? [],
|
|
94
|
+
frozen,
|
|
95
|
+
sessionKeys: Array.from(sessionKeys.entries()).map(([key, data]) => ({
|
|
96
|
+
key,
|
|
97
|
+
data: {
|
|
98
|
+
agentAddress: data.agentAddress,
|
|
99
|
+
maxPerTx: data.maxPerTx.toString(),
|
|
100
|
+
dailyLimit: data.dailyLimit.toString(),
|
|
101
|
+
validUntil: data.validUntil,
|
|
102
|
+
cooldownSeconds: data.cooldownSeconds,
|
|
103
|
+
createdAt: data.createdAt,
|
|
104
|
+
revoked: data.revoked,
|
|
105
|
+
txHash: data.txHash,
|
|
106
|
+
},
|
|
107
|
+
})),
|
|
108
|
+
permissionGrants: Array.from(permissionGrants.entries()).map(([key, data]) => ({
|
|
109
|
+
key, data,
|
|
110
|
+
})),
|
|
111
|
+
};
|
|
72
112
|
const json = JSON.stringify(state);
|
|
73
113
|
const encrypted = encrypt(json, STORAGE_KEY);
|
|
74
114
|
writeFileSync(STATE_FILE, encrypted, { mode: 0o600 });
|
|
75
|
-
console.error('[Warden MCP]
|
|
115
|
+
console.error('[Warden MCP] Full state saved to ~/.warden/wallet-state.enc');
|
|
76
116
|
}
|
|
77
117
|
catch (err) {
|
|
78
|
-
console.error('[Warden MCP] Failed to save
|
|
118
|
+
console.error('[Warden MCP] Failed to save state:', err);
|
|
79
119
|
}
|
|
80
120
|
}
|
|
81
121
|
function loadState() {
|
|
@@ -172,22 +212,8 @@ server.tool('warden_create_wallet', 'Create a new policy-enforced wallet for the
|
|
|
172
212
|
policyEngine = new PolicyEngine(policy);
|
|
173
213
|
auditLogger = new AuditLogger({ maxEntries: 10000 });
|
|
174
214
|
frozen = false;
|
|
175
|
-
// Persist
|
|
176
|
-
|
|
177
|
-
privateKey: storedPrivateKey,
|
|
178
|
-
agentId,
|
|
179
|
-
policy: {
|
|
180
|
-
maxPerTx: policy.maxPerTx.toString(),
|
|
181
|
-
dailyLimit: policy.dailyLimit.toString(),
|
|
182
|
-
requireApprovalAbove: policy.requireApprovalAbove.toString(),
|
|
183
|
-
cooldownMs: policy.cooldownMs,
|
|
184
|
-
allowedTokens: policy.allowedTokens,
|
|
185
|
-
blockedTokens: policy.blockedTokens,
|
|
186
|
-
allowedRecipients: policy.allowedRecipients,
|
|
187
|
-
blockedRecipients: policy.blockedRecipients,
|
|
188
|
-
allowedChains: policy.allowedChains,
|
|
189
|
-
},
|
|
190
|
-
});
|
|
215
|
+
// Persist full state for recovery across restarts
|
|
216
|
+
saveFullState();
|
|
191
217
|
return {
|
|
192
218
|
content: [{
|
|
193
219
|
type: 'text',
|
|
@@ -321,6 +347,7 @@ server.tool('warden_transfer', 'Send ERC-20 tokens with policy enforcement. Eval
|
|
|
321
347
|
const valueMicro = BigInt(Math.round(amount * 1e6));
|
|
322
348
|
const decision = policyEngine.evaluate(recipient, valueMicro, tokenAddress, 'ethereum');
|
|
323
349
|
auditLogger.log(decision);
|
|
350
|
+
saveFullState(); // Persist audit log entry (blocked or approved)
|
|
324
351
|
if (!decision.approved) {
|
|
325
352
|
const currentPolicy = policyEngine.getPolicy();
|
|
326
353
|
return {
|
|
@@ -376,6 +403,8 @@ server.tool('warden_transfer', 'Send ERC-20 tokens with policy enforcement. Eval
|
|
|
376
403
|
blockNumber: Number(receipt.blockNumber),
|
|
377
404
|
gasUsed: receipt.gasUsed,
|
|
378
405
|
});
|
|
406
|
+
// Persist spending tracker + audit log after successful transfer
|
|
407
|
+
saveFullState();
|
|
379
408
|
return {
|
|
380
409
|
content: [{
|
|
381
410
|
type: 'text',
|
|
@@ -492,24 +521,7 @@ server.tool('warden_update_policy', 'Modify policy rules at runtime. Can update
|
|
|
492
521
|
}
|
|
493
522
|
policyEngine.updatePolicy(updates);
|
|
494
523
|
// Persist updated policy so it survives restarts
|
|
495
|
-
|
|
496
|
-
const p = policyEngine.getPolicy();
|
|
497
|
-
saveState({
|
|
498
|
-
privateKey: storedPrivateKey,
|
|
499
|
-
agentId: p.agentId,
|
|
500
|
-
policy: {
|
|
501
|
-
maxPerTx: p.maxPerTx.toString(),
|
|
502
|
-
dailyLimit: p.dailyLimit.toString(),
|
|
503
|
-
requireApprovalAbove: p.requireApprovalAbove.toString(),
|
|
504
|
-
cooldownMs: p.cooldownMs,
|
|
505
|
-
allowedTokens: p.allowedTokens,
|
|
506
|
-
blockedTokens: p.blockedTokens,
|
|
507
|
-
allowedRecipients: p.allowedRecipients,
|
|
508
|
-
blockedRecipients: p.blockedRecipients,
|
|
509
|
-
allowedChains: p.allowedChains,
|
|
510
|
-
},
|
|
511
|
-
});
|
|
512
|
-
}
|
|
524
|
+
saveFullState();
|
|
513
525
|
return {
|
|
514
526
|
content: [{
|
|
515
527
|
type: 'text',
|
|
@@ -522,6 +534,7 @@ server.tool('warden_update_policy', 'Modify policy rules at runtime. Can update
|
|
|
522
534
|
// ============================================================
|
|
523
535
|
server.tool('warden_freeze', 'EMERGENCY: Freeze all wallet operations immediately. No transfers will be allowed until unfrozen.', {}, async () => {
|
|
524
536
|
frozen = true;
|
|
537
|
+
saveFullState();
|
|
525
538
|
return {
|
|
526
539
|
content: [{
|
|
527
540
|
type: 'text',
|
|
@@ -538,6 +551,7 @@ server.tool('warden_freeze', 'EMERGENCY: Freeze all wallet operations immediatel
|
|
|
538
551
|
// ============================================================
|
|
539
552
|
server.tool('warden_unfreeze', 'Resume wallet operations after an emergency freeze.', {}, async () => {
|
|
540
553
|
frozen = false;
|
|
554
|
+
saveFullState();
|
|
541
555
|
return {
|
|
542
556
|
content: [{
|
|
543
557
|
type: 'text',
|
|
@@ -628,6 +642,7 @@ server.tool('warden_create_session_key', 'Create a scoped session key for a sub-
|
|
|
628
642
|
txHash: hash,
|
|
629
643
|
};
|
|
630
644
|
sessionKeys.set(agentAddress.toLowerCase(), sessionData);
|
|
645
|
+
saveFullState();
|
|
631
646
|
return {
|
|
632
647
|
content: [{
|
|
633
648
|
type: 'text',
|
|
@@ -705,6 +720,7 @@ server.tool('warden_revoke_session_key', 'Revoke a previously created session ke
|
|
|
705
720
|
};
|
|
706
721
|
}
|
|
707
722
|
session.revoked = true;
|
|
723
|
+
saveFullState();
|
|
708
724
|
return {
|
|
709
725
|
content: [{
|
|
710
726
|
type: 'text',
|
|
@@ -728,6 +744,7 @@ server.tool('warden_revoke_session_key', 'Revoke a previously created session ke
|
|
|
728
744
|
}
|
|
729
745
|
}
|
|
730
746
|
session.revoked = true;
|
|
747
|
+
saveFullState();
|
|
731
748
|
return {
|
|
732
749
|
content: [{
|
|
733
750
|
type: 'text',
|
|
@@ -958,6 +975,7 @@ server.tool('warden_grant_permissions', 'Grant scoped permissions to an AI agent
|
|
|
958
975
|
txHash,
|
|
959
976
|
};
|
|
960
977
|
permissionGrants.set(agentId, grant);
|
|
978
|
+
saveFullState();
|
|
961
979
|
return {
|
|
962
980
|
content: [{
|
|
963
981
|
type: 'text',
|
|
@@ -1050,6 +1068,7 @@ server.tool('warden_revoke_permissions', 'Revoke all permissions from an AI agen
|
|
|
1050
1068
|
});
|
|
1051
1069
|
frozen = true;
|
|
1052
1070
|
permissionGrants.delete(agentId);
|
|
1071
|
+
saveFullState();
|
|
1053
1072
|
return {
|
|
1054
1073
|
content: [{
|
|
1055
1074
|
type: 'text',
|
|
@@ -1156,8 +1175,42 @@ async function main() {
|
|
|
1156
1175
|
};
|
|
1157
1176
|
policyEngine = new PolicyEngine(restoredPolicy);
|
|
1158
1177
|
auditLogger = new AuditLogger({ maxEntries: 10000 });
|
|
1159
|
-
|
|
1160
|
-
|
|
1178
|
+
// Restore spending tracker
|
|
1179
|
+
if (saved.tracker) {
|
|
1180
|
+
policyEngine.importTracker(saved.tracker);
|
|
1181
|
+
console.error('[Warden MCP] Restored spending tracker');
|
|
1182
|
+
}
|
|
1183
|
+
// Restore audit log
|
|
1184
|
+
if (saved.auditLog && Array.isArray(saved.auditLog)) {
|
|
1185
|
+
auditLogger.loadEntries(saved.auditLog);
|
|
1186
|
+
console.error(`[Warden MCP] Restored ${saved.auditLog.length} audit log entries`);
|
|
1187
|
+
}
|
|
1188
|
+
// Restore frozen state
|
|
1189
|
+
frozen = saved.frozen ?? false;
|
|
1190
|
+
// Restore session keys
|
|
1191
|
+
if (saved.sessionKeys) {
|
|
1192
|
+
for (const { key, data } of saved.sessionKeys) {
|
|
1193
|
+
sessionKeys.set(key, {
|
|
1194
|
+
agentAddress: data.agentAddress,
|
|
1195
|
+
maxPerTx: BigInt(data.maxPerTx || '0'),
|
|
1196
|
+
dailyLimit: BigInt(data.dailyLimit || '0'),
|
|
1197
|
+
validUntil: data.validUntil,
|
|
1198
|
+
cooldownSeconds: data.cooldownSeconds,
|
|
1199
|
+
createdAt: data.createdAt,
|
|
1200
|
+
revoked: data.revoked,
|
|
1201
|
+
txHash: data.txHash,
|
|
1202
|
+
});
|
|
1203
|
+
}
|
|
1204
|
+
console.error(`[Warden MCP] Restored ${saved.sessionKeys.length} session keys`);
|
|
1205
|
+
}
|
|
1206
|
+
// Restore permission grants
|
|
1207
|
+
if (saved.permissionGrants) {
|
|
1208
|
+
for (const { key, data } of saved.permissionGrants) {
|
|
1209
|
+
permissionGrants.set(key, data);
|
|
1210
|
+
}
|
|
1211
|
+
console.error(`[Warden MCP] Restored ${saved.permissionGrants.length} permission grants`);
|
|
1212
|
+
}
|
|
1213
|
+
console.error(`[Warden MCP] Restored wallet ${walletAddress} (agent: ${saved.agentId}, frozen: ${frozen})`);
|
|
1161
1214
|
}
|
|
1162
1215
|
catch (err) {
|
|
1163
1216
|
console.error('[Warden MCP] Failed to restore wallet state:', err);
|