@chrischall/gemini-mcp 2.3.1 → 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.1"
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.1",
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.1",
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
@@ -24393,7 +24393,7 @@ var init_internal = __esm({
24393
24393
  }
24394
24394
  });
24395
24395
 
24396
- // node_modules/@modelcontextprotocol/server/dist/src-BHSMhZ_W.mjs
24396
+ // node_modules/@modelcontextprotocol/server/dist/src-Cqbh3MYc.mjs
24397
24397
  function stampErrorBrands(instance, ctor) {
24398
24398
  const brands = /* @__PURE__ */ new Set();
24399
24399
  let current = ctor;
@@ -26373,7 +26373,8 @@ function build() {
26373
26373
  ListResourceTemplatesResultResponseSchema: wireResultResponse(ListResourceTemplatesResultSchema$1),
26374
26374
  ReadResourceResultResponseSchema: wireResultResponse(z2.union([ReadResourceResultSchema$1, InputRequiredResultSchema])),
26375
26375
  CompleteResultResponseSchema: wireResultResponse(CompleteResultSchema$1),
26376
- DiscoverResultResponseSchema: wireResultResponse(DiscoverResultSchema$1)
26376
+ DiscoverResultResponseSchema: wireResultResponse(DiscoverResultSchema$1),
26377
+ SubscriptionsListenResultResponseSchema: wireResultResponse(SubscriptionsListenResultSchema$1)
26377
26378
  };
26378
26379
  }
26379
26380
  function buildSchemas2026() {
@@ -26592,6 +26593,9 @@ function isSpecRequestMethod(method) {
26592
26593
  function isSpecNotificationMethod(method) {
26593
26594
  return ALL_CODECS.some((codec2) => codec2.hasNotificationMethod(method));
26594
26595
  }
26596
+ function isExtensionReusedRequestMethod(method) {
26597
+ return method === "tasks/get" || method === "tasks/cancel";
26598
+ }
26595
26599
  function isPlainObject$3(value) {
26596
26600
  return value !== null && typeof value === "object" && !Array.isArray(value);
26597
26601
  }
@@ -27166,8 +27170,8 @@ function normalizeRawShapeSchema(schema) {
27166
27170
  return schema;
27167
27171
  }
27168
27172
  var z2, BRANDS, OAuthError, SdkErrorCode, SdkError, SdkHttpError, FIRST_MODERN_PROTOCOL_VERSION, SUPPORTED_MODERN_PROTOCOL_VERSIONS, TOOL_RESULT_FOREIGN_FAMILY_KEYS, memo$1, REF_REWRITE_DATA_POSITION_KEYS, REF_REWRITE_NAME_MAP_KEYS, requestMethodKeys$1, notificationMethodKeys$1, resultMethodKeys, maps$1, rev2025RequestMethods, rev2025NotificationMethods, NOT_IN_ERA$1, rev2025Codec, memo, CACHEABLE_RESULT_METHODS, RESULT_CACHE_HINT_FALLBACK, ProtocolErrorCode, ProtocolError, ResourceNotFoundError, UrlElicitationRequiredError, UnsupportedProtocolVersionError, MissingRequiredClientCapabilityError, DEFAULT_CACHE_TTL_MS, DEFAULT_CACHE_SCOPE, EXTENDED_RESULT_TYPE_METHODS, INPUT_REQUEST_METHODS_2026, maps, requestMethodKeys, notificationMethodKeys, rev2026RequestMethods, rev2026NotificationMethods, NOT_IN_ERA, REQUIRED_ENVELOPE_KEYS, rev2026Codec, wireResultSchemasMemo, MODERN_WIRE_REVISION, ALL_CODECS, schemas_exports, isJSONRPCRequest, isJSONRPCNotification, isJSONRPCResultResponse, isJSONRPCErrorResponse, isInputRequiredResult, X_MCP_HEADER_KEY, RFC9110_TOKEN, PERMITTED_X_MCP_HEADER_TYPES, NON_REACHABLE_SUBSCHEMA_KEYWORDS, OBJECT_VALUED_SUBSCHEMA_KEYWORDS, HEADER_MISMATCH_ERROR_CODE, INBOUND_VALIDATION_LADDER, LADDER_ERROR_HTTP_STATUS, warnedZodFallback, JSON_SCHEMA_CONVERSION_TARGET, DATETIME_FRACTION_DIGITS, ANNOTATION_ONLY_JSON_SCHEMA_KEYWORDS, ROOT_KEYS, PROPERTY_KEYS_BY_TYPE, SUPPORTED_STRING_FORMATS, inputRequired, REQUEST_STATE_ONLY_LEG_PACING_MS, SPEC_SCHEMA_KEYS, authSchemas, _specTypeSchemas, _isSpecType, specTypeSchemas, isSpecType, DEFAULT_REQUEST_TIMEOUT_MSEC, RESERVED_ENVELOPE_META_KEYS, RETRY_PARAMS_KEYS, NO_REQUEST_STATE, writeNegotiatedProtocolVersion, Protocol, require_content_type, import_content_type, STDIO_DEFAULT_MAX_BUFFER_SIZE, ReadBuffer, TOOL_NAME_REGEX;
27169
- var init_src_BHSMhZ_W = __esm({
27170
- "node_modules/@modelcontextprotocol/server/dist/src-BHSMhZ_W.mjs"() {
27173
+ var init_src_Cqbh3MYc = __esm({
27174
+ "node_modules/@modelcontextprotocol/server/dist/src-Cqbh3MYc.mjs"() {
27171
27175
  init_chunk_Br0eD_fh();
27172
27176
  init_dialects_DoSzNhcb();
27173
27177
  init_internal();
@@ -28267,6 +28271,8 @@ var init_src_BHSMhZ_W = __esm({
28267
28271
  _transport;
28268
28272
  _requestMessageId = 0;
28269
28273
  _requestHandlers = /* @__PURE__ */ new Map();
28274
+ /** Methods registered with an explicit schema; the era gate in `_onrequest` reads it for the Tasks extension names. */
28275
+ _customSchemaRequestMethods = /* @__PURE__ */ new Set();
28270
28276
  _requestHandlerAbortControllers = /* @__PURE__ */ new Map();
28271
28277
  _notificationHandlers = /* @__PURE__ */ new Map();
28272
28278
  _responseHandlers = /* @__PURE__ */ new Map();
@@ -28550,7 +28556,7 @@ var init_src_BHSMhZ_W = __esm({
28550
28556
  return;
28551
28557
  }
28552
28558
  }
28553
- if (isSpecRequestMethod(request.method) && !codec2.hasRequestMethod(request.method)) {
28559
+ if (isSpecRequestMethod(request.method) && !codec2.hasRequestMethod(request.method) && !(isExtensionReusedRequestMethod(request.method) && this._customSchemaRequestMethods.has(request.method))) {
28554
28560
  sendErrorResponse(ProtocolErrorCode.MethodNotFound, "Method not found");
28555
28561
  return;
28556
28562
  }
@@ -28683,8 +28689,11 @@ var init_src_BHSMhZ_W = __esm({
28683
28689
  }
28684
28690
  request(request, schemaOrOptions, maybeOptions) {
28685
28691
  const codec2 = this._resolveOutboundCodec(request.method);
28692
+ if (isStandardSchema(schemaOrOptions)) {
28693
+ if (!isExtensionReusedRequestMethod(request.method)) this._assertOutboundRequestInEra(codec2, request.method);
28694
+ return this._requestWithSchemaViaCodec(codec2, request, schemaOrOptions, maybeOptions);
28695
+ }
28686
28696
  this._assertOutboundRequestInEra(codec2, request.method);
28687
- if (isStandardSchema(schemaOrOptions)) return this._requestWithSchemaViaCodec(codec2, request, schemaOrOptions, maybeOptions);
28688
28697
  const validate2 = codecResultValidator(codec2, request.method);
28689
28698
  if (validate2 === void 0) throw new TypeError(`'${request.method}' is not a spec method; pass a result schema as the second argument to request().`);
28690
28699
  return this._requestWithSchemaViaCodec(codec2, request, validate2, schemaOrOptions);
@@ -28928,6 +28937,8 @@ var init_src_BHSMhZ_W = __esm({
28928
28937
  return maybeHandler(parsed.data, ctx);
28929
28938
  };
28930
28939
  else throw new TypeError("setRequestHandler: handler is required");
28940
+ if (typeof schemasOrHandler === "function") this._customSchemaRequestMethods.delete(method);
28941
+ else this._customSchemaRequestMethods.add(method);
28931
28942
  this._requestHandlers.set(method, this._wrapHandler(method, stored));
28932
28943
  }
28933
28944
  /**
@@ -28957,6 +28968,7 @@ var init_src_BHSMhZ_W = __esm({
28957
28968
  */
28958
28969
  removeRequestHandler(method) {
28959
28970
  this._requestHandlers.delete(method);
28971
+ this._customSchemaRequestMethods.delete(method);
28960
28972
  }
28961
28973
  /**
28962
28974
  * Asserts that a request handler has not already been set for the given method, in preparation for a new one being automatically installed.
@@ -36099,7 +36111,7 @@ var init_shimsNode = __esm({
36099
36111
  }
36100
36112
  });
36101
36113
 
36102
- // node_modules/@modelcontextprotocol/server/dist/mcp-DYuW2ZSs.mjs
36114
+ // node_modules/@modelcontextprotocol/server/dist/mcp-DIH4cS6P.mjs
36103
36115
  function isCompletable(schema) {
36104
36116
  return !!schema && typeof schema === "object" && COMPLETABLE_SYMBOL in schema;
36105
36117
  }
@@ -36209,6 +36221,30 @@ function serverIdentityOf(server) {
36209
36221
  function discoverAdvertisedCapabilities(capabilities) {
36210
36222
  return { ...capabilities };
36211
36223
  }
36224
+ function toolInputElementCount(value, max) {
36225
+ let count = 0;
36226
+ const stack = [value];
36227
+ while (stack.length > 0) {
36228
+ const node2 = stack.pop();
36229
+ if (node2 === null || typeof node2 !== "object") continue;
36230
+ if (Array.isArray(node2)) for (const child of node2) {
36231
+ if (++count > max) return count;
36232
+ if (child !== null && typeof child === "object") stack.push(child);
36233
+ }
36234
+ else for (const key in node2) {
36235
+ if (!Object.prototype.hasOwnProperty.call(node2, key)) continue;
36236
+ if (++count > max) return count;
36237
+ const child = node2[key];
36238
+ if (child !== null && typeof child === "object") stack.push(child);
36239
+ }
36240
+ }
36241
+ return count;
36242
+ }
36243
+ function resolveMaxToolInputElements(value) {
36244
+ if (value === void 0 || value === Infinity) return void 0;
36245
+ if (typeof value !== "number" || Number.isNaN(value) || value < 1) throw new RangeError(`maxToolInputElements must be a number of at least 1, or Infinity, got ${String(value)}`);
36246
+ return value;
36247
+ }
36212
36248
  function createToolExecutor(inputSchema, handler) {
36213
36249
  if (inputSchema) {
36214
36250
  const callback$1 = handler;
@@ -36217,6 +36253,12 @@ function createToolExecutor(inputSchema, handler) {
36217
36253
  const callback = handler;
36218
36254
  return async (_args, ctx) => callback(ctx);
36219
36255
  }
36256
+ function convertListedInputSchema(name, inputSchema) {
36257
+ const json2 = standardSchemaToJsonSchema(inputSchema, "input");
36258
+ const scan = scanXMcpHeaderDeclarations(json2);
36259
+ if (!scan.valid) console.warn(`[mcp-sdk] tool '${name}' carries an invalid x-mcp-header declaration and will be excluded by conforming Streamable HTTP clients: ${scan.reason}`);
36260
+ return json2;
36261
+ }
36220
36262
  function convertOutputSchemaJson(outputSchema) {
36221
36263
  if (outputSchema === void 0) return void 0;
36222
36264
  try {
@@ -36229,7 +36271,7 @@ function createPromptHandler(name, argsSchema, callback) {
36229
36271
  if (argsSchema) {
36230
36272
  const typedCallback = callback;
36231
36273
  return async (args, ctx) => {
36232
- const parseResult = await validateStandardSchema(argsSchema, args);
36274
+ const parseResult = await validateStandardSchema(argsSchema, args ?? {});
36233
36275
  if (!parseResult.success) throw new ProtocolError(ProtocolErrorCode.InvalidParams, `Invalid arguments for prompt ${name}: ${parseResult.error}`);
36234
36276
  return typedCallback(parseResult.data, ctx);
36235
36277
  };
@@ -36259,9 +36301,9 @@ function unwrapOptionalSchema(schema) {
36259
36301
  return schema.def?.innerType ?? schema;
36260
36302
  }
36261
36303
  var COMPLETABLE_SYMBOL, MAX_TIMER_DELAY_MS, DEFAULT_MAX_SUBSCRIPTIONS, CHANGE_NOTIFICATION_METHODS, StdioListenRouter, DEFAULT_LEGACY_SHIM_MAX_ROUNDS, DEFAULT_LEGACY_SHIM_ROUND_TIMEOUT_MS, LegacyInputRequiredShim, INPUT_REQUIRED_CAPABLE_METHODS, writeClientIdentity, installDiscoverHandler, readServerIdentity, Server, McpServer, EMPTY_OBJECT_JSON_SCHEMA, EMPTY_COMPLETION_RESULT;
36262
- var init_mcp_DYuW2ZSs = __esm({
36263
- "node_modules/@modelcontextprotocol/server/dist/mcp-DYuW2ZSs.mjs"() {
36264
- init_src_BHSMhZ_W();
36304
+ var init_mcp_DIH4cS6P = __esm({
36305
+ "node_modules/@modelcontextprotocol/server/dist/mcp-DIH4cS6P.mjs"() {
36306
+ init_src_Cqbh3MYc();
36265
36307
  init_shimsNode();
36266
36308
  COMPLETABLE_SYMBOL = /* @__PURE__ */ Symbol.for("mcp.completable");
36267
36309
  MAX_TIMER_DELAY_MS = 2 ** 31 - 1;
@@ -36284,7 +36326,7 @@ var init_mcp_DYuW2ZSs = __esm({
36284
36326
  _serverCapabilities;
36285
36327
  /**
36286
36328
  * The serving instance's identity, stamped onto the graceful-close
36287
- * results' `_meta` (the spec's `SubscriptionsListenResultMeta` extends
36329
+ * results' `_meta` (the spec's `SubscriptionsListenResultMetaObject` extends
36288
36330
  * `ResultMetaObject`). Handed over together with the capabilities.
36289
36331
  */
36290
36332
  _serverInfo;
@@ -36550,6 +36592,11 @@ var init_mcp_DYuW2ZSs = __esm({
36550
36592
  if (modernProtocolVersions(this._supportedProtocolVersions).length > 0) this.setRequestHandler("server/discover", () => this._ondiscover());
36551
36593
  if (this._capabilities.logging) this._registerLoggingHandler();
36552
36594
  }
36595
+ /** Attaches to the given transport; rejects while this instance is connected to another one. */
36596
+ async connect(transport) {
36597
+ if (this.transport !== void 0) throw new SdkError(SdkErrorCode.AlreadyConnected, "Use a separate Server instance per connection: this instance is already connected to a transport. To connect it to a new transport, call close() first.");
36598
+ await super.connect(transport);
36599
+ }
36553
36600
  /**
36554
36601
  * Registers the built-in `logging/setLevel` request handler.
36555
36602
  *
@@ -37105,16 +37152,12 @@ var init_mcp_DYuW2ZSs = __esm({
37105
37152
  * The underlying {@linkcode Server} instance, useful for advanced operations like sending notifications.
37106
37153
  */
37107
37154
  server;
37155
+ _maxToolInputElements;
37108
37156
  _registeredResources = {};
37109
37157
  _registeredResourceTemplates = {};
37110
37158
  _registeredTools = {};
37111
37159
  _registeredPrompts = {};
37112
- /**
37113
- * Per-tool JSON-converted `inputSchema`, memoized so the SEP-2243
37114
- * registration-time scan and the pre-dispatch validation step share one
37115
- * conversion instead of paying it twice per request under the
37116
- * per-request-factory `createMcpHandler` model.
37117
- */
37160
+ /** Per-tool JSON-converted `inputSchema`, filled on first use by `toolInputSchemaJson()`. */
37118
37161
  _toolInputSchemaJson = {};
37119
37162
  /**
37120
37163
  * The JSON-serialized `inputSchema` of a registered tool, or `undefined`
@@ -37139,6 +37182,7 @@ var init_mcp_DYuW2ZSs = __esm({
37139
37182
  }
37140
37183
  constructor(serverInfo, options) {
37141
37184
  this.server = new Server(serverInfo, options);
37185
+ this._maxToolInputElements = resolveMaxToolInputElements(options?.maxToolInputElements);
37142
37186
  if (options?.capabilities?.tools) this.setToolRequestHandlers();
37143
37187
  if (options?.capabilities?.resources) this.setResourceRequestHandlers();
37144
37188
  if (options?.capabilities?.prompts) this.setPromptRequestHandlers();
@@ -37211,7 +37255,7 @@ var init_mcp_DYuW2ZSs = __esm({
37211
37255
  name,
37212
37256
  title: tool.title,
37213
37257
  description: tool.description,
37214
- inputSchema: tool.inputSchema ? standardSchemaToJsonSchema(tool.inputSchema, "input") : EMPTY_OBJECT_JSON_SCHEMA,
37258
+ inputSchema: tool.inputSchema ? convertListedInputSchema(name, tool.inputSchema) : EMPTY_OBJECT_JSON_SCHEMA,
37215
37259
  annotations: tool.annotations,
37216
37260
  icons: tool.icons,
37217
37261
  execution: tool.execution,
@@ -37256,6 +37300,7 @@ var init_mcp_DYuW2ZSs = __esm({
37256
37300
  * Validates tool input arguments against the tool's input schema.
37257
37301
  */
37258
37302
  async validateToolInput(tool, args, toolName) {
37303
+ if (this._maxToolInputElements !== void 0 && toolInputElementCount(args, this._maxToolInputElements) > this._maxToolInputElements) throw new ProtocolError(ProtocolErrorCode.InvalidParams, `Invalid arguments for tool ${toolName}: arguments contain more than the maximum of ${this._maxToolInputElements} elements`);
37259
37304
  if (!tool.inputSchema) return;
37260
37305
  const parseResult = await validateStandardSchema(tool.inputSchema, args ?? {});
37261
37306
  if (!parseResult.success) throw new ProtocolError(ProtocolErrorCode.InvalidParams, `Input validation error: Invalid arguments for tool ${toolName}: ${parseResult.error}`);
@@ -37530,20 +37575,19 @@ var init_mcp_DYuW2ZSs = __esm({
37530
37575
  }
37531
37576
  _createRegisteredTool(name, title, description, inputSchema, outputSchema, annotations, icons, execution, scopeChallenge, _meta, handler) {
37532
37577
  validateAndWarnToolName(name);
37533
- if (inputSchema !== void 0) try {
37534
- const json2 = standardSchemaToJsonSchema(inputSchema, "input");
37535
- this._toolInputSchemaJson[name] = json2;
37536
- const scan = scanXMcpHeaderDeclarations(json2);
37537
- if (!scan.valid) console.warn(`[mcp-sdk] tool '${name}' carries an invalid x-mcp-header declaration and will be excluded by conforming Streamable HTTP clients: ${scan.reason}`);
37538
- } catch {
37539
- }
37540
37578
  let currentHandler = handler;
37579
+ let outputSchemaJson;
37541
37580
  const registeredTool = {
37542
37581
  title,
37543
37582
  description,
37544
37583
  inputSchema,
37545
37584
  outputSchema,
37546
- outputSchemaJson: convertOutputSchemaJson(outputSchema),
37585
+ get outputSchemaJson() {
37586
+ return outputSchemaJson ??= convertOutputSchemaJson(registeredTool.outputSchema);
37587
+ },
37588
+ set outputSchemaJson(value) {
37589
+ outputSchemaJson = value;
37590
+ },
37547
37591
  annotations,
37548
37592
  icons,
37549
37593
  execution,
@@ -37987,8 +38031,8 @@ function toError(value) {
37987
38031
  var swallowsErrorsAfterClose, StdioServerTransport, DISCARD_ANSWER_TIMEOUT_MS, StdioConnectionChannel;
37988
38032
  var init_stdio = __esm({
37989
38033
  "node_modules/@modelcontextprotocol/server/dist/stdio.mjs"() {
37990
- init_mcp_DYuW2ZSs();
37991
- init_src_BHSMhZ_W();
38034
+ init_mcp_DIH4cS6P();
38035
+ init_src_Cqbh3MYc();
37992
38036
  init_shimsNode();
37993
38037
  swallowsErrorsAfterClose = /* @__PURE__ */ Symbol("swallowsErrorsAfterClose");
37994
38038
  StdioServerTransport = class {
@@ -38179,8 +38223,8 @@ var init_stdio = __esm({
38179
38223
  var DEFAULT_MAX_REQUEST_BODY_SIZE;
38180
38224
  var init_dist = __esm({
38181
38225
  "node_modules/@modelcontextprotocol/server/dist/index.mjs"() {
38182
- init_mcp_DYuW2ZSs();
38183
- init_src_BHSMhZ_W();
38226
+ init_mcp_DIH4cS6P();
38227
+ init_src_Cqbh3MYc();
38184
38228
  init_shimsNode();
38185
38229
  DEFAULT_MAX_REQUEST_BODY_SIZE = 4 * 1024 * 1024;
38186
38230
  }
@@ -58808,6 +58852,15 @@ ${JSON.stringify(preview, null, 2)}`,
58808
58852
  };
58809
58853
  const response = inputResponse(ctx.mcpReq.inputResponses, requestKey);
58810
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
+ }
58811
58864
  if (response.kind === "missing") {
58812
58865
  if (callerAcceptsFormElicitation(ctx) === false) {
58813
58866
  return textResult({
@@ -58838,7 +58891,7 @@ ${JSON.stringify(preview, null, 2)}`,
58838
58891
  note: "Nothing was changed because the confirmation was declined, cancelled, or left unchecked."
58839
58892
  });
58840
58893
  }
58841
- 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;
58842
58895
  var init_confirmation = __esm({
58843
58896
  "node_modules/@chrischall/mcp-utils/dist/server/confirmation.js"() {
58844
58897
  init_dist();
@@ -58849,6 +58902,7 @@ var init_confirmation = __esm({
58849
58902
  DEFAULT_REQUEST_KEY = "confirmation";
58850
58903
  DEFAULT_CONFIRMATION_LABEL = "Confirm this action should proceed.";
58851
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";
58852
58906
  STATE_PREFIX = "mcpu.confirm.v1.";
58853
58907
  }
58854
58908
  });
@@ -59002,7 +59056,7 @@ async function tokenConfirmation(action, fb) {
59002
59056
  }
59003
59057
  async function requireConfirmationWithFallback(ctx, options) {
59004
59058
  const { tokenFallback, ...confirmation } = options;
59005
- if (tokenFallback && callerAcceptsFormElicitation(ctx) === false) {
59059
+ if (tokenFallback && (options.elicitation === false || callerAcceptsFormElicitation(ctx) === false)) {
59006
59060
  return tokenConfirmation(options.action, tokenFallback);
59007
59061
  }
59008
59062
  return requireConfirmation(ctx, confirmation);
@@ -59179,6 +59233,20 @@ function readConfirmMode(env = process.env) {
59179
59233
  }
59180
59234
  return "refuse";
59181
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
+ }
59182
59250
  function readConfirmTtl(env) {
59183
59251
  const raw = readEnvVar("MCP_CONFIRM_TTL_SECONDS", { env })?.trim();
59184
59252
  if (!raw)
@@ -59231,10 +59299,13 @@ function confirmationFromEnv(options) {
59231
59299
  const spent = callerSpent ?? spentTokenStoreFromEnv(env);
59232
59300
  const mode = readConfirmMode(env);
59233
59301
  const ttlSeconds = readConfirmTtl(env);
59302
+ const elicitationOff = readConfirmElicitation(env) === "off";
59234
59303
  const bound = args === void 0 ? void 0 : boundArgs(args);
59235
- 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;
59236
59306
  if (mode === "refuse" || ttlSeconds === void 0) {
59237
- 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;
59238
59309
  return {
59239
59310
  ...confirmation,
59240
59311
  unsupportedNote: confirmation.unsupportedNote ? `${confirmation.unsupportedNote} ${hint}` : hint
@@ -59260,7 +59331,7 @@ function confirmationFromEnv(options) {
59260
59331
  }
59261
59332
  };
59262
59333
  }
59263
- 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;
59264
59335
  var init_confirm_env = __esm({
59265
59336
  "node_modules/@chrischall/mcp-utils/dist/server/confirm-env.js"() {
59266
59337
  init_config();
@@ -59272,6 +59343,7 @@ var init_confirm_env = __esm({
59272
59343
  fileStores = /* @__PURE__ */ new Map();
59273
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.)";
59274
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.";
59275
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.";
59276
59348
  }
59277
59349
  });
@@ -59368,7 +59440,10 @@ function surfaceToolHints(server) {
59368
59440
  ));
59369
59441
  }
59370
59442
  async function createMcpServer(opts) {
59371
- const server = new McpServer({ name: opts.name, version: opts.version }, { supportedProtocolVersions: [...SERVER_PROTOCOL_VERSIONS] });
59443
+ const server = new McpServer({ name: opts.name, version: opts.version }, {
59444
+ supportedProtocolVersions: [...SERVER_PROTOCOL_VERSIONS],
59445
+ ...opts.maxToolInputElements !== void 0 ? { maxToolInputElements: opts.maxToolInputElements } : {}
59446
+ });
59372
59447
  if (opts.surfaceHints !== false)
59373
59448
  surfaceToolHints(server);
59374
59449
  if (opts.banner !== void 0) {
@@ -59770,6 +59845,21 @@ var init_fs = __esm({
59770
59845
  }
59771
59846
  });
59772
59847
 
59848
+ // node_modules/@chrischall/mcp-utils/dist/internal/headers.js
59849
+ function responseHeader(res, name) {
59850
+ return getHeader(res?.headers, name);
59851
+ }
59852
+ function getHeader(headers, name) {
59853
+ if (!headers || typeof headers.get !== "function")
59854
+ return null;
59855
+ const value = headers.get.call(headers, name);
59856
+ return typeof value === "string" ? value : null;
59857
+ }
59858
+ var init_headers = __esm({
59859
+ "node_modules/@chrischall/mcp-utils/dist/internal/headers.js"() {
59860
+ }
59861
+ });
59862
+
59773
59863
  // node_modules/@chrischall/mcp-utils/dist/internal/ascii.js
59774
59864
  var init_ascii = __esm({
59775
59865
  "node_modules/@chrischall/mcp-utils/dist/internal/ascii.js"() {
@@ -60020,7 +60110,7 @@ function createApiClient(opts) {
60020
60110
  if (retryStatuses.includes(res.status) && attempt < retry.count) {
60021
60111
  discard(current);
60022
60112
  attempt += 1;
60023
- const delay = retry.honorRetryAfter ? parseRetryAfterMs(res.headers.get("retry-after"), {
60113
+ const delay = retry.honorRetryAfter ? parseRetryAfterMs(responseHeader(res, "retry-after"), {
60024
60114
  defaultMs: retry.delayMs,
60025
60115
  capMs: retry.maxRetryAfterMs ?? 3e4
60026
60116
  }) : retry.delayMs;
@@ -60033,7 +60123,7 @@ function createApiClient(opts) {
60033
60123
  async function unauthorizedOrEdge(attempt, method, path) {
60034
60124
  const res = attempt.res;
60035
60125
  let text = "";
60036
- if (/json/i.test(res.headers.get("content-type") ?? "")) {
60126
+ if (/json/i.test(responseHeader(res, "content-type") ?? "")) {
60037
60127
  discard(attempt);
60038
60128
  } else {
60039
60129
  text = await readBody(attempt, (r) => r.text()).catch(() => "");
@@ -60045,14 +60135,14 @@ function createApiClient(opts) {
60045
60135
  }
60046
60136
  async function rateLimitedError(attempt, method, path) {
60047
60137
  const res = attempt.res;
60048
- const retryAfter = res.headers.get("retry-after");
60138
+ const retryAfter = responseHeader(res, "retry-after");
60049
60139
  const retryAfterMs = retryAfterToMs(retryAfter);
60050
60140
  if (!opts.onRateLimited) {
60051
60141
  discard(attempt);
60052
60142
  return new RateLimitedError(service, retryAfterMs);
60053
60143
  }
60054
60144
  let text = "";
60055
- if (/json/i.test(res.headers.get("content-type") ?? "")) {
60145
+ if (/json/i.test(responseHeader(res, "content-type") ?? "")) {
60056
60146
  discard(attempt);
60057
60147
  } else {
60058
60148
  text = await readBody(attempt, (r) => r.text()).catch(() => "");
@@ -60112,7 +60202,7 @@ function createApiClient(opts) {
60112
60202
  const bytes = new Uint8Array(await readBody(attempt, (r) => r.arrayBuffer()));
60113
60203
  return {
60114
60204
  status: res.status,
60115
- contentType: res.headers.get("content-type"),
60205
+ contentType: responseHeader(res, "content-type"),
60116
60206
  headers: res.headers,
60117
60207
  bytes
60118
60208
  };
@@ -60145,6 +60235,7 @@ function formatApiError(status, method, path, errorText, opts = {}) {
60145
60235
  var DEFAULT_RETRY, defaultSleep, UnauthorizedError, RateLimitedError, RequestTimeoutError, ApiError, EdgeBlockedError, EDGE_BLOCK_SCAN_MAX, EDGE_BLOCK_MARKERS;
60146
60236
  var init_http = __esm({
60147
60237
  "node_modules/@chrischall/mcp-utils/dist/http/index.js"() {
60238
+ init_headers();
60148
60239
  init_cancel();
60149
60240
  init_errors();
60150
60241
  init_scrape();
@@ -60320,6 +60411,7 @@ var init_es256 = __esm({
60320
60411
  // node_modules/@chrischall/mcp-utils/dist/auth/index.js
60321
60412
  var init_auth = __esm({
60322
60413
  "node_modules/@chrischall/mcp-utils/dist/auth/index.js"() {
60414
+ init_headers();
60323
60415
  init_config();
60324
60416
  init_errors();
60325
60417
  init_http();
@@ -60691,7 +60783,7 @@ async function loadStdioDotenv() {
60691
60783
  }
60692
60784
 
60693
60785
  // src/version.ts
60694
- var VERSION = "2.3.1";
60786
+ var VERSION = "2.3.3";
60695
60787
 
60696
60788
  // src/errors.ts
60697
60789
  init_dist2();
@@ -65725,7 +65817,7 @@ await runMcp({
65725
65817
  });
65726
65818
  /*! Bundled license information:
65727
65819
 
65728
- @modelcontextprotocol/server/dist/src-BHSMhZ_W.mjs:
65820
+ @modelcontextprotocol/server/dist/src-Cqbh3MYc.mjs:
65729
65821
  (*!
65730
65822
  * content-type
65731
65823
  * Copyright(c) 2015 Douglas Christopher Wilson
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.1'; // 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.1",
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,13 +46,13 @@
46
46
  "typecheck": "tsc -p tsconfig.test.json"
47
47
  },
48
48
  "dependencies": {
49
- "@chrischall/mcp-utils": "^2.13.0",
50
- "@modelcontextprotocol/server": "^2.2.0",
49
+ "@chrischall/mcp-utils": "^2.15.0",
50
+ "@modelcontextprotocol/server": "^2.3.0",
51
51
  "dotenv": "^18.0.2",
52
52
  "zod": "^4.6.5"
53
53
  },
54
54
  "devDependencies": {
55
- "@modelcontextprotocol/client": "^2.2.0",
55
+ "@modelcontextprotocol/client": "^2.3.0",
56
56
  "@types/node": "^26.0.0",
57
57
  "@vitest/coverage-v8": "^5.0.0",
58
58
  "esbuild": "^0.28.0",
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.1",
9
+ "version": "2.3.3",
10
10
  "packages": [
11
11
  {
12
12
  "registryType": "npm",
13
13
  "identifier": "@chrischall/gemini-mcp",
14
- "version": "2.3.1",
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.