@i4ctime/q-ring 0.16.2 → 0.17.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/README.md +4 -4
- package/dist/mcp.js +165 -155
- package/dist/mcp.js.map +1 -1
- package/package.json +3 -2
package/dist/mcp.js
CHANGED
|
@@ -48,6 +48,82 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
|
|
|
48
48
|
// src/mcp/server.ts
|
|
49
49
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
50
50
|
|
|
51
|
+
// src/mcp/tool-annotations.ts
|
|
52
|
+
var hints = (readOnlyHint, destructiveHint, idempotentHint, openWorldHint) => ({ readOnlyHint, destructiveHint, idempotentHint, openWorldHint });
|
|
53
|
+
var READ = hints(true, false, true, false);
|
|
54
|
+
var READ_OPEN = hints(true, false, true, true);
|
|
55
|
+
var TOOL_ANNOTATIONS = {
|
|
56
|
+
// secrets
|
|
57
|
+
get_secret: READ,
|
|
58
|
+
list_secrets: READ,
|
|
59
|
+
set_secret: hints(false, true, true, false),
|
|
60
|
+
delete_secret: hints(false, true, true, false),
|
|
61
|
+
has_secret: READ,
|
|
62
|
+
export_secrets: READ,
|
|
63
|
+
import_dotenv: hints(false, false, true, false),
|
|
64
|
+
// existing keys are skipped, not overwritten
|
|
65
|
+
inspect_secret: READ,
|
|
66
|
+
generate_secret: hints(false, true, false, false),
|
|
67
|
+
// saveAs overwrites; fresh value every call
|
|
68
|
+
entangle_secrets: hints(false, false, true, false),
|
|
69
|
+
disentangle_secrets: hints(false, false, true, false),
|
|
70
|
+
// project
|
|
71
|
+
check_project: READ,
|
|
72
|
+
env_generate: READ,
|
|
73
|
+
// renders text, never writes files
|
|
74
|
+
detect_environment: READ,
|
|
75
|
+
get_project_context: READ,
|
|
76
|
+
// tunnels (memory-only)
|
|
77
|
+
tunnel_create: hints(false, false, false, false),
|
|
78
|
+
tunnel_read: hints(false, true, false, false),
|
|
79
|
+
// may self-destruct on read
|
|
80
|
+
tunnel_list: READ,
|
|
81
|
+
tunnel_destroy: hints(false, true, true, false),
|
|
82
|
+
// teleport
|
|
83
|
+
teleport_pack: READ,
|
|
84
|
+
teleport_unpack: hints(false, true, true, false),
|
|
85
|
+
// imports may overwrite keys
|
|
86
|
+
// audit / health
|
|
87
|
+
audit_log: READ,
|
|
88
|
+
detect_anomalies: READ,
|
|
89
|
+
health_check: READ,
|
|
90
|
+
verify_audit_chain: READ,
|
|
91
|
+
export_audit: READ,
|
|
92
|
+
// validation / rotation (network)
|
|
93
|
+
validate_secret: READ_OPEN,
|
|
94
|
+
list_providers: READ,
|
|
95
|
+
rotate_secret: hints(false, true, false, true),
|
|
96
|
+
// replaces the credential upstream and locally
|
|
97
|
+
ci_validate_secrets: READ_OPEN,
|
|
98
|
+
// hooks
|
|
99
|
+
register_hook: hints(false, false, false, false),
|
|
100
|
+
list_hooks: READ,
|
|
101
|
+
remove_hook: hints(false, true, true, false),
|
|
102
|
+
// execution / scanning
|
|
103
|
+
exec_with_secrets: hints(false, true, false, true),
|
|
104
|
+
// arbitrary command
|
|
105
|
+
scan_codebase_for_secrets: READ,
|
|
106
|
+
lint_files: hints(false, true, true, false),
|
|
107
|
+
// fix:true rewrites source files
|
|
108
|
+
analyze_secrets: READ,
|
|
109
|
+
status_dashboard: hints(false, false, false, false),
|
|
110
|
+
// starts a local server, new token per launch
|
|
111
|
+
agent_scan: hints(false, true, false, true),
|
|
112
|
+
// autoRotate replaces expired credentials
|
|
113
|
+
// agent memory
|
|
114
|
+
agent_remember: hints(false, true, true, false),
|
|
115
|
+
agent_recall: READ,
|
|
116
|
+
agent_forget: hints(false, true, true, false),
|
|
117
|
+
// policy
|
|
118
|
+
check_policy: READ,
|
|
119
|
+
get_policy_summary: READ
|
|
120
|
+
};
|
|
121
|
+
function toolAnnotations(name) {
|
|
122
|
+
const a = TOOL_ANNOTATIONS[name];
|
|
123
|
+
if (!a) throw new Error(`q-ring: no tool annotations defined for "${name}"`);
|
|
124
|
+
return a;
|
|
125
|
+
}
|
|
126
|
+
|
|
51
127
|
// src/mcp/tools/secrets.ts
|
|
52
128
|
import { z as z2 } from "zod";
|
|
53
129
|
|
|
@@ -252,10 +328,7 @@ function opts(params) {
|
|
|
252
328
|
function enforceToolPolicy(toolName, projectPath8) {
|
|
253
329
|
const decision = checkToolPolicy(toolName, projectPath8);
|
|
254
330
|
if (!decision.allowed) {
|
|
255
|
-
return text(
|
|
256
|
-
`Policy Denied: ${decision.reason} (source: ${decision.policySource})`,
|
|
257
|
-
true
|
|
258
|
-
);
|
|
331
|
+
return text(`Policy Denied: ${decision.reason} (source: ${decision.policySource})`, true);
|
|
259
332
|
}
|
|
260
333
|
return null;
|
|
261
334
|
}
|
|
@@ -297,23 +370,18 @@ function registerSecretTools(server2) {
|
|
|
297
370
|
teamId,
|
|
298
371
|
orgId
|
|
299
372
|
},
|
|
373
|
+
toolAnnotations("get_secret"),
|
|
300
374
|
async (params) => {
|
|
301
375
|
const toolBlock = enforceToolPolicy("get_secret", params.projectPath);
|
|
302
376
|
if (toolBlock) return toolBlock;
|
|
303
377
|
try {
|
|
304
|
-
const keyBlock = checkKeyReadPolicy(
|
|
305
|
-
params.key,
|
|
306
|
-
void 0,
|
|
307
|
-
params.projectPath
|
|
308
|
-
);
|
|
378
|
+
const keyBlock = checkKeyReadPolicy(params.key, void 0, params.projectPath);
|
|
309
379
|
if (!keyBlock.allowed) {
|
|
310
380
|
return text(`Policy Denied: ${keyBlock.reason}`, true);
|
|
311
381
|
}
|
|
312
382
|
const value = getSecret(params.key, opts(params));
|
|
313
383
|
if (value === null) return text(`Secret "${params.key}" not found`, true);
|
|
314
|
-
return text(
|
|
315
|
-
JSON.stringify({ ok: true, data: { key: params.key, value } }, null, 2)
|
|
316
|
-
);
|
|
384
|
+
return text(JSON.stringify({ ok: true, data: { key: params.key, value } }, null, 2));
|
|
317
385
|
} catch (err) {
|
|
318
386
|
return text(err instanceof Error ? err.message : String(err), true);
|
|
319
387
|
}
|
|
@@ -344,22 +412,19 @@ function registerSecretTools(server2) {
|
|
|
344
412
|
teamId,
|
|
345
413
|
orgId
|
|
346
414
|
},
|
|
415
|
+
toolAnnotations("list_secrets"),
|
|
347
416
|
async (params) => {
|
|
348
417
|
const toolBlock = enforceToolPolicy("list_secrets", params.projectPath);
|
|
349
418
|
if (toolBlock) return toolBlock;
|
|
350
419
|
let entries = listSecrets(opts(params));
|
|
351
420
|
if (params.tag) {
|
|
352
|
-
entries = entries.filter(
|
|
353
|
-
(e) => e.envelope?.meta.tags?.includes(params.tag)
|
|
354
|
-
);
|
|
421
|
+
entries = entries.filter((e) => e.envelope?.meta.tags?.includes(params.tag));
|
|
355
422
|
}
|
|
356
423
|
if (params.expired) {
|
|
357
424
|
entries = entries.filter((e) => e.decay?.isExpired);
|
|
358
425
|
}
|
|
359
426
|
if (params.stale) {
|
|
360
|
-
entries = entries.filter(
|
|
361
|
-
(e) => e.decay?.isStale && !e.decay?.isExpired
|
|
362
|
-
);
|
|
427
|
+
entries = entries.filter((e) => e.decay?.isStale && !e.decay?.isExpired);
|
|
363
428
|
}
|
|
364
429
|
if (params.filter) {
|
|
365
430
|
entries = filterSecretsByKeyGlob(entries, params.filter);
|
|
@@ -386,9 +451,7 @@ function registerSecretTools(server2) {
|
|
|
386
451
|
"Mutates the keyring (overwrites any existing value at the same key/scope), writes a 'write' event to the audit log, and triggers any matching hooks. Subject to tool policy. Returns a short confirmation text like '[scope] KEY saved' (or '[scope] KEY set for env:NAME' when `env` is provided)."
|
|
387
452
|
].join(" "),
|
|
388
453
|
{
|
|
389
|
-
key: z2.string().describe(
|
|
390
|
-
"Secret key name (UPPER_SNAKE_CASE recommended). Example: 'STRIPE_SECRET_KEY'."
|
|
391
|
-
),
|
|
454
|
+
key: z2.string().describe("Secret key name (UPPER_SNAKE_CASE recommended). Example: 'STRIPE_SECRET_KEY'."),
|
|
392
455
|
value: z2.string().describe(
|
|
393
456
|
"The secret value to store. Stored as-is; never logged or echoed. May be empty only when `env` is provided to register a new env without a default."
|
|
394
457
|
),
|
|
@@ -403,18 +466,8 @@ function registerSecretTools(server2) {
|
|
|
403
466
|
description: z2.string().optional().describe(
|
|
404
467
|
"Free-text human-readable description shown in `inspect_secret` and the dashboard."
|
|
405
468
|
),
|
|
406
|
-
tags: z2.array(z2.string()).optional().describe(
|
|
407
|
-
|
|
408
|
-
),
|
|
409
|
-
rotationFormat: z2.enum([
|
|
410
|
-
"hex",
|
|
411
|
-
"base64",
|
|
412
|
-
"alphanumeric",
|
|
413
|
-
"uuid",
|
|
414
|
-
"api-key",
|
|
415
|
-
"token",
|
|
416
|
-
"password"
|
|
417
|
-
]).optional().describe(
|
|
469
|
+
tags: z2.array(z2.string()).optional().describe("Tag list for filtering and hook matching. Example: ['production', 'payments']."),
|
|
470
|
+
rotationFormat: z2.enum(["hex", "base64", "alphanumeric", "uuid", "api-key", "token", "password"]).optional().describe(
|
|
418
471
|
"Format used by `agent_scan --autoRotate` and `rotate_secret` when this secret expires. Pick the format that matches the upstream service's accepted shape."
|
|
419
472
|
),
|
|
420
473
|
rotationPrefix: z2.string().optional().describe(
|
|
@@ -423,6 +476,7 @@ function registerSecretTools(server2) {
|
|
|
423
476
|
teamId,
|
|
424
477
|
orgId
|
|
425
478
|
},
|
|
479
|
+
toolAnnotations("set_secret"),
|
|
426
480
|
async (params) => {
|
|
427
481
|
const toolBlock = enforceToolPolicy("set_secret", params.projectPath);
|
|
428
482
|
if (toolBlock) return toolBlock;
|
|
@@ -444,9 +498,7 @@ function registerSecretTools(server2) {
|
|
|
444
498
|
rotationFormat: params.rotationFormat,
|
|
445
499
|
rotationPrefix: params.rotationPrefix
|
|
446
500
|
});
|
|
447
|
-
return text(
|
|
448
|
-
`[${params.scope ?? "global"}] ${params.key} set for env:${params.env}`
|
|
449
|
-
);
|
|
501
|
+
return text(`[${params.scope ?? "global"}] ${params.key} set for env:${params.env}`);
|
|
450
502
|
}
|
|
451
503
|
setSecret(params.key, params.value, {
|
|
452
504
|
...o,
|
|
@@ -473,6 +525,7 @@ function registerSecretTools(server2) {
|
|
|
473
525
|
teamId,
|
|
474
526
|
orgId
|
|
475
527
|
},
|
|
528
|
+
toolAnnotations("delete_secret"),
|
|
476
529
|
async (params) => {
|
|
477
530
|
const toolBlock = enforceToolPolicy("delete_secret", params.projectPath);
|
|
478
531
|
if (toolBlock) return toolBlock;
|
|
@@ -497,6 +550,7 @@ function registerSecretTools(server2) {
|
|
|
497
550
|
teamId,
|
|
498
551
|
orgId
|
|
499
552
|
},
|
|
553
|
+
toolAnnotations("has_secret"),
|
|
500
554
|
async (params) => {
|
|
501
555
|
const toolBlock = enforceToolPolicy("has_secret", params.projectPath);
|
|
502
556
|
if (toolBlock) return toolBlock;
|
|
@@ -526,6 +580,7 @@ function registerSecretTools(server2) {
|
|
|
526
580
|
teamId,
|
|
527
581
|
orgId
|
|
528
582
|
},
|
|
583
|
+
toolAnnotations("export_secrets"),
|
|
529
584
|
async (params) => {
|
|
530
585
|
const toolBlock = enforceToolPolicy("export_secrets", params.projectPath);
|
|
531
586
|
if (toolBlock) return toolBlock;
|
|
@@ -559,6 +614,7 @@ function registerSecretTools(server2) {
|
|
|
559
614
|
"If true, parse and report what would happen but do not write to the keyring. Useful for previewing imports before committing."
|
|
560
615
|
)
|
|
561
616
|
},
|
|
617
|
+
toolAnnotations("import_dotenv"),
|
|
562
618
|
async (params) => {
|
|
563
619
|
const toolBlock = enforceToolPolicy("import_dotenv", params.projectPath);
|
|
564
620
|
if (toolBlock) return toolBlock;
|
|
@@ -595,6 +651,7 @@ function registerSecretTools(server2) {
|
|
|
595
651
|
teamId,
|
|
596
652
|
orgId
|
|
597
653
|
},
|
|
654
|
+
toolAnnotations("inspect_secret"),
|
|
598
655
|
async (params) => {
|
|
599
656
|
const toolBlock = enforceToolPolicy("inspect_secret", params.projectPath);
|
|
600
657
|
if (toolBlock) return toolBlock;
|
|
@@ -626,8 +683,7 @@ function registerSecretTools(server2) {
|
|
|
626
683
|
if (envelope.meta.entangled?.length) {
|
|
627
684
|
info.entangled = envelope.meta.entangled;
|
|
628
685
|
}
|
|
629
|
-
if (envelope.meta.description)
|
|
630
|
-
info.description = envelope.meta.description;
|
|
686
|
+
if (envelope.meta.description) info.description = envelope.meta.description;
|
|
631
687
|
if (envelope.meta.tags?.length) info.tags = envelope.meta.tags;
|
|
632
688
|
return text(JSON.stringify(info, null, 2));
|
|
633
689
|
}
|
|
@@ -640,15 +696,7 @@ function registerSecretTools(server2) {
|
|
|
640
696
|
"If `saveAs` is provided this mutates the keyring (one 'write' event) and returns a summary like 'Generated and saved as \"KEY\" (FORMAT, ~N bits entropy)'. Without `saveAs` the call is read-only and returns JSON `{ ok, data: { value } }` containing the freshly generated string."
|
|
641
697
|
].join(" "),
|
|
642
698
|
{
|
|
643
|
-
format: z2.enum([
|
|
644
|
-
"hex",
|
|
645
|
-
"base64",
|
|
646
|
-
"alphanumeric",
|
|
647
|
-
"uuid",
|
|
648
|
-
"api-key",
|
|
649
|
-
"token",
|
|
650
|
-
"password"
|
|
651
|
-
]).optional().default("api-key").describe(
|
|
699
|
+
format: z2.enum(["hex", "base64", "alphanumeric", "uuid", "api-key", "token", "password"]).optional().default("api-key").describe(
|
|
652
700
|
"Output shape. 'hex' / 'base64' / 'alphanumeric' = raw random string of `length` characters; 'uuid' = RFC4122 v4; 'api-key' / 'token' = random alphanumeric with optional `prefix`; 'password' = mixed-case alphanumeric with symbols. Defaults to 'api-key'."
|
|
653
701
|
),
|
|
654
702
|
length: z2.number().optional().describe(
|
|
@@ -665,6 +713,7 @@ function registerSecretTools(server2) {
|
|
|
665
713
|
teamId,
|
|
666
714
|
orgId
|
|
667
715
|
},
|
|
716
|
+
toolAnnotations("generate_secret"),
|
|
668
717
|
async (params) => {
|
|
669
718
|
const toolBlock = enforceToolPolicy("generate_secret", params.projectPath);
|
|
670
719
|
if (toolBlock) return toolBlock;
|
|
@@ -705,19 +754,14 @@ function registerSecretTools(server2) {
|
|
|
705
754
|
"Project root for targetKey when targetScope='project'. Defaults to the server cwd."
|
|
706
755
|
)
|
|
707
756
|
},
|
|
757
|
+
toolAnnotations("entangle_secrets"),
|
|
708
758
|
async (params) => {
|
|
709
|
-
const toolBlock = enforceToolPolicy(
|
|
710
|
-
"entangle_secrets",
|
|
711
|
-
params.sourceProjectPath
|
|
712
|
-
);
|
|
759
|
+
const toolBlock = enforceToolPolicy("entangle_secrets", params.sourceProjectPath);
|
|
713
760
|
if (toolBlock) return toolBlock;
|
|
714
761
|
for (const key of [params.sourceKey, params.targetKey]) {
|
|
715
762
|
const decision = checkKeyReadPolicy(key, void 0, params.sourceProjectPath);
|
|
716
763
|
if (!decision.allowed) {
|
|
717
|
-
return text(
|
|
718
|
-
`Policy Denied: ${decision.reason} (source: ${decision.policySource})`,
|
|
719
|
-
true
|
|
720
|
-
);
|
|
764
|
+
return text(`Policy Denied: ${decision.reason} (source: ${decision.policySource})`, true);
|
|
721
765
|
}
|
|
722
766
|
}
|
|
723
767
|
entangleSecrets(
|
|
@@ -752,11 +796,9 @@ function registerSecretTools(server2) {
|
|
|
752
796
|
sourceProjectPath: z2.string().optional().describe("Project root for sourceKey when sourceScope='project'."),
|
|
753
797
|
targetProjectPath: z2.string().optional().describe("Project root for targetKey when targetScope='project'.")
|
|
754
798
|
},
|
|
799
|
+
toolAnnotations("disentangle_secrets"),
|
|
755
800
|
async (params) => {
|
|
756
|
-
const toolBlock = enforceToolPolicy(
|
|
757
|
-
"disentangle_secrets",
|
|
758
|
-
params.sourceProjectPath
|
|
759
|
-
);
|
|
801
|
+
const toolBlock = enforceToolPolicy("disentangle_secrets", params.sourceProjectPath);
|
|
760
802
|
if (toolBlock) return toolBlock;
|
|
761
803
|
disentangleSecrets(
|
|
762
804
|
params.sourceKey,
|
|
@@ -789,9 +831,9 @@ var ProviderRegistry = class {
|
|
|
789
831
|
get(name) {
|
|
790
832
|
return this.providers.get(name);
|
|
791
833
|
}
|
|
792
|
-
detectProvider(value,
|
|
793
|
-
if (
|
|
794
|
-
return this.providers.get(
|
|
834
|
+
detectProvider(value, hints2) {
|
|
835
|
+
if (hints2?.provider) {
|
|
836
|
+
return this.providers.get(hints2.provider);
|
|
795
837
|
}
|
|
796
838
|
for (const provider of this.providers.values()) {
|
|
797
839
|
if (provider.prefixes) {
|
|
@@ -1147,6 +1189,7 @@ function registerProjectTools(server2) {
|
|
|
1147
1189
|
{
|
|
1148
1190
|
projectPath: projectPath2
|
|
1149
1191
|
},
|
|
1192
|
+
toolAnnotations("check_project"),
|
|
1150
1193
|
async (params) => {
|
|
1151
1194
|
const toolBlock = enforceToolPolicy("check_project", params.projectPath);
|
|
1152
1195
|
if (toolBlock) return toolBlock;
|
|
@@ -1219,6 +1262,7 @@ function registerProjectTools(server2) {
|
|
|
1219
1262
|
projectPath: projectPath2,
|
|
1220
1263
|
env: env2
|
|
1221
1264
|
},
|
|
1265
|
+
toolAnnotations("env_generate"),
|
|
1222
1266
|
async (params) => {
|
|
1223
1267
|
const toolBlock = enforceToolPolicy("env_generate", params.projectPath);
|
|
1224
1268
|
if (toolBlock) return toolBlock;
|
|
@@ -1269,19 +1313,15 @@ ${warnings.map((w) => `# ${w}`).join("\n")}` : output;
|
|
|
1269
1313
|
{
|
|
1270
1314
|
projectPath: projectPath2
|
|
1271
1315
|
},
|
|
1316
|
+
toolAnnotations("detect_environment"),
|
|
1272
1317
|
async (params) => {
|
|
1273
|
-
const toolBlock = enforceToolPolicy(
|
|
1274
|
-
"detect_environment",
|
|
1275
|
-
params.projectPath
|
|
1276
|
-
);
|
|
1318
|
+
const toolBlock = enforceToolPolicy("detect_environment", params.projectPath);
|
|
1277
1319
|
if (toolBlock) return toolBlock;
|
|
1278
1320
|
const result = collapseEnvironment({
|
|
1279
1321
|
projectPath: params.projectPath ?? process.cwd()
|
|
1280
1322
|
});
|
|
1281
1323
|
if (!result) {
|
|
1282
|
-
return text(
|
|
1283
|
-
"No environment detected. Set QRING_ENV, NODE_ENV, or create .q-ring.json"
|
|
1284
|
-
);
|
|
1324
|
+
return text("No environment detected. Set QRING_ENV, NODE_ENV, or create .q-ring.json");
|
|
1285
1325
|
}
|
|
1286
1326
|
return text(JSON.stringify(result, null, 2));
|
|
1287
1327
|
}
|
|
@@ -1299,11 +1339,9 @@ ${warnings.map((w) => `# ${w}`).join("\n")}` : output;
|
|
|
1299
1339
|
teamId: teamId2,
|
|
1300
1340
|
orgId: orgId2
|
|
1301
1341
|
},
|
|
1342
|
+
toolAnnotations("get_project_context"),
|
|
1302
1343
|
async (params) => {
|
|
1303
|
-
const toolBlock = enforceToolPolicy(
|
|
1304
|
-
"get_project_context",
|
|
1305
|
-
params.projectPath
|
|
1306
|
-
);
|
|
1344
|
+
const toolBlock = enforceToolPolicy("get_project_context", params.projectPath);
|
|
1307
1345
|
if (toolBlock) return toolBlock;
|
|
1308
1346
|
const context = getProjectContext(opts(params));
|
|
1309
1347
|
return text(JSON.stringify(context, null, 2));
|
|
@@ -1322,9 +1360,7 @@ function registerTunnelTools(server2) {
|
|
|
1322
1360
|
"Mutates only in-memory state \u2014 the value never touches disk and is lost on server restart. Subject to tool policy. Returns JSON `{ ok, data: { id } }` where `id` is an opaque string to pass to `tunnel_read`/`tunnel_destroy`."
|
|
1323
1361
|
].join(" "),
|
|
1324
1362
|
{
|
|
1325
|
-
value: z3.string().describe(
|
|
1326
|
-
"The plaintext value to tunnel. Held only in process memory; never logged."
|
|
1327
|
-
),
|
|
1363
|
+
value: z3.string().describe("The plaintext value to tunnel. Held only in process memory; never logged."),
|
|
1328
1364
|
ttlSeconds: z3.number().optional().describe(
|
|
1329
1365
|
"Auto-destroy the tunnel after this many seconds. Omit for no time limit (then a `maxReads` is highly recommended)."
|
|
1330
1366
|
),
|
|
@@ -1332,6 +1368,7 @@ function registerTunnelTools(server2) {
|
|
|
1332
1368
|
"Self-destruct after this many successful `tunnel_read` calls. Use 1 for true one-shot delivery."
|
|
1333
1369
|
)
|
|
1334
1370
|
},
|
|
1371
|
+
toolAnnotations("tunnel_create"),
|
|
1335
1372
|
async (params) => {
|
|
1336
1373
|
const toolBlock = enforceToolPolicy("tunnel_create");
|
|
1337
1374
|
if (toolBlock) return toolBlock;
|
|
@@ -1350,10 +1387,9 @@ function registerTunnelTools(server2) {
|
|
|
1350
1387
|
"Increments the read counter and may auto-destroy the tunnel if `maxReads` was set. Returns JSON `{ ok, data: { id, value } }` on success, or an error 'Tunnel \"...\" not found or expired' if the tunnel has been destroyed, hit its TTL, or never existed."
|
|
1351
1388
|
].join(" "),
|
|
1352
1389
|
{
|
|
1353
|
-
id: z3.string().describe(
|
|
1354
|
-
"The opaque tunnel ID returned by `tunnel_create`. Case-sensitive."
|
|
1355
|
-
)
|
|
1390
|
+
id: z3.string().describe("The opaque tunnel ID returned by `tunnel_create`. Case-sensitive.")
|
|
1356
1391
|
},
|
|
1392
|
+
toolAnnotations("tunnel_read"),
|
|
1357
1393
|
async (params) => {
|
|
1358
1394
|
const toolBlock = enforceToolPolicy("tunnel_read");
|
|
1359
1395
|
if (toolBlock) return toolBlock;
|
|
@@ -1361,9 +1397,7 @@ function registerTunnelTools(server2) {
|
|
|
1361
1397
|
if (value === null) {
|
|
1362
1398
|
return text(`Tunnel "${params.id}" not found or expired`, true);
|
|
1363
1399
|
}
|
|
1364
|
-
return text(
|
|
1365
|
-
JSON.stringify({ ok: true, data: { id: params.id, value } }, null, 2)
|
|
1366
|
-
);
|
|
1400
|
+
return text(JSON.stringify({ ok: true, data: { id: params.id, value } }, null, 2));
|
|
1367
1401
|
}
|
|
1368
1402
|
);
|
|
1369
1403
|
server2.tool(
|
|
@@ -1374,6 +1408,7 @@ function registerTunnelTools(server2) {
|
|
|
1374
1408
|
"Read-only. Returns one line per tunnel formatted as `id | reads:N | max:N | expires:Ns`, or the literal text 'No active tunnels' when the list is empty."
|
|
1375
1409
|
].join(" "),
|
|
1376
1410
|
{},
|
|
1411
|
+
toolAnnotations("tunnel_list"),
|
|
1377
1412
|
async () => {
|
|
1378
1413
|
const toolBlock = enforceToolPolicy("tunnel_list");
|
|
1379
1414
|
if (toolBlock) return toolBlock;
|
|
@@ -1384,10 +1419,7 @@ function registerTunnelTools(server2) {
|
|
|
1384
1419
|
parts.push(`reads:${t.accessCount}`);
|
|
1385
1420
|
if (t.maxReads) parts.push(`max:${t.maxReads}`);
|
|
1386
1421
|
if (t.expiresAt) {
|
|
1387
|
-
const rem = Math.max(
|
|
1388
|
-
0,
|
|
1389
|
-
Math.floor((t.expiresAt - Date.now()) / 1e3)
|
|
1390
|
-
);
|
|
1422
|
+
const rem = Math.max(0, Math.floor((t.expiresAt - Date.now()) / 1e3));
|
|
1391
1423
|
parts.push(`expires:${rem}s`);
|
|
1392
1424
|
}
|
|
1393
1425
|
return parts.join(" | ");
|
|
@@ -1405,6 +1437,7 @@ function registerTunnelTools(server2) {
|
|
|
1405
1437
|
{
|
|
1406
1438
|
id: z3.string().describe("The opaque tunnel ID to destroy.")
|
|
1407
1439
|
},
|
|
1440
|
+
toolAnnotations("tunnel_destroy"),
|
|
1408
1441
|
async (params) => {
|
|
1409
1442
|
const toolBlock = enforceToolPolicy("tunnel_destroy");
|
|
1410
1443
|
if (toolBlock) return toolBlock;
|
|
@@ -1558,6 +1591,7 @@ function registerTeleportTools(server2) {
|
|
|
1558
1591
|
teamId: teamId3,
|
|
1559
1592
|
orgId: orgId3
|
|
1560
1593
|
},
|
|
1594
|
+
toolAnnotations("teleport_pack"),
|
|
1561
1595
|
async (params) => {
|
|
1562
1596
|
const toolBlock = enforceToolPolicy("teleport_pack", params.projectPath);
|
|
1563
1597
|
if (toolBlock) return toolBlock;
|
|
@@ -1598,6 +1632,7 @@ function registerTeleportTools(server2) {
|
|
|
1598
1632
|
"If true, decrypt and report what would be written but do not mutate the keyring. Useful for verifying bundle contents before commit."
|
|
1599
1633
|
)
|
|
1600
1634
|
},
|
|
1635
|
+
toolAnnotations("teleport_unpack"),
|
|
1601
1636
|
async (params) => {
|
|
1602
1637
|
const toolBlock = enforceToolPolicy("teleport_unpack", params.projectPath);
|
|
1603
1638
|
if (toolBlock) return toolBlock;
|
|
@@ -1605,18 +1640,14 @@ function registerTeleportTools(server2) {
|
|
|
1605
1640
|
const payload = teleportUnpack(params.bundle, params.passphrase);
|
|
1606
1641
|
if (params.dryRun) {
|
|
1607
1642
|
const preview = payload.secrets.map((s) => `${s.key} [${s.scope ?? "global"}]`).join("\n");
|
|
1608
|
-
return text(
|
|
1609
|
-
|
|
1610
|
-
${preview}`
|
|
1611
|
-
);
|
|
1643
|
+
return text(`Would import ${payload.secrets.length} secrets:
|
|
1644
|
+
${preview}`);
|
|
1612
1645
|
}
|
|
1613
1646
|
const o = opts(params);
|
|
1614
1647
|
for (const s of payload.secrets) {
|
|
1615
1648
|
setSecret(s.key, s.value, o);
|
|
1616
1649
|
}
|
|
1617
|
-
return text(
|
|
1618
|
-
`Imported ${payload.secrets.length} secret(s) from teleport bundle`
|
|
1619
|
-
);
|
|
1650
|
+
return text(`Imported ${payload.secrets.length} secret(s) from teleport bundle`);
|
|
1620
1651
|
} catch (err) {
|
|
1621
1652
|
const msg = err instanceof Error ? err.message : String(err);
|
|
1622
1653
|
return text(JSON.stringify({ ok: false, error: { message: msg } }), true);
|
|
@@ -1637,9 +1668,7 @@ function registerAuditTools(server2) {
|
|
|
1637
1668
|
"Read-only. Returns one line per event in chronological order, formatted `timestamp | action | key | [scope] | env:NAME | detail`. Returns 'No audit events found' when the filter matches nothing."
|
|
1638
1669
|
].join(" "),
|
|
1639
1670
|
{
|
|
1640
|
-
key: z6.string().optional().describe(
|
|
1641
|
-
"Limit to events touching this exact key. Omit for the full log."
|
|
1642
|
-
),
|
|
1671
|
+
key: z6.string().optional().describe("Limit to events touching this exact key. Omit for the full log."),
|
|
1643
1672
|
action: z6.enum([
|
|
1644
1673
|
"read",
|
|
1645
1674
|
"write",
|
|
@@ -1667,6 +1696,7 @@ function registerAuditTools(server2) {
|
|
|
1667
1696
|
"Maximum events to return, newest first. Defaults to 20. Increase for deeper investigations."
|
|
1668
1697
|
)
|
|
1669
1698
|
},
|
|
1699
|
+
toolAnnotations("audit_log"),
|
|
1670
1700
|
async (params) => {
|
|
1671
1701
|
const toolBlock = enforceToolPolicy("audit_log");
|
|
1672
1702
|
if (toolBlock) return toolBlock;
|
|
@@ -1700,6 +1730,7 @@ function registerAuditTools(server2) {
|
|
|
1700
1730
|
"If provided, narrow the scan to this exact key. Omit to scan across every key in the audit log."
|
|
1701
1731
|
)
|
|
1702
1732
|
},
|
|
1733
|
+
toolAnnotations("detect_anomalies"),
|
|
1703
1734
|
async (params) => {
|
|
1704
1735
|
const toolBlock = enforceToolPolicy("detect_anomalies");
|
|
1705
1736
|
if (toolBlock) return toolBlock;
|
|
@@ -1722,6 +1753,7 @@ function registerAuditTools(server2) {
|
|
|
1722
1753
|
teamId: teamId4,
|
|
1723
1754
|
orgId: orgId4
|
|
1724
1755
|
},
|
|
1756
|
+
toolAnnotations("health_check"),
|
|
1725
1757
|
async (params) => {
|
|
1726
1758
|
const toolBlock = enforceToolPolicy("health_check", params.projectPath);
|
|
1727
1759
|
if (toolBlock) return toolBlock;
|
|
@@ -1758,11 +1790,7 @@ function registerAuditTools(server2) {
|
|
|
1758
1790
|
summary.push("", "Issues:", ...issues);
|
|
1759
1791
|
}
|
|
1760
1792
|
if (anomalies.length > 0) {
|
|
1761
|
-
summary.push(
|
|
1762
|
-
"",
|
|
1763
|
-
"Anomalies:",
|
|
1764
|
-
...anomalies.map((a) => `[${a.type}] ${a.description}`)
|
|
1765
|
-
);
|
|
1793
|
+
summary.push("", "Anomalies:", ...anomalies.map((a) => `[${a.type}] ${a.description}`));
|
|
1766
1794
|
}
|
|
1767
1795
|
return text(summary.join("\n"));
|
|
1768
1796
|
}
|
|
@@ -1775,6 +1803,7 @@ function registerAuditTools(server2) {
|
|
|
1775
1803
|
"Read-only. Returns JSON `{ ok, valid, brokenAt? }` where `valid` is `true` for an intact chain and `brokenAt` (when present) names the first event whose hash did not match."
|
|
1776
1804
|
].join(" "),
|
|
1777
1805
|
{},
|
|
1806
|
+
toolAnnotations("verify_audit_chain"),
|
|
1778
1807
|
async () => {
|
|
1779
1808
|
const toolBlock = enforceToolPolicy("verify_audit_chain");
|
|
1780
1809
|
if (toolBlock) return toolBlock;
|
|
@@ -1800,6 +1829,7 @@ function registerAuditTools(server2) {
|
|
|
1800
1829
|
"Output format. 'jsonl' (default) is most stream-friendly; 'json' is a single array; 'csv' is spreadsheet-friendly."
|
|
1801
1830
|
)
|
|
1802
1831
|
},
|
|
1832
|
+
toolAnnotations("export_audit"),
|
|
1803
1833
|
async (params) => {
|
|
1804
1834
|
const toolBlock = enforceToolPolicy("export_audit");
|
|
1805
1835
|
if (toolBlock) return toolBlock;
|
|
@@ -1838,6 +1868,7 @@ function registerValidationTools(server2) {
|
|
|
1838
1868
|
teamId: teamId5,
|
|
1839
1869
|
orgId: orgId5
|
|
1840
1870
|
},
|
|
1871
|
+
toolAnnotations("validate_secret"),
|
|
1841
1872
|
async (params) => {
|
|
1842
1873
|
const toolBlock = enforceToolPolicy("validate_secret", params.projectPath);
|
|
1843
1874
|
if (toolBlock) return toolBlock;
|
|
@@ -1857,6 +1888,7 @@ function registerValidationTools(server2) {
|
|
|
1857
1888
|
"Read-only. Returns JSON array of `{ name, description, prefixes }` objects. `prefixes` are the literal key-value prefixes (e.g. 'sk-' for OpenAI) used for auto-detection."
|
|
1858
1889
|
].join(" "),
|
|
1859
1890
|
{},
|
|
1891
|
+
toolAnnotations("list_providers"),
|
|
1860
1892
|
async () => {
|
|
1861
1893
|
const toolBlock = enforceToolPolicy("list_providers");
|
|
1862
1894
|
if (toolBlock) return toolBlock;
|
|
@@ -1885,6 +1917,7 @@ function registerValidationTools(server2) {
|
|
|
1885
1917
|
teamId: teamId5,
|
|
1886
1918
|
orgId: orgId5
|
|
1887
1919
|
},
|
|
1920
|
+
toolAnnotations("rotate_secret"),
|
|
1888
1921
|
async (params) => {
|
|
1889
1922
|
const toolBlock = enforceToolPolicy("rotate_secret", params.projectPath);
|
|
1890
1923
|
if (toolBlock) return toolBlock;
|
|
@@ -1914,11 +1947,9 @@ function registerValidationTools(server2) {
|
|
|
1914
1947
|
teamId: teamId5,
|
|
1915
1948
|
orgId: orgId5
|
|
1916
1949
|
},
|
|
1950
|
+
toolAnnotations("ci_validate_secrets"),
|
|
1917
1951
|
async (params) => {
|
|
1918
|
-
const toolBlock = enforceToolPolicy(
|
|
1919
|
-
"ci_validate_secrets",
|
|
1920
|
-
params.projectPath
|
|
1921
|
-
);
|
|
1952
|
+
const toolBlock = enforceToolPolicy("ci_validate_secrets", params.projectPath);
|
|
1922
1953
|
if (toolBlock) return toolBlock;
|
|
1923
1954
|
const entries = listSecrets(opts(params));
|
|
1924
1955
|
const secrets = entries.map((e) => {
|
|
@@ -1959,18 +1990,14 @@ function registerHookTools(server2) {
|
|
|
1959
1990
|
key: z8.string().optional().describe(
|
|
1960
1991
|
"Trigger only on this exact key name. Pick at most one of `key` / `keyPattern` / `tag` (or combine for stricter matching)."
|
|
1961
1992
|
),
|
|
1962
|
-
keyPattern: z8.string().optional().describe(
|
|
1963
|
-
"Trigger on any key matching this glob pattern. Examples: 'DB_*', 'STRIPE_*'."
|
|
1964
|
-
),
|
|
1993
|
+
keyPattern: z8.string().optional().describe("Trigger on any key matching this glob pattern. Examples: 'DB_*', 'STRIPE_*'."),
|
|
1965
1994
|
tag: z8.string().optional().describe(
|
|
1966
1995
|
"Trigger on any secret carrying this exact tag. Combinable with key/keyPattern as an AND filter."
|
|
1967
1996
|
),
|
|
1968
1997
|
scope: z8.enum(["global", "project"]).optional().describe(
|
|
1969
1998
|
"Restrict the hook to secrets in this scope. Omit to fire across both global and project secrets."
|
|
1970
1999
|
),
|
|
1971
|
-
actions: z8.array(z8.enum(["write", "delete", "rotate"])).optional().default(["write", "delete", "rotate"]).describe(
|
|
1972
|
-
"Which lifecycle actions trigger this hook. Defaults to all three."
|
|
1973
|
-
),
|
|
2000
|
+
actions: z8.array(z8.enum(["write", "delete", "rotate"])).optional().default(["write", "delete", "rotate"]).describe("Which lifecycle actions trigger this hook. Defaults to all three."),
|
|
1974
2001
|
command: z8.string().optional().describe(
|
|
1975
2002
|
"Required when type='shell'. The literal shell command to run; q-ring exposes the matching key as $QRING_HOOK_KEY and action as $QRING_HOOK_ACTION."
|
|
1976
2003
|
),
|
|
@@ -1987,14 +2014,12 @@ function registerHookTools(server2) {
|
|
|
1987
2014
|
"Free-text human-readable description, surfaced by `list_hooks` and the dashboard."
|
|
1988
2015
|
)
|
|
1989
2016
|
},
|
|
2017
|
+
toolAnnotations("register_hook"),
|
|
1990
2018
|
async (params) => {
|
|
1991
2019
|
const toolBlock = enforceToolPolicy("register_hook");
|
|
1992
2020
|
if (toolBlock) return toolBlock;
|
|
1993
2021
|
if (!params.key && !params.keyPattern && !params.tag) {
|
|
1994
|
-
return text(
|
|
1995
|
-
"At least one match criterion required: key, keyPattern, or tag",
|
|
1996
|
-
true
|
|
1997
|
-
);
|
|
2022
|
+
return text("At least one match criterion required: key, keyPattern, or tag", true);
|
|
1998
2023
|
}
|
|
1999
2024
|
const entry = registerHook({
|
|
2000
2025
|
type: params.type,
|
|
@@ -2022,6 +2047,7 @@ function registerHookTools(server2) {
|
|
|
2022
2047
|
"Read-only. Returns pretty-printed JSON array of hook entries, or 'No hooks registered' when the registry is empty."
|
|
2023
2048
|
].join(" "),
|
|
2024
2049
|
{},
|
|
2050
|
+
toolAnnotations("list_hooks"),
|
|
2025
2051
|
async () => {
|
|
2026
2052
|
const toolBlock = enforceToolPolicy("list_hooks");
|
|
2027
2053
|
if (toolBlock) return toolBlock;
|
|
@@ -2042,6 +2068,7 @@ function registerHookTools(server2) {
|
|
|
2042
2068
|
"Hook id returned by `register_hook` or visible in `list_hooks` (opaque string)."
|
|
2043
2069
|
)
|
|
2044
2070
|
},
|
|
2071
|
+
toolAnnotations("remove_hook"),
|
|
2045
2072
|
async (params) => {
|
|
2046
2073
|
const toolBlock = enforceToolPolicy("remove_hook");
|
|
2047
2074
|
if (toolBlock) return toolBlock;
|
|
@@ -2648,6 +2675,7 @@ function registerToolingTools(server2) {
|
|
|
2648
2675
|
teamId: teamId6,
|
|
2649
2676
|
orgId: orgId6
|
|
2650
2677
|
},
|
|
2678
|
+
toolAnnotations("exec_with_secrets"),
|
|
2651
2679
|
async (params) => {
|
|
2652
2680
|
const toolBlock = enforceToolPolicy("exec_with_secrets", params.projectPath);
|
|
2653
2681
|
if (toolBlock) return toolBlock;
|
|
@@ -2675,10 +2703,7 @@ ${result.stdout}`);
|
|
|
2675
2703
|
${result.stderr}`);
|
|
2676
2704
|
return text(output.join("\n\n"));
|
|
2677
2705
|
} catch (err) {
|
|
2678
|
-
return text(
|
|
2679
|
-
`Execution failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
2680
|
-
true
|
|
2681
|
-
);
|
|
2706
|
+
return text(`Execution failed: ${err instanceof Error ? err.message : String(err)}`, true);
|
|
2682
2707
|
}
|
|
2683
2708
|
}
|
|
2684
2709
|
);
|
|
@@ -2694,6 +2719,7 @@ ${result.stderr}`);
|
|
|
2694
2719
|
"Directory to scan, absolute or relative to the server cwd. The scan recurses into subdirectories."
|
|
2695
2720
|
)
|
|
2696
2721
|
},
|
|
2722
|
+
toolAnnotations("scan_codebase_for_secrets"),
|
|
2697
2723
|
async (params) => {
|
|
2698
2724
|
const toolBlock = enforceToolPolicy("scan_codebase_for_secrets");
|
|
2699
2725
|
if (toolBlock) return toolBlock;
|
|
@@ -2704,10 +2730,7 @@ ${result.stderr}`);
|
|
|
2704
2730
|
}
|
|
2705
2731
|
return text(JSON.stringify(results, null, 2));
|
|
2706
2732
|
} catch (err) {
|
|
2707
|
-
return text(
|
|
2708
|
-
`Scan failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
2709
|
-
true
|
|
2710
|
-
);
|
|
2733
|
+
return text(`Scan failed: ${err instanceof Error ? err.message : String(err)}`, true);
|
|
2711
2734
|
}
|
|
2712
2735
|
}
|
|
2713
2736
|
);
|
|
@@ -2719,9 +2742,7 @@ ${result.stderr}`);
|
|
|
2719
2742
|
"With `fix: false` this is read-only. With `fix: true` this MUTATES the listed source files in place (review with git diff!) and writes one new secret per finding to the keyring. Returns a JSON array of `{ file, line, key, value, kind }` findings, or 'No hardcoded secrets found in the specified files.'."
|
|
2720
2743
|
].join(" "),
|
|
2721
2744
|
{
|
|
2722
|
-
files: z9.array(z9.string()).describe(
|
|
2723
|
-
"Absolute or relative paths to lint. Non-existent paths surface as scan errors."
|
|
2724
|
-
),
|
|
2745
|
+
files: z9.array(z9.string()).describe("Absolute or relative paths to lint. Non-existent paths surface as scan errors."),
|
|
2725
2746
|
fix: z9.boolean().optional().default(false).describe(
|
|
2726
2747
|
"If true, rewrite the source files to read `process.env.KEY` and store the extracted value in the keyring. If false (default), only report findings."
|
|
2727
2748
|
),
|
|
@@ -2730,6 +2751,7 @@ ${result.stderr}`);
|
|
|
2730
2751
|
teamId: teamId6,
|
|
2731
2752
|
orgId: orgId6
|
|
2732
2753
|
},
|
|
2754
|
+
toolAnnotations("lint_files"),
|
|
2733
2755
|
async (params) => {
|
|
2734
2756
|
const toolBlock = enforceToolPolicy("lint_files", params.projectPath);
|
|
2735
2757
|
if (toolBlock) return toolBlock;
|
|
@@ -2744,10 +2766,7 @@ ${result.stderr}`);
|
|
|
2744
2766
|
}
|
|
2745
2767
|
return text(JSON.stringify(results, null, 2));
|
|
2746
2768
|
} catch (err) {
|
|
2747
|
-
return text(
|
|
2748
|
-
`Lint failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
2749
|
-
true
|
|
2750
|
-
);
|
|
2769
|
+
return text(`Lint failed: ${err instanceof Error ? err.message : String(err)}`, true);
|
|
2751
2770
|
}
|
|
2752
2771
|
}
|
|
2753
2772
|
);
|
|
@@ -2764,6 +2783,7 @@ ${result.stderr}`);
|
|
|
2764
2783
|
teamId: teamId6,
|
|
2765
2784
|
orgId: orgId6
|
|
2766
2785
|
},
|
|
2786
|
+
toolAnnotations("analyze_secrets"),
|
|
2767
2787
|
async (params) => {
|
|
2768
2788
|
const toolBlock = enforceToolPolicy("analyze_secrets", params.projectPath);
|
|
2769
2789
|
if (toolBlock) return toolBlock;
|
|
@@ -2800,13 +2820,12 @@ ${result.stderr}`);
|
|
|
2800
2820
|
"TCP port to listen on (default 9876). Pick another port if 9876 is already in use; the call fails if binding errors."
|
|
2801
2821
|
)
|
|
2802
2822
|
},
|
|
2823
|
+
toolAnnotations("status_dashboard"),
|
|
2803
2824
|
async (params) => {
|
|
2804
2825
|
const toolBlock = enforceToolPolicy("status_dashboard");
|
|
2805
2826
|
if (toolBlock) return toolBlock;
|
|
2806
2827
|
if (dashboardInstance) {
|
|
2807
|
-
return text(
|
|
2808
|
-
`Dashboard already running at ${dashboardInstance.url}`
|
|
2809
|
-
);
|
|
2828
|
+
return text(`Dashboard already running at ${dashboardInstance.url}`);
|
|
2810
2829
|
}
|
|
2811
2830
|
const { startDashboardServer } = await import("./dashboard-WVPR5BQO.js");
|
|
2812
2831
|
dashboardInstance = startDashboardServer({ port: params.port });
|
|
@@ -2831,6 +2850,7 @@ Open this URL in a browser to see live quantum status. The token is required for
|
|
|
2831
2850
|
"List of absolute project roots to scan. Defaults to `[server.cwd]` when omitted."
|
|
2832
2851
|
)
|
|
2833
2852
|
},
|
|
2853
|
+
toolAnnotations("agent_scan"),
|
|
2834
2854
|
async (params) => {
|
|
2835
2855
|
const toolBlock = enforceToolPolicy("agent_scan");
|
|
2836
2856
|
if (toolBlock) return toolBlock;
|
|
@@ -2861,6 +2881,7 @@ function registerAgentTools(server2) {
|
|
|
2861
2881
|
"Plain-string value to store. JSON-stringify structured data on the caller side if needed."
|
|
2862
2882
|
)
|
|
2863
2883
|
},
|
|
2884
|
+
toolAnnotations("agent_remember"),
|
|
2864
2885
|
async (params) => {
|
|
2865
2886
|
const toolBlock = enforceToolPolicy("agent_remember");
|
|
2866
2887
|
if (toolBlock) return toolBlock;
|
|
@@ -2876,10 +2897,9 @@ function registerAgentTools(server2) {
|
|
|
2876
2897
|
"Read-only. With a `key` argument: returns JSON `{ ok, data: { key, value } }` or a not-found error. Without `key`: returns a JSON listing of every stored key (no values), or 'Agent memory is empty'."
|
|
2877
2898
|
].join(" "),
|
|
2878
2899
|
{
|
|
2879
|
-
key: z10.string().optional().describe(
|
|
2880
|
-
"Memory key to read. Omit to list every stored key (without values)."
|
|
2881
|
-
)
|
|
2900
|
+
key: z10.string().optional().describe("Memory key to read. Omit to list every stored key (without values).")
|
|
2882
2901
|
},
|
|
2902
|
+
toolAnnotations("agent_recall"),
|
|
2883
2903
|
async (params) => {
|
|
2884
2904
|
const toolBlock = enforceToolPolicy("agent_recall");
|
|
2885
2905
|
if (toolBlock) return toolBlock;
|
|
@@ -2889,11 +2909,8 @@ function registerAgentTools(server2) {
|
|
|
2889
2909
|
return text(JSON.stringify(entries, null, 2));
|
|
2890
2910
|
}
|
|
2891
2911
|
const value = recall(params.key);
|
|
2892
|
-
if (value === null)
|
|
2893
|
-
|
|
2894
|
-
return text(
|
|
2895
|
-
JSON.stringify({ ok: true, data: { key: params.key, value } }, null, 2)
|
|
2896
|
-
);
|
|
2912
|
+
if (value === null) return text(`No memory found for "${params.key}"`, true);
|
|
2913
|
+
return text(JSON.stringify({ ok: true, data: { key: params.key, value } }, null, 2));
|
|
2897
2914
|
}
|
|
2898
2915
|
);
|
|
2899
2916
|
server2.tool(
|
|
@@ -2906,6 +2923,7 @@ function registerAgentTools(server2) {
|
|
|
2906
2923
|
{
|
|
2907
2924
|
key: z10.string().describe("Memory key to delete.")
|
|
2908
2925
|
},
|
|
2926
|
+
toolAnnotations("agent_forget"),
|
|
2909
2927
|
async (params) => {
|
|
2910
2928
|
const toolBlock = enforceToolPolicy("agent_forget");
|
|
2911
2929
|
if (toolBlock) return toolBlock;
|
|
@@ -2933,17 +2951,14 @@ function registerPolicyTools(server2) {
|
|
|
2933
2951
|
action: z11.enum(["tool", "key_read", "exec"]).describe(
|
|
2934
2952
|
"Which policy surface to query. 'tool' = MCP tool gate (needs `toolName`); 'key_read' = secret read gate (needs `key`); 'exec' = exec_with_secrets command gate (needs `command`)."
|
|
2935
2953
|
),
|
|
2936
|
-
toolName: z11.string().optional().describe(
|
|
2937
|
-
|
|
2938
|
-
),
|
|
2939
|
-
key: z11.string().optional().describe(
|
|
2940
|
-
"Secret key name to evaluate. Required when `action` is 'key_read'."
|
|
2941
|
-
),
|
|
2954
|
+
toolName: z11.string().optional().describe("Tool id to evaluate, e.g. 'rotate_secret'. Required when `action` is 'tool'."),
|
|
2955
|
+
key: z11.string().optional().describe("Secret key name to evaluate. Required when `action` is 'key_read'."),
|
|
2942
2956
|
command: z11.string().optional().describe(
|
|
2943
2957
|
"Command to evaluate against the exec allowlist/denylist. Required when `action` is 'exec'."
|
|
2944
2958
|
),
|
|
2945
2959
|
projectPath: projectPath7
|
|
2946
2960
|
},
|
|
2961
|
+
toolAnnotations("check_policy"),
|
|
2947
2962
|
async (params) => {
|
|
2948
2963
|
if (params.action === "tool" && params.toolName) {
|
|
2949
2964
|
const d = checkToolPolicy(params.toolName, params.projectPath);
|
|
@@ -2957,10 +2972,7 @@ function registerPolicyTools(server2) {
|
|
|
2957
2972
|
const d = checkExecPolicy(params.command, params.projectPath);
|
|
2958
2973
|
return text(JSON.stringify(d, null, 2));
|
|
2959
2974
|
}
|
|
2960
|
-
return text(
|
|
2961
|
-
"Missing required parameter for the selected action type",
|
|
2962
|
-
true
|
|
2963
|
-
);
|
|
2975
|
+
return text("Missing required parameter for the selected action type", true);
|
|
2964
2976
|
}
|
|
2965
2977
|
);
|
|
2966
2978
|
server2.tool(
|
|
@@ -2973,11 +2985,9 @@ function registerPolicyTools(server2) {
|
|
|
2973
2985
|
{
|
|
2974
2986
|
projectPath: projectPath7
|
|
2975
2987
|
},
|
|
2988
|
+
toolAnnotations("get_policy_summary"),
|
|
2976
2989
|
async (params) => {
|
|
2977
|
-
const toolBlock = enforceToolPolicy(
|
|
2978
|
-
"get_policy_summary",
|
|
2979
|
-
params.projectPath
|
|
2980
|
-
);
|
|
2990
|
+
const toolBlock = enforceToolPolicy("get_policy_summary", params.projectPath);
|
|
2981
2991
|
if (toolBlock) return toolBlock;
|
|
2982
2992
|
const summary = getPolicySummary(params.projectPath);
|
|
2983
2993
|
return text(JSON.stringify(summary, null, 2));
|