@seekrit/cli 0.31.0 → 0.32.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 CHANGED
@@ -2720,7 +2720,7 @@ function isCliSessionToken(value) {
2720
2720
  }
2721
2721
  //#endregion
2722
2722
  //#region package.json
2723
- var version = "0.31.0";
2723
+ var version = "0.32.0";
2724
2724
  //#endregion
2725
2725
  //#region ../../packages/api-client/src/index.ts
2726
2726
  var SeekritApiError = class extends Error {
@@ -7395,7 +7395,7 @@ registerMongoCommands(program);
7395
7395
  registerKmsCommands(program);
7396
7396
  registerRecoveryCommands(program);
7397
7397
  program.command("mcp").description("run an MCP server over stdio so AI agents can drive seekrit").action(async () => {
7398
- const { runMcpServer } = await import("./mcp-DLplPOvz.js");
7398
+ const { runMcpServer } = await import("./mcp-DR-zla_u.js");
7399
7399
  await runMcpServer();
7400
7400
  });
7401
7401
  registerAuditCommands(program);
@@ -26,6 +26,16 @@ function errText(err) {
26
26
  isError: true
27
27
  };
28
28
  }
29
+ /** Read-only and safe to repeat — every list/inspect tool. */
30
+ const ro = {
31
+ readOnly: true,
32
+ idempotent: true
33
+ };
34
+ /** Removes or overwrites something; repeating it lands in the same state. */
35
+ const destructive = {
36
+ destructive: true,
37
+ idempotent: true
38
+ };
29
39
  /**
30
40
  * Short primer surfaced as the MCP server `instructions`. Most clients show
31
41
  * this to the model on connect, so it has to orient an agent that lands here
@@ -194,10 +204,17 @@ async function runMcpServer(options = {}) {
194
204
  version: options.version ?? version
195
205
  }, { instructions: serverInstructions() });
196
206
  /** Register a tool whose handler returns data (serialized) or throws (→ isError). */
197
- const tool = (name, description, shape, handler) => {
207
+ const tool = (name, description, hints, shape, handler) => {
198
208
  server.registerTool(name, {
199
209
  description,
200
- inputSchema: shape
210
+ inputSchema: shape,
211
+ annotations: {
212
+ title: name,
213
+ readOnlyHint: hints.readOnly ?? false,
214
+ destructiveHint: hints.destructive ?? false,
215
+ idempotentHint: hints.idempotent ?? false,
216
+ openWorldHint: true
217
+ }
201
218
  }, (async (args) => {
202
219
  try {
203
220
  return jsonText(await handler(args));
@@ -215,7 +232,7 @@ async function runMcpServer(options = {}) {
215
232
  openWorldHint: false
216
233
  }
217
234
  }, async () => jsonText(getStartedText()));
218
- tool("whoami", "Show the authenticated identity, its role, and accessible orgs.", {}, async () => {
235
+ tool("whoami", "Show the authenticated identity, its role, and accessible orgs.", ro, {}, async () => {
219
236
  const ctx = getCtx();
220
237
  if (isTokenAuth(ctx) && ctx.auth.type === "bearer") {
221
238
  const { tokenId } = await parseServiceToken(ctx.auth.token);
@@ -236,13 +253,13 @@ async function runMcpServer(options = {}) {
236
253
  ...await ctx.client.me()
237
254
  };
238
255
  });
239
- tool("list_orgs", "List organizations the caller can access.", {}, async () => (await getCtx().client.listOrgs()).orgs);
240
- tool("list_apps", "List applications in an organization.", { org: z.string().optional() }, async ({ org }) => {
256
+ tool("list_orgs", "List organizations the caller can access.", ro, {}, async () => (await getCtx().client.listOrgs()).orgs);
257
+ tool("list_apps", "List applications in an organization.", ro, { org: z.string().optional() }, async ({ org }) => {
241
258
  const ctx = getCtx();
242
259
  const orgRef = await resolveOrg(ctx, org);
243
260
  return (await ctx.client.listApps(orgRef.id)).apps;
244
261
  });
245
- tool("list_envs", "List environments of an application.", {
262
+ tool("list_envs", "List environments of an application.", ro, {
246
263
  org: z.string().optional(),
247
264
  app: z.string()
248
265
  }, async ({ org, app }) => {
@@ -253,7 +270,7 @@ async function runMcpServer(options = {}) {
253
270
  if (!appRow) throw new Error(`no app "${app}" in ${orgRef.slug}`);
254
271
  return (await ctx.client.listEnvs(orgRef.id, appRow.id)).environments;
255
272
  });
256
- tool("list_branches", "List ephemeral branch configs in an application (optionally just one environment's).", {
273
+ tool("list_branches", "List ephemeral branch configs in an application (optionally just one environment's).", ro, {
257
274
  org: z.string().optional(),
258
275
  app: z.string(),
259
276
  env: z.string().optional()
@@ -271,12 +288,12 @@ async function runMcpServer(options = {}) {
271
288
  });
272
289
  return (await ctx.client.listBranches(parent.orgId, parent.envId)).branches;
273
290
  });
274
- tool("list_groups", "List shared groups (reusable secret bags) in an organization.", { org: z.string().optional() }, async ({ org }) => {
291
+ tool("list_groups", "List shared groups (reusable secret bags) in an organization.", ro, { org: z.string().optional() }, async ({ org }) => {
275
292
  const ctx = getCtx();
276
293
  const orgRef = await resolveOrg(ctx, org);
277
294
  return (await ctx.client.listGroups(orgRef.id)).groups;
278
295
  });
279
- tool("list_group_envs", "List a group's environments (per-slug value sets).", {
296
+ tool("list_group_envs", "List a group's environments (per-slug value sets).", ro, {
280
297
  org: z.string().optional(),
281
298
  group: z.string()
282
299
  }, async ({ org, group }) => {
@@ -287,7 +304,7 @@ async function runMcpServer(options = {}) {
287
304
  });
288
305
  return (await ctx.client.listGroupEnvs(g.orgId, g.id)).environments;
289
306
  });
290
- tool("list_env_groups", "List the groups composed into an application environment (precedence order).", {
307
+ tool("list_env_groups", "List the groups composed into an application environment (precedence order).", ro, {
291
308
  org: z.string().optional(),
292
309
  app: z.string(),
293
310
  env: z.string()
@@ -300,17 +317,17 @@ async function runMcpServer(options = {}) {
300
317
  });
301
318
  return (await ctx.client.listEnvGroups(target.orgId, target.envId)).groups;
302
319
  });
303
- tool("list_members", "List organization members and their public keys (for granting access).", { org: z.string().optional() }, async ({ org }) => {
320
+ tool("list_members", "List organization members and their public keys (for granting access).", ro, { org: z.string().optional() }, async ({ org }) => {
304
321
  const ctx = getCtx();
305
322
  const orgRef = await resolveOrg(ctx, org);
306
323
  return (await ctx.client.listMembers(orgRef.id)).members;
307
324
  });
308
- tool("kms_list_keys", "List managed KMS keys the caller can see (metadata only).", { org: z.string().optional() }, async ({ org }) => {
325
+ tool("kms_list_keys", "List managed KMS keys the caller can see (metadata only).", ro, { org: z.string().optional() }, async ({ org }) => {
309
326
  const ctx = getCtx();
310
327
  const orgRef = await resolveOrg(ctx, org);
311
328
  return (await ctx.client.listKmsKeys(orgRef.id)).keys;
312
329
  });
313
- tool("kms_create_key", "Create an org-scoped managed key. Material is generated locally and wrapped to each grantee (self plus any listed users/tokens); the server never sees it. Use the CLI for app/group-scoped keys.", {
330
+ tool("kms_create_key", "Create an org-scoped managed key. Material is generated locally and wrapped to each grantee (self plus any listed users/tokens); the server never sees it. Use the CLI for app/group-scoped keys.", { idempotent: false }, {
314
331
  org: z.string().optional(),
315
332
  name: z.string(),
316
333
  purpose: z.enum(["encrypt", "sign"]),
@@ -351,7 +368,7 @@ async function runMcpServer(options = {}) {
351
368
  });
352
369
  return key;
353
370
  });
354
- tool("kms_grant", "Grant a principal (user email or token id) use of a key's current version.", {
371
+ tool("kms_grant", "Grant a principal (user email or token id) use of a key's current version.", { idempotent: true }, {
355
372
  org: z.string().optional(),
356
373
  key: z.string(),
357
374
  user: z.string().optional(),
@@ -376,7 +393,7 @@ async function runMcpServer(options = {}) {
376
393
  key: k.name
377
394
  };
378
395
  });
379
- tool("kms_encrypt", "Encrypt a value under a managed encrypt key; returns a ce1 ciphertext blob. `context` (if given) is bound as AAD and must be supplied identically to decrypt.", {
396
+ tool("kms_encrypt", "Encrypt a value under a managed encrypt key; returns a ce1 ciphertext blob. `context` (if given) is bound as AAD and must be supplied identically to decrypt.", { readOnly: true }, {
380
397
  org: z.string().optional(),
381
398
  key: z.string(),
382
399
  plaintext: z.string(),
@@ -393,7 +410,7 @@ async function runMcpServer(options = {}) {
393
410
  version: currentVersion
394
411
  }, plaintext, context ?? "") };
395
412
  });
396
- tool("kms_decrypt", "Decrypt a ce1 blob. Supply the same `context` used to encrypt.", {
413
+ tool("kms_decrypt", "Decrypt a ce1 blob. Supply the same `context` used to encrypt.", ro, {
397
414
  org: z.string().optional(),
398
415
  key: z.string(),
399
416
  ciphertext: z.string(),
@@ -407,7 +424,7 @@ async function runMcpServer(options = {}) {
407
424
  const { material } = await kmsRecoverMaterial(ctx, orgRef.id, k.id, ref.version);
408
425
  return { plaintext: await kmsDecrypt(material, ciphertext, context ?? "") };
409
426
  });
410
- tool("kms_generate_data_key", "Generate a data key under a managed encrypt key (envelope encryption). Returns the plaintext key (base64) and its wrapped form to store.", {
427
+ tool("kms_generate_data_key", "Generate a data key under a managed encrypt key (envelope encryption). Returns the plaintext key (base64) and its wrapped form to store.", { readOnly: true }, {
411
428
  org: z.string().optional(),
412
429
  key: z.string()
413
430
  }, async ({ org, key }) => {
@@ -426,7 +443,7 @@ async function runMcpServer(options = {}) {
426
443
  wrapped: dk.wrapped
427
444
  };
428
445
  });
429
- tool("kms_sign", "Sign a message with a managed signing key; returns an sg1 signature blob.", {
446
+ tool("kms_sign", "Sign a message with a managed signing key; returns an sg1 signature blob.", { readOnly: true }, {
430
447
  org: z.string().optional(),
431
448
  key: z.string(),
432
449
  message: z.string()
@@ -442,7 +459,7 @@ async function runMcpServer(options = {}) {
442
459
  version: currentVersion
443
460
  }, message) };
444
461
  });
445
- tool("kms_verify", "Verify an sg1 signature over a message using a signing key's published public key (no grant needed).", {
462
+ tool("kms_verify", "Verify an sg1 signature over a message using a signing key's published public key (no grant needed).", ro, {
446
463
  org: z.string().optional(),
447
464
  key: z.string(),
448
465
  signature: z.string(),
@@ -457,7 +474,7 @@ async function runMcpServer(options = {}) {
457
474
  if (!pub) throw new Error(`no published public key for version ${ref.version}`);
458
475
  return { valid: await verifyMessage(await importVerifyingKey(pub), signature, message) };
459
476
  });
460
- tool("list_secrets", "List secret names + versions in an environment (never values).", targetShape, async (o) => {
477
+ tool("list_secrets", "List secret names + versions in an environment (never values).", ro, targetShape, async (o) => {
461
478
  const ctx = getCtx();
462
479
  const { orgId, envId } = await resolveTargetEnv(ctx, o);
463
480
  const { secrets } = await ctx.client.listSecrets(orgId, envId);
@@ -467,12 +484,12 @@ async function runMcpServer(options = {}) {
467
484
  updatedAt: s.updatedAt
468
485
  }));
469
486
  });
470
- tool("list_tokens", "List an organization's service tokens (never the secret token strings).", { org: z.string().optional() }, async ({ org }) => {
487
+ tool("list_tokens", "List an organization's service tokens (never the secret token strings).", ro, { org: z.string().optional() }, async ({ org }) => {
471
488
  const ctx = getCtx();
472
489
  const orgRef = await resolveOrg(ctx, org);
473
490
  return (await ctx.client.listTokens(orgRef.id)).tokens;
474
491
  });
475
- tool("audit", "Read the organization's audit trail (most recent first).", {
492
+ tool("audit", "Read the organization's audit trail (most recent first).", ro, {
476
493
  org: z.string().optional(),
477
494
  limit: z.number().int().min(1).max(200).optional(),
478
495
  action: z.string().optional().describe("filter by action, e.g. secret.updated")
@@ -484,14 +501,14 @@ async function runMcpServer(options = {}) {
484
501
  action
485
502
  })).entries;
486
503
  });
487
- tool("create_org", "Create an organization. Requires a user session — service tokens cannot own a Stytch org.", {
504
+ tool("create_org", "Create an organization. Requires a user session — service tokens cannot own a Stytch org.", { idempotent: false }, {
488
505
  name: z.string(),
489
506
  slug: z.string()
490
507
  }, async ({ name, slug }) => (await getCtx().client.createOrg({
491
508
  name,
492
509
  slug
493
510
  })).org);
494
- tool("create_app", "Create an application in an organization.", {
511
+ tool("create_app", "Create an application in an organization.", { idempotent: false }, {
495
512
  org: z.string().optional(),
496
513
  name: z.string(),
497
514
  slug: z.string()
@@ -503,7 +520,7 @@ async function runMcpServer(options = {}) {
503
520
  slug
504
521
  })).app;
505
522
  });
506
- tool("create_group", "Create a shared group (reusable secret bag) in an organization.", {
523
+ tool("create_group", "Create a shared group (reusable secret bag) in an organization.", { idempotent: false }, {
507
524
  org: z.string().optional(),
508
525
  name: z.string(),
509
526
  slug: z.string()
@@ -515,7 +532,7 @@ async function runMcpServer(options = {}) {
515
532
  slug
516
533
  })).group;
517
534
  });
518
- tool("create_env", "Create an application environment. Generates the data key locally and grants it to the caller.", {
535
+ tool("create_env", "Create an application environment. Generates the data key locally and grants it to the caller.", { idempotent: false }, {
519
536
  org: z.string().optional(),
520
537
  app: z.string(),
521
538
  name: z.string(),
@@ -533,7 +550,7 @@ async function runMcpServer(options = {}) {
533
550
  wrappedDek
534
551
  })).environment;
535
552
  });
536
- tool("create_branch", "Fork an environment into an ephemeral branch (a per-PR / preview config). The branch inherits the parent's secrets by layering at read time — nothing is copied or re-encrypted — and holds only the values you override on it. Generates the branch's data key locally, grants it to the caller, and shares it with the parent's other readers.", {
553
+ tool("create_branch", "Fork an environment into an ephemeral branch (a per-PR / preview config). The branch inherits the parent's secrets by layering at read time — nothing is copied or re-encrypted — and holds only the values you override on it. Generates the branch's data key locally, grants it to the caller, and shares it with the parent's other readers.", { idempotent: false }, {
537
554
  org: z.string().optional(),
538
555
  app: z.string(),
539
556
  from: z.string().describe("the environment to branch"),
@@ -568,7 +585,7 @@ async function runMcpServer(options = {}) {
568
585
  grants
569
586
  })).branch;
570
587
  });
571
- tool("delete_branch", "Tear down a branch config and every value it overrode. The parent environment is untouched.", {
588
+ tool("delete_branch", "Tear down a branch config and every value it overrode. The parent environment is untouched.", destructive, {
572
589
  org: z.string().optional(),
573
590
  app: z.string(),
574
591
  branch: z.string()
@@ -582,7 +599,7 @@ async function runMcpServer(options = {}) {
582
599
  await ctx.client.deleteBranch(appRef.orgId, target.id);
583
600
  return { deleted: target.slug };
584
601
  });
585
- tool("create_group_env", "Create a group environment. Generates the data key locally and grants it to the caller.", {
602
+ tool("create_group_env", "Create a group environment. Generates the data key locally and grants it to the caller.", { idempotent: false }, {
586
603
  org: z.string().optional(),
587
604
  group: z.string(),
588
605
  name: z.string(),
@@ -600,7 +617,7 @@ async function runMcpServer(options = {}) {
600
617
  wrappedDek
601
618
  })).environment;
602
619
  });
603
- tool("compose_group", "Compose a group into an application environment (higher position wins on name clashes).", {
620
+ tool("compose_group", "Compose a group into an application environment (higher position wins on name clashes).", { idempotent: true }, {
604
621
  org: z.string().optional(),
605
622
  app: z.string(),
606
623
  env: z.string(),
@@ -622,7 +639,7 @@ async function runMcpServer(options = {}) {
622
639
  position
623
640
  })).group;
624
641
  });
625
- tool("uncompose_group", "Remove a composed group from an application environment.", {
642
+ tool("uncompose_group", "Remove a composed group from an application environment.", { idempotent: true }, {
626
643
  org: z.string().optional(),
627
644
  app: z.string(),
628
645
  env: z.string(),
@@ -641,7 +658,7 @@ async function runMcpServer(options = {}) {
641
658
  await ctx.client.unlinkEnvGroup(target.orgId, target.envId, g.id);
642
659
  return { ok: true };
643
660
  });
644
- tool("set_secret", "Encrypt a value locally and store it in an environment. A value may reference another secret as ${OTHER_SECRET}: the reference is stored literally and expanded whenever the secret is read, so it tracks the referenced value. Write $${OTHER_SECRET} for a literal.", {
661
+ tool("set_secret", "Encrypt a value locally and store it in an environment. A value may reference another secret as ${OTHER_SECRET}: the reference is stored literally and expanded whenever the secret is read, so it tracks the referenced value. Write $${OTHER_SECRET} for a literal.", { idempotent: false }, {
645
662
  ...targetShape,
646
663
  name: z.string(),
647
664
  value: z.string()
@@ -655,7 +672,7 @@ async function runMcpServer(options = {}) {
655
672
  name: o.name
656
673
  };
657
674
  });
658
- tool("get_secret", "Return one secret. By default only reports presence + version; pass reveal:true to decrypt the plaintext into this response (avoid unless the value is actually needed — prefer run_command). A revealed current value has its ${OTHER_SECRET} references expanded against this environment's own secrets; pass raw:true for the stored text instead. Pass `version` to read an earlier version instead of the current one (always as stored, never expanded).", {
675
+ tool("get_secret", "Return one secret. By default only reports presence + version; pass reveal:true to decrypt the plaintext into this response (avoid unless the value is actually needed — prefer run_command). A revealed current value has its ${OTHER_SECRET} references expanded against this environment's own secrets; pass raw:true for the stored text instead. Pass `version` to read an earlier version instead of the current one (always as stored, never expanded).", ro, {
659
676
  ...targetShape,
660
677
  name: z.string(),
661
678
  reveal: z.boolean().optional(),
@@ -692,7 +709,7 @@ async function runMcpServer(options = {}) {
692
709
  revealed: true
693
710
  };
694
711
  });
695
- tool("list_secret_versions", "List a secret's version history: who wrote each version, when, and which ones were restores. Never returns values — pair it with restore_secret to roll back, or get_secret(version, reveal:true) to inspect one.", {
712
+ tool("list_secret_versions", "List a secret's version history: who wrote each version, when, and which ones were restores. Never returns values — pair it with restore_secret to roll back, or get_secret(version, reveal:true) to inspect one.", ro, {
696
713
  ...targetShape,
697
714
  name: z.string(),
698
715
  limit: z.number().int().min(1).max(200).optional().describe("default 20")
@@ -710,7 +727,7 @@ async function runMcpServer(options = {}) {
710
727
  }))
711
728
  };
712
729
  });
713
- tool("restore_secret", "Roll a secret back to an earlier version. The stored ciphertext is replayed as a NEW version (history is append-only, nothing is overwritten). Keyless — no decryption happens, so this works even without a key.", {
730
+ tool("restore_secret", "Roll a secret back to an earlier version. The stored ciphertext is replayed as a NEW version (history is append-only, nothing is overwritten). Keyless — no decryption happens, so this works even without a key.", { idempotent: false }, {
714
731
  ...targetShape,
715
732
  name: z.string(),
716
733
  version: z.number().int().positive()
@@ -725,7 +742,7 @@ async function runMcpServer(options = {}) {
725
742
  version: secret.version
726
743
  };
727
744
  });
728
- tool("delete_secret", "Delete a secret from an environment.", {
745
+ tool("delete_secret", "Delete a secret from an environment.", destructive, {
729
746
  ...targetShape,
730
747
  name: z.string()
731
748
  }, async (o) => {
@@ -738,6 +755,9 @@ async function runMcpServer(options = {}) {
738
755
  };
739
756
  });
740
757
  tool("run_command", "Run a command with the resolved secrets injected as environment variables, and return its exit code + captured output. Secret VALUES are never returned — this is the preferred way to use secrets. process env > .env > app env > groups.", {
758
+ destructive: true,
759
+ idempotent: false
760
+ }, {
741
761
  command: z.string().describe("executable to run"),
742
762
  args: z.array(z.string()).optional(),
743
763
  org: z.string().optional(),
@@ -760,7 +780,7 @@ async function runMcpServer(options = {}) {
760
780
  injectedVarCount: Object.keys(values).length
761
781
  };
762
782
  });
763
- tool("export_env", "Write the resolved secrets to a dotenv file on disk and return the variable names written (never the values). Use to materialize a .env for local tooling.", {
783
+ tool("export_env", "Write the resolved secrets to a dotenv file on disk and return the variable names written (never the values). Use to materialize a .env for local tooling.", destructive, {
764
784
  file: z.string().describe("path to write, e.g. .env"),
765
785
  org: z.string().optional(),
766
786
  app: z.string().optional(),
@@ -779,7 +799,7 @@ async function runMcpServer(options = {}) {
779
799
  names: Object.keys(values).sort()
780
800
  };
781
801
  });
782
- tool("create_token", "Mint a service token, printed once. Runtime tokens bind to one app environment (auto-granted its keys, so a command/agent can decrypt it). Pass admin:true for an org-scoped provisioning token (create apps/groups/envs, grant, mint tokens) — admin tokens need no env binding.", {
802
+ tool("create_token", "Mint a service token, printed once. Runtime tokens bind to one app environment (auto-granted its keys, so a command/agent can decrypt it). Pass admin:true for an org-scoped provisioning token (create apps/groups/envs, grant, mint tokens) — admin tokens need no env binding.", { idempotent: false }, {
783
803
  name: z.string().describe("display name, e.g. ci-deploy or agent-session"),
784
804
  org: z.string().optional(),
785
805
  app: z.string().optional().describe("bind to this app (runtime tokens)"),
@@ -830,7 +850,7 @@ async function runMcpServer(options = {}) {
830
850
  note: "save this now — the secret token string is not stored and cannot be retrieved"
831
851
  };
832
852
  });
833
- tool("revoke_token", "Revoke a service token by id.", {
853
+ tool("revoke_token", "Revoke a service token by id.", destructive, {
834
854
  org: z.string().optional(),
835
855
  tokenId: z.string()
836
856
  }, async ({ org, tokenId }) => {
@@ -842,7 +862,7 @@ async function runMcpServer(options = {}) {
842
862
  tokenId
843
863
  };
844
864
  });
845
- tool("grant_env", "Grant a member (by email) or service token (by id) access to an environment's data key. Re-wraps the DEK to the grantee — the caller must already hold the key.", {
865
+ tool("grant_env", "Grant a member (by email) or service token (by id) access to an environment's data key. Re-wraps the DEK to the grantee — the caller must already hold the key.", { idempotent: true }, {
846
866
  ...targetShape,
847
867
  user: z.string().optional().describe("org member email"),
848
868
  token: z.string().optional().describe("service token id (skt_…)")
@@ -887,12 +907,12 @@ async function runMcpServer(options = {}) {
887
907
  principalId
888
908
  };
889
909
  });
890
- tool("list_pg_targets", "List registered Postgres provisioning targets for temporary credentials.", { org: z.string().optional() }, async ({ org }) => {
910
+ tool("list_pg_targets", "List registered Postgres provisioning targets for temporary credentials.", ro, { org: z.string().optional() }, async ({ org }) => {
891
911
  const ctx = getCtx();
892
912
  const orgRef = await resolveOrg(ctx, org);
893
913
  return (await ctx.client.listLeaseTargets(orgRef.id)).targets;
894
914
  });
895
- tool("create_pg_lease", "Mint a short-lived Postgres credential against a target and return a ready-to-use connection URL. The password is generated on THIS machine and only its SCRAM verifier is sent to the API — the plaintext never reaches seekrit or Postgres at rest. The role auto-expires; revoke early with revoke_pg_lease.", {
915
+ tool("create_pg_lease", "Mint a short-lived Postgres credential against a target and return a ready-to-use connection URL. The password is generated on THIS machine and only its SCRAM verifier is sent to the API — the plaintext never reaches seekrit or Postgres at rest. The role auto-expires; revoke early with revoke_pg_lease.", { idempotent: false }, {
896
916
  org: z.string().optional(),
897
917
  target: z.string().describe("target id or name"),
898
918
  role: z.string().optional().describe("role name to create (default: random tmp_ name)"),
@@ -921,12 +941,12 @@ async function runMcpServer(options = {}) {
921
941
  note: "short-lived credential; it auto-expires and the plaintext is not stored anywhere"
922
942
  };
923
943
  });
924
- tool("list_pg_leases", "List Postgres leases (the ledger — never secret material).", { org: z.string().optional() }, async ({ org }) => {
944
+ tool("list_pg_leases", "List Postgres leases (the ledger — never secret material).", ro, { org: z.string().optional() }, async ({ org }) => {
925
945
  const ctx = getCtx();
926
946
  const orgRef = await resolveOrg(ctx, org);
927
947
  return (await ctx.client.listLeases(orgRef.id)).leases;
928
948
  });
929
- tool("revoke_pg_lease", "Revoke a Postgres lease now (drops the role immediately).", {
949
+ tool("revoke_pg_lease", "Revoke a Postgres lease now (drops the role immediately).", destructive, {
930
950
  org: z.string().optional(),
931
951
  leaseId: z.string()
932
952
  }, async ({ org, leaseId }) => {
@@ -938,12 +958,12 @@ async function runMcpServer(options = {}) {
938
958
  leaseId
939
959
  };
940
960
  });
941
- tool("list_mysql_targets", "List registered MySQL/MariaDB provisioning targets for temporary credentials.", { org: z.string().optional() }, async ({ org }) => {
961
+ tool("list_mysql_targets", "List registered MySQL/MariaDB provisioning targets for temporary credentials.", ro, { org: z.string().optional() }, async ({ org }) => {
942
962
  const ctx = getCtx();
943
963
  const orgRef = await resolveOrg(ctx, org);
944
964
  return (await ctx.client.listLeaseTargets(orgRef.id)).targets.filter((t) => t.provider === "mysql");
945
965
  });
946
- tool("create_mysql_lease", "Mint a short-lived MySQL/MariaDB credential against a target and return a ready-to-use connection URL. The password is generated on THIS machine and only its mysql_native_password hash is sent to the API — the plaintext never reaches seekrit or MySQL at rest. The user auto-expires; revoke early with revoke_mysql_lease.", {
966
+ tool("create_mysql_lease", "Mint a short-lived MySQL/MariaDB credential against a target and return a ready-to-use connection URL. The password is generated on THIS machine and only its mysql_native_password hash is sent to the API — the plaintext never reaches seekrit or MySQL at rest. The user auto-expires; revoke early with revoke_mysql_lease.", { idempotent: false }, {
947
967
  org: z.string().optional(),
948
968
  target: z.string().describe("target id or name"),
949
969
  user: z.string().optional().describe("user name to create (default: random tmp_ name)"),
@@ -973,12 +993,12 @@ async function runMcpServer(options = {}) {
973
993
  note: "short-lived credential; it auto-expires and the plaintext is not stored anywhere"
974
994
  };
975
995
  });
976
- tool("list_mysql_leases", "List MySQL/MariaDB leases (the ledger — never secret material).", { org: z.string().optional() }, async ({ org }) => {
996
+ tool("list_mysql_leases", "List MySQL/MariaDB leases (the ledger — never secret material).", ro, { org: z.string().optional() }, async ({ org }) => {
977
997
  const ctx = getCtx();
978
998
  const orgRef = await resolveOrg(ctx, org);
979
999
  return (await ctx.client.listLeases(orgRef.id)).leases.filter((l) => l.provider === "mysql");
980
1000
  });
981
- tool("revoke_mysql_lease", "Revoke a MySQL/MariaDB lease now (drops the user immediately).", {
1001
+ tool("revoke_mysql_lease", "Revoke a MySQL/MariaDB lease now (drops the user immediately).", destructive, {
982
1002
  org: z.string().optional(),
983
1003
  leaseId: z.string()
984
1004
  }, async ({ org, leaseId }) => {
@@ -990,7 +1010,7 @@ async function runMcpServer(options = {}) {
990
1010
  leaseId
991
1011
  };
992
1012
  });
993
- tool("configure_project", "Link a directory to an org/app by writing seekrit.json (like `seekrit init`). The environment is chosen by the service token at runtime.", {
1013
+ tool("configure_project", "Link a directory to an org/app by writing seekrit.json (like `seekrit init`). The environment is chosen by the service token at runtime.", destructive, {
994
1014
  org: z.string(),
995
1015
  app: z.string(),
996
1016
  dir: z.string().optional()
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@seekrit/cli",
3
- "version": "0.31.0",
3
+ "version": "0.32.0",
4
4
  "description": "End-to-end encrypted secrets manager CLI — inject decrypted secrets into any command.",
5
5
  "type": "module",
6
6
  "publishConfig": {
@@ -27,8 +27,8 @@
27
27
  "@types/node": "^26.1.0",
28
28
  "tsdown": "^0.22.3",
29
29
  "vitest": "^4.1.9",
30
- "@seekrit/core": "0.0.1",
31
30
  "@seekrit/api-client": "0.0.1",
31
+ "@seekrit/core": "0.0.1",
32
32
  "@seekrit/crypto": "0.0.1"
33
33
  },
34
34
  "scripts": {