@envseal/mcp-server 0.1.3 → 0.1.4

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/bin.js CHANGED
@@ -4,7 +4,7 @@ import { Broker } from '@envseal/core';
4
4
  import { selectPrompter } from '@envseal/prompters';
5
5
  import { createServer } from './index.js';
6
6
  import { parseArgv, resolveProjectRoot, USAGE, VERSION } from './cli-args.js';
7
- import { createProbeApproval, createUseConfirm } from './confirm.js';
7
+ import { createProbeApproval, createRevokeConfirm, createUseConfirm } from './confirm.js';
8
8
  import { createRefusingPrompter, createStubPrompter, isStubOutcome, } from './test-prompter.js';
9
9
  // NOTE: MCP protocol owns stdout. All diagnostics MUST go to stderr.
10
10
  // Any output to stdout corrupts the JSON-RPC stream.
@@ -57,6 +57,7 @@ async function main() {
57
57
  // cannot ask anyone, and exec.ts turns that absence into "the user
58
58
  // denied the confirmation" for a user who was never asked.
59
59
  onConfirm: createUseConfirm(surface),
60
+ onRevokeConfirm: createRevokeConfirm(surface),
60
61
  // PLAN.md §6.4: consent before a credential goes to a host the registry
61
62
  // does not allowlist. Supplied by no binding before this.
62
63
  onApprovalNeeded: createProbeApproval(surface),
@@ -2,8 +2,8 @@
2
2
  * Argument handling for the `envseal-mcp` binary, kept out of bin.ts so it can
3
3
  * be tested without importing a module whose side effect is starting a server.
4
4
  */
5
- export declare const VERSION = "0.1.3";
6
- export declare const USAGE = "envseal-mcp 0.1.3\n\nServes the SEP/1 tools to an MCP host over stdio JSON-RPC.\n\nUsage: envseal-mcp [--project <dir>]\n\nOptions:\n --project <dir> Project root to broker secrets for. Default: search\n upward from the current directory for env.schema.jsonc,\n .git or package.json. If none is found, this server\n refuses to start rather than create .envseal/ in a\n directory that is not a project.\n --help, -h Show this help and exit.\n --version, -v Print the version and exit.\n\nTransport: stdio only. --http and --port were removed; they were parsed and\nthen ignored, and no HTTP or SSE transport was ever implemented. For an HTTP\nsurface use @envseal/http-server, which speaks REST + OpenAPI on loopback --\nthat is a different protocol, not MCP over HTTP.\n";
5
+ export declare const VERSION = "0.1.4";
6
+ export declare const USAGE = "envseal-mcp 0.1.4\n\nServes the SEP/1 tools to an MCP host over stdio JSON-RPC.\n\nUsage: envseal-mcp [--project <dir>]\n\nOptions:\n --project <dir> Project root to broker secrets for. Default: search\n upward from the current directory for env.schema.jsonc,\n .git or package.json. If none is found, this server\n refuses to start rather than create .envseal/ in a\n directory that is not a project.\n --help, -h Show this help and exit.\n --version, -v Print the version and exit.\n\nTransport: stdio only. --http and --port were removed; they were parsed and\nthen ignored, and no HTTP or SSE transport was ever implemented. For an HTTP\nsurface use @envseal/http-server, which speaks REST + OpenAPI on loopback --\nthat is a different protocol, not MCP over HTTP.\n";
7
7
  export type ParsedArgv = {
8
8
  kind: 'help';
9
9
  } | {
package/dist/cli-args.js CHANGED
@@ -5,7 +5,7 @@ import { findProjectRoot } from '@envseal/core';
5
5
  * Argument handling for the `envseal-mcp` binary, kept out of bin.ts so it can
6
6
  * be tested without importing a module whose side effect is starting a server.
7
7
  */
8
- export const VERSION = '0.1.3';
8
+ export const VERSION = '0.1.4';
9
9
  export const USAGE = `envseal-mcp ${VERSION}
10
10
 
11
11
  Serves the SEP/1 tools to an MCP host over stdio JSON-RPC.
package/dist/confirm.d.ts CHANGED
@@ -26,6 +26,8 @@ import type { Prompter } from '@envseal/prompters';
26
26
  */
27
27
  /** Value-entry key name carrying the `env_use` confirmation. */
28
28
  export declare const CONFIRM_KEY_USE = "APPROVE";
29
+ /** Value-entry key name carrying the `env_revoke` confirmation. */
30
+ export declare const CONFIRM_KEY_REVOKE = "APPROVE_REVOKE";
29
31
  /** Value-entry key name carrying the `env_verify` probe-consent question. */
30
32
  export declare const CONFIRM_KEY_PROBE = "APPROVE_PROBE";
31
33
  export interface ConfirmSurface {
@@ -46,6 +48,7 @@ export declare function useConfirmationBody(info: {
46
48
  networkEgress: boolean;
47
49
  target?: TargetInfo;
48
50
  }, projectRoot: string): string;
51
+ export declare function revokeConfirmationBody(keys: string[], projectRoot: string): string;
49
52
  export declare function probeConfirmationBody(entry: ManifestEntry): string | null;
50
53
  /**
51
54
  * `onConfirm` for the Broker: gates `env_use`.
@@ -56,6 +59,13 @@ export declare function probeConfirmationBody(entry: ManifestEntry): string | nu
56
59
  * or for a silence — the defect this project already fixed once in the CLI.
57
60
  */
58
61
  export declare function createUseConfirm(surface: ConfirmSurface): NonNullable<BrokerOptions['onConfirm']>;
62
+ /**
63
+ * `onRevokeConfirm` for the Broker: gates `env_revoke`.
64
+ *
65
+ * Same ask/outcome mapping as createUseConfirm. Throws rather than returning
66
+ * false when no human could be asked or when the ask expired unanswered.
67
+ */
68
+ export declare function createRevokeConfirm(surface: ConfirmSurface): NonNullable<BrokerOptions['onRevokeConfirm']>;
59
69
  /**
60
70
  * `onApprovalNeeded` for the Broker: PLAN.md §6.4 probe consent for
61
71
  * `env_verify` against a host that is not registry-allowlisted.
package/dist/confirm.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { randomBytes } from 'node:crypto';
2
- import { useConfirmationBody as sharedUseConfirmationBody, escapeForDisplay as coreEscapeForDisplay, displayArg as coreDisplayArg, } from '@envseal/core';
2
+ import { useConfirmationBody as sharedUseConfirmationBody, revokeConfirmationBody as sharedRevokeConfirmationBody, escapeForDisplay as coreEscapeForDisplay, displayArg as coreDisplayArg, } from '@envseal/core';
3
3
  import { SepError, zero } from '@envseal/protocol';
4
4
  import { makeDisplayNonce } from '@envseal/prompters';
5
5
  /**
@@ -27,6 +27,8 @@ import { makeDisplayNonce } from '@envseal/prompters';
27
27
  */
28
28
  /** Value-entry key name carrying the `env_use` confirmation. */
29
29
  export const CONFIRM_KEY_USE = 'APPROVE';
30
+ /** Value-entry key name carrying the `env_revoke` confirmation. */
31
+ export const CONFIRM_KEY_REVOKE = 'APPROVE_REVOKE';
30
32
  /** Value-entry key name carrying the `env_verify` probe-consent question. */
31
33
  export const CONFIRM_KEY_PROBE = 'APPROVE_PROBE';
32
34
  const DEFAULT_TIMEOUT_MS = 120_000;
@@ -46,6 +48,9 @@ export const displayArg = coreDisplayArg;
46
48
  export function useConfirmationBody(info, projectRoot) {
47
49
  return sharedUseConfirmationBody(info, projectRoot);
48
50
  }
51
+ export function revokeConfirmationBody(keys, projectRoot) {
52
+ return sharedRevokeConfirmationBody(keys, projectRoot);
53
+ }
49
54
  export function probeConfirmationBody(entry) {
50
55
  const probe = entry.verify;
51
56
  if (!probe) {
@@ -160,6 +165,50 @@ export function createUseConfirm(surface) {
160
165
  }
161
166
  };
162
167
  }
168
+ /**
169
+ * `onRevokeConfirm` for the Broker: gates `env_revoke`.
170
+ *
171
+ * Same ask/outcome mapping as createUseConfirm. Throws rather than returning
172
+ * false when no human could be asked or when the ask expired unanswered.
173
+ */
174
+ export function createRevokeConfirm(surface) {
175
+ return async (keys) => {
176
+ const outcome = await ask(surface, CONFIRM_KEY_REVOKE, 'Approve removing stored credentials? Nothing has been removed yet.', revokeConfirmationBody(keys, surface.projectRoot));
177
+ switch (outcome) {
178
+ case 'approved':
179
+ return true;
180
+ case 'denied':
181
+ return false;
182
+ case 'timed-out':
183
+ throw new SepError({
184
+ code: 'SEP_TICKET_EXPIRED',
185
+ userMessage: 'The env_revoke confirmation closed after its timeout with nobody answering it. Nothing was ' +
186
+ 'removed. This is not a denial: ask the user to approve it, then call env_revoke again.',
187
+ });
188
+ case 'no-surface':
189
+ throw new SepError({
190
+ code: 'SEP_NO_INTERACTIVE_SURFACE',
191
+ userMessage: 'env_revoke needs the user to confirm before stored credentials are removed, ' +
192
+ 'but there is no interactive surface here to ask on (this is what CI looks like to envseal). ' +
193
+ 'Nothing was removed. ' +
194
+ 'There is no flag or environment variable that skips this prompt in this binding: the request ' +
195
+ 'came from a model, and the confirmation is the only control on it. ' +
196
+ 'Run `envseal revoke` yourself in a session that has a browser or a terminal.',
197
+ });
198
+ case 'busy':
199
+ throw new SepError({
200
+ code: 'SEP_RATE_LIMITED',
201
+ userMessage: 'Another envseal confirmation is already open. Answer that one first, then call env_revoke again.',
202
+ });
203
+ case 'too-large':
204
+ throw new SepError({
205
+ code: 'SEP_FORMAT_INVALID',
206
+ userMessage: 'This revoke request is too large to display in a confirmation dialog, and envseal will not ask ' +
207
+ 'anyone to approve something it cannot show them. Revoke fewer keys at once.',
208
+ });
209
+ }
210
+ };
211
+ }
163
212
  /**
164
213
  * `onApprovalNeeded` for the Broker: PLAN.md §6.4 probe consent for
165
214
  * `env_verify` against a host that is not registry-allowlisted.
@@ -172,7 +221,7 @@ export function createUseConfirm(surface) {
172
221
  */
173
222
  export function createProbeApproval(surface) {
174
223
  return async (entry) => {
175
- const outcome = await ask(surface, CONFIRM_KEY_PROBE, `Approve sending ${entry.key} to a host that is not on envseal's allowlist? Nothing has been sent yet.`, probeConfirmationBody(entry));
224
+ const outcome = await ask(surface, CONFIRM_KEY_PROBE, `Approve sending ${escapeForDisplay(entry.key)} to a host that is not on envseal's allowlist? Nothing has been sent yet.`, probeConfirmationBody(entry));
176
225
  return outcome === 'approved';
177
226
  };
178
227
  }
@@ -8,7 +8,7 @@ export declare const inputSchema: import("zod").ZodObject<{
8
8
  required: import("zod").ZodDefault<import("zod").ZodBoolean>;
9
9
  secret: import("zod").ZodDefault<import("zod").ZodBoolean>;
10
10
  format: import("zod").ZodOptional<import("zod").ZodObject<{
11
- pattern: import("zod").ZodOptional<import("zod").ZodString>;
11
+ pattern: import("zod").ZodOptional<import("zod").ZodEffects<import("zod").ZodString, string, string>>;
12
12
  minLength: import("zod").ZodOptional<import("zod").ZodNumber>;
13
13
  maxLength: import("zod").ZodOptional<import("zod").ZodNumber>;
14
14
  example: import("zod").ZodOptional<import("zod").ZodString>;
@@ -1,6 +1,6 @@
1
1
  import type { Broker } from '@envseal/core';
2
2
  export declare const name = "env_revoke";
3
- export declare const description = "Removes stored credentials. Records in the audit log and emits the provider rotation URL so you can help the user invalidate the old key.";
3
+ export declare const description = "Removes stored credentials after user confirmation. Records in the audit log and emits the provider rotation URL so you can help the user invalidate the old key.";
4
4
  export declare const inputSchema: import("zod").ZodObject<{
5
5
  keys: import("zod").ZodArray<import("zod").ZodString, "many">;
6
6
  }, "strict", import("zod").ZodTypeAny, {
@@ -1,7 +1,7 @@
1
1
  import { EnvRevokeInput, INPUT_SCHEMAS } from '@envseal/protocol';
2
2
  import { respond, respondError } from '../respond.js';
3
3
  export const name = 'env_revoke';
4
- export const description = 'Removes stored credentials. Records in the audit log and emits the provider rotation URL so you can help the user invalidate the old key.';
4
+ export const description = 'Removes stored credentials after user confirmation. Records in the audit log and emits the provider rotation URL so you can help the user invalidate the old key.';
5
5
  export const inputSchema = INPUT_SCHEMAS.env_revoke;
6
6
  export async function handler(args, broker) {
7
7
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@envseal/mcp-server",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
4
  "type": "module",
5
5
  "license": "Apache-2.0",
6
6
  "main": "./dist/index.js",
@@ -25,10 +25,10 @@
25
25
  "dependencies": {
26
26
  "@modelcontextprotocol/sdk": "^1.13.0",
27
27
  "zod": "^3.24.1",
28
- "@envseal/protocol": "0.1.3",
29
- "@envseal/core": "0.1.3",
30
- "@envseal/prompters": "0.1.3",
31
- "@envseal/registry": "0.1.3"
28
+ "@envseal/protocol": "0.1.4",
29
+ "@envseal/core": "0.1.4",
30
+ "@envseal/registry": "0.1.4",
31
+ "@envseal/prompters": "0.1.4"
32
32
  },
33
33
  "devDependencies": {
34
34
  "tsx": "^4.19.2",