@chrischall/gemini-mcp 2.3.2 → 2.3.3

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.
@@ -7,7 +7,7 @@
7
7
  },
8
8
  "metadata": {
9
9
  "description": "MCP server for Google Gemini image generation and editing — generate and edit images via the Gemini API",
10
- "version": "2.3.2"
10
+ "version": "2.3.3"
11
11
  },
12
12
  "plugins": [
13
13
  {
@@ -15,7 +15,7 @@
15
15
  "displayName": "Gemini Images",
16
16
  "source": "./",
17
17
  "description": "Generate and edit images with Google Gemini image models (Nano Banana / Nano Banana Pro) via natural language prompts",
18
- "version": "2.3.2",
18
+ "version": "2.3.3",
19
19
  "author": {
20
20
  "name": "Chris Hall"
21
21
  },
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "gemini-mcp",
3
3
  "displayName": "Gemini Images",
4
- "version": "2.3.2",
4
+ "version": "2.3.3",
5
5
  "description": "MCP server for Google Gemini image generation and editing — generate and edit images via the Gemini API",
6
6
  "author": {
7
7
  "name": "Chris Hall",
package/README.md CHANGED
@@ -26,7 +26,8 @@ Developed and maintained by AI (Claude Code).
26
26
 
27
27
  Sending a **local file** to Google (the `images` / `master_images` / `video_path` inputs, or
28
28
  `gemini_upload_file`'s `path`) and every **delete** ask for confirmation first. A client that can
29
- show a confirmation prompt (Claude Code) gets the real prompt. Elsewhere the first call does
29
+ show a confirmation prompt (Claude Code) gets the real prompt, unless `MCP_CONFIRM_ELICITATION=off`.
30
+ Elsewhere the first call does
30
31
  nothing and returns a preview (the resolved local paths with their MIME types and sizes, or the
31
32
  method/path being deleted) plus a `confirmToken`; only a repeat call with the same arguments and
32
33
  that token proceeds. The token is single-use, expires, and is bound to the exact arguments — a
@@ -35,7 +36,8 @@ changed prompt or a swapped file between the two calls is refused. Pure text pro
35
36
 
36
37
  | variable | default | |
37
38
  |---|---|---|
38
- | `MCP_CONFIRM_MODE` | `ask-user` | What a write does on a client that cannot show a confirmation prompt (claude.ai, Claude Desktop). `ask-user`: two steps — the first call does nothing and returns a preview plus a token, and the model must get your approval in chat before calling again with it. `auto`: the same two steps, but the model may use the token after reviewing the preview itself. `refuse`: writes are refused on such clients. A client that can show prompts (Claude Code) always gets the real prompt. An unrecognised value is treated as `refuse`. |
39
+ | `MCP_CONFIRM_MODE` | `ask-user` | What a write does on a client that cannot show a confirmation prompt (claude.ai, Claude Desktop). `ask-user`: two steps — the first call does nothing and returns a preview plus a token, and the model must get your approval in chat before calling again with it. `auto`: the same two steps, but the model may use the token after reviewing the preview itself. `refuse`: writes are refused on such clients. A client that can show prompts (Claude Code) always gets the real prompt, unless `MCP_CONFIRM_ELICITATION=off`. An unrecognised value is treated as `refuse`. |
40
+ | `MCP_CONFIRM_ELICITATION` | `on` | `off` never shows a confirmation prompt, so every client gets the `MCP_CONFIRM_MODE` path. Set it for a client that claims to support prompts but never shows one (the gated call hangs — opencode 2.0.x). Any other value stays `on`, with a warning on stderr. |
39
41
  | `MCP_CONFIRM_TTL_SECONDS` | `600` | How long a token stays valid. |
40
42
  | `MCP_CONFIRM_SECRET` | random per process | Signing key; set it only if tokens must survive a server restart. |
41
43
 
package/dist/bundle.js CHANGED
@@ -58852,6 +58852,15 @@ ${JSON.stringify(preview, null, 2)}`,
58852
58852
  };
58853
58853
  const response = inputResponse(ctx.mcpReq.inputResponses, requestKey);
58854
58854
  const accepted = acceptedContent(ctx.mcpReq.inputResponses, requestKey, confirmationSchema);
58855
+ if (options.elicitation === false) {
58856
+ return textResult({
58857
+ confirmed: false,
58858
+ dispatched: false,
58859
+ action: options.action,
58860
+ reason: "confirmation-unsupported",
58861
+ note: options.unsupportedNote ? `${DISABLED_NOTE}. ${options.unsupportedNote}` : `${DISABLED_NOTE}.`
58862
+ });
58863
+ }
58855
58864
  if (response.kind === "missing") {
58856
58865
  if (callerAcceptsFormElicitation(ctx) === false) {
58857
58866
  return textResult({
@@ -58882,7 +58891,7 @@ ${JSON.stringify(preview, null, 2)}`,
58882
58891
  note: "Nothing was changed because the confirmation was declined, cancelled, or left unchecked."
58883
58892
  });
58884
58893
  }
58885
- var DEFAULT_REQUEST_KEY, DEFAULT_CONFIRMATION_LABEL, UNSUPPORTED_NOTE, STATE_PREFIX;
58894
+ var DEFAULT_REQUEST_KEY, DEFAULT_CONFIRMATION_LABEL, UNSUPPORTED_NOTE, DISABLED_NOTE, STATE_PREFIX;
58886
58895
  var init_confirmation = __esm({
58887
58896
  "node_modules/@chrischall/mcp-utils/dist/server/confirmation.js"() {
58888
58897
  init_dist();
@@ -58893,6 +58902,7 @@ var init_confirmation = __esm({
58893
58902
  DEFAULT_REQUEST_KEY = "confirmation";
58894
58903
  DEFAULT_CONFIRMATION_LABEL = "Confirm this action should proceed.";
58895
58904
  UNSUPPORTED_NOTE = "Nothing was done because this client cannot show a confirmation prompt (it declares no MCP elicitation capability), and this action is never taken without one";
58905
+ DISABLED_NOTE = "Nothing was done because confirmation prompts are turned off for this server, and this action is never taken without one";
58896
58906
  STATE_PREFIX = "mcpu.confirm.v1.";
58897
58907
  }
58898
58908
  });
@@ -59046,7 +59056,7 @@ async function tokenConfirmation(action, fb) {
59046
59056
  }
59047
59057
  async function requireConfirmationWithFallback(ctx, options) {
59048
59058
  const { tokenFallback, ...confirmation } = options;
59049
- if (tokenFallback && callerAcceptsFormElicitation(ctx) === false) {
59059
+ if (tokenFallback && (options.elicitation === false || callerAcceptsFormElicitation(ctx) === false)) {
59050
59060
  return tokenConfirmation(options.action, tokenFallback);
59051
59061
  }
59052
59062
  return requireConfirmation(ctx, confirmation);
@@ -59223,6 +59233,20 @@ function readConfirmMode(env = process.env) {
59223
59233
  }
59224
59234
  return "refuse";
59225
59235
  }
59236
+ function readConfirmElicitation(env = process.env) {
59237
+ const raw = readEnvVar("MCP_CONFIRM_ELICITATION", { env })?.trim().toLowerCase();
59238
+ if (!raw || raw === "on")
59239
+ return "on";
59240
+ if (raw === "off")
59241
+ return "off";
59242
+ const key = `elicitation:${raw}`;
59243
+ if (!warned.has(key)) {
59244
+ warned.add(key);
59245
+ process.stderr.write(`MCP_CONFIRM_ELICITATION="${raw}" is not one of on, off; treating it as on.
59246
+ `);
59247
+ }
59248
+ return "on";
59249
+ }
59226
59250
  function readConfirmTtl(env) {
59227
59251
  const raw = readEnvVar("MCP_CONFIRM_TTL_SECONDS", { env })?.trim();
59228
59252
  if (!raw)
@@ -59275,10 +59299,13 @@ function confirmationFromEnv(options) {
59275
59299
  const spent = callerSpent ?? spentTokenStoreFromEnv(env);
59276
59300
  const mode = readConfirmMode(env);
59277
59301
  const ttlSeconds = readConfirmTtl(env);
59302
+ const elicitationOff = readConfirmElicitation(env) === "off";
59278
59303
  const bound = args === void 0 ? void 0 : boundArgs(args);
59279
- const confirmation = bound === void 0 || rest.binding ? rest : { ...rest, binding: { key: confirmKeyFromEnv(env), args: bound, ttlSeconds: ttlSeconds ?? DEFAULT_TTL_SECONDS2 } };
59304
+ const bindingAdded = bound === void 0 || rest.binding ? rest : { ...rest, binding: { key: confirmKeyFromEnv(env), args: bound, ttlSeconds: ttlSeconds ?? DEFAULT_TTL_SECONDS2 } };
59305
+ const confirmation = elicitationOff ? { ...bindingAdded, elicitation: false } : bindingAdded;
59280
59306
  if (mode === "refuse" || ttlSeconds === void 0) {
59281
- const hint = mode === "refuse" ? REFUSE_HINT : BAD_TTL_HINT;
59307
+ const reason = mode === "refuse" ? REFUSE_HINT : BAD_TTL_HINT;
59308
+ const hint = elicitationOff ? `${ELICITATION_OFF_HINT} ${reason}` : reason;
59282
59309
  return {
59283
59310
  ...confirmation,
59284
59311
  unsupportedNote: confirmation.unsupportedNote ? `${confirmation.unsupportedNote} ${hint}` : hint
@@ -59304,7 +59331,7 @@ function confirmationFromEnv(options) {
59304
59331
  }
59305
59332
  };
59306
59333
  }
59307
- var MODES, DEFAULT_TTL_SECONDS2, warned, processKey, fileStores, CONFIRM_TOKEN_AUTO_INSTRUCTION, REFUSE_HINT, BAD_TTL_HINT;
59334
+ var MODES, DEFAULT_TTL_SECONDS2, warned, processKey, fileStores, CONFIRM_TOKEN_AUTO_INSTRUCTION, REFUSE_HINT, ELICITATION_OFF_HINT, BAD_TTL_HINT;
59308
59335
  var init_confirm_env = __esm({
59309
59336
  "node_modules/@chrischall/mcp-utils/dist/server/confirm-env.js"() {
59310
59337
  init_config();
@@ -59316,6 +59343,7 @@ var init_confirm_env = __esm({
59316
59343
  fileStores = /* @__PURE__ */ new Map();
59317
59344
  CONFIRM_TOKEN_AUTO_INSTRUCTION = "Nothing has been done yet. Review this preview; if it is what was intended, call again with the same arguments plus confirmToken. (This server runs with MCP_CONFIRM_MODE=auto, so the user's approval in chat is not required.)";
59318
59345
  REFUSE_HINT = "Set MCP_CONFIRM_MODE=ask-user on the server to allow two-step confirmation instead.";
59346
+ ELICITATION_OFF_HINT = "MCP_CONFIRM_ELICITATION=off on the server turns confirmation prompts off.";
59319
59347
  BAD_TTL_HINT = "MCP_CONFIRM_TTL_SECONDS on the server is not a positive whole number of seconds; fix it to allow two-step confirmation.";
59320
59348
  }
59321
59349
  });
@@ -60755,7 +60783,7 @@ async function loadStdioDotenv() {
60755
60783
  }
60756
60784
 
60757
60785
  // src/version.ts
60758
- var VERSION = "2.3.2";
60786
+ var VERSION = "2.3.3";
60759
60787
 
60760
60788
  // src/errors.ts
60761
60789
  init_dist2();
package/dist/version.js CHANGED
@@ -1,2 +1,2 @@
1
1
  /** Single source of the server version. release-please bumps the literal below. */
2
- export const VERSION = '2.3.2'; // x-release-please-version
2
+ export const VERSION = '2.3.3'; // x-release-please-version
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chrischall/gemini-mcp",
3
- "version": "2.3.2",
3
+ "version": "2.3.3",
4
4
  "mcpName": "io.github.chrischall/gemini-mcp",
5
5
  "description": "Gemini image-generation MCP server for Claude — developed and maintained by AI (Claude Code)",
6
6
  "author": "Claude Code (AI) <https://www.anthropic.com/claude>",
@@ -46,7 +46,7 @@
46
46
  "typecheck": "tsc -p tsconfig.test.json"
47
47
  },
48
48
  "dependencies": {
49
- "@chrischall/mcp-utils": "^2.14.0",
49
+ "@chrischall/mcp-utils": "^2.15.0",
50
50
  "@modelcontextprotocol/server": "^2.3.0",
51
51
  "dotenv": "^18.0.2",
52
52
  "zod": "^4.6.5"
package/server.json CHANGED
@@ -6,12 +6,12 @@
6
6
  "url": "https://github.com/chrischall/gemini-mcp",
7
7
  "source": "github"
8
8
  },
9
- "version": "2.3.2",
9
+ "version": "2.3.3",
10
10
  "packages": [
11
11
  {
12
12
  "registryType": "npm",
13
13
  "identifier": "@chrischall/gemini-mcp",
14
- "version": "2.3.2",
14
+ "version": "2.3.3",
15
15
  "transport": {
16
16
  "type": "stdio"
17
17
  },
@@ -307,7 +307,7 @@ Condensed from Google's official Nano Banana prompting guide. Core rule:
307
307
 
308
308
  ## Notes
309
309
 
310
- - **Confirmations.** Local file inputs (`images`, `master_images`, `video_path`, `gemini_upload_file`'s `path`) and every delete are confirmed before anything is sent: a confirmation prompt where the client supports one; otherwise the first call does nothing and returns `status: "confirmation-required"` with a `preview` (resolved paths, MIME types, sizes — or the method/path being deleted) and a `confirmToken`. Show the preview to the user, and only after they approve call again with the **same arguments** plus `confirmToken`. The token is single-use, expires (default 10 min), and is bound to those exact arguments — change anything and the call is refused (`DRAFT_CHANGED`, with a fresh preview and token). `MCP_CONFIRM_MODE` on the server picks `ask-user` (default), `auto` (the model may approve after reviewing the preview) or `refuse`. Text prompts, URLs, `files/` references and base64 inputs are not gated.
310
+ - **Confirmations.** Local file inputs (`images`, `master_images`, `video_path`, `gemini_upload_file`'s `path`) and every delete are confirmed before anything is sent: a confirmation prompt where the client supports one (unless the server sets `MCP_CONFIRM_ELICITATION=off`); otherwise the first call does nothing and returns `status: "confirmation-required"` with a `preview` (resolved paths, MIME types, sizes — or the method/path being deleted) and a `confirmToken`. Show the preview to the user, and only after they approve call again with the **same arguments** plus `confirmToken`. The token is single-use, expires (default 10 min), and is bound to those exact arguments — change anything and the call is refused (`DRAFT_CHANGED`, with a fresh preview and token). `MCP_CONFIRM_MODE` on the server picks `ask-user` (default), `auto` (the model may approve after reviewing the preview) or `refuse`. Text prompts, URLs, `files/` references and base64 inputs are not gated.
311
311
  - **Input images** accept either file **paths** (`images` / `master_images`) or **base64/data-URI values** (`images_base64` / `master_images_base64`).
312
312
  - **`seed`** makes a result reproducible; it's echoed in the result metadata (a random one is chosen + echoed when omitted). `count>1` uses `seed, seed+1, …` so the images differ. Determinism isn't fully guaranteed by the model.
313
313
  - **`filename`/`basename`** set the output name (extension stripped); names never overwrite (a `-2`, `-3` suffix is added). The result echoes the absolute path(s), `model`, `seed`, and aspect/size.