@chrischall/gemini-mcp 0.7.0 → 0.7.1

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": "0.7.0"
10
+ "version": "0.7.1"
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": "0.7.0",
18
+ "version": "0.7.1",
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": "0.7.0",
4
+ "version": "0.7.1",
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/dist/bundle.js CHANGED
@@ -32510,7 +32510,7 @@ var init_clipboard = __esm({
32510
32510
  init_dist();
32511
32511
 
32512
32512
  // src/version.ts
32513
- var VERSION = "0.7.0";
32513
+ var VERSION = "0.7.1";
32514
32514
 
32515
32515
  // src/tools/models.ts
32516
32516
  init_dist();
@@ -32544,6 +32544,8 @@ var UPLOAD_BASE_URL = "https://generativelanguage.googleapis.com/upload/v1beta";
32544
32544
  var FILE_MAX_BYTES = 2 * 1024 ** 3;
32545
32545
  var FILE_POLL_INTERVAL_MS = 2e3;
32546
32546
  var FILE_POLL_MAX_ATTEMPTS = 150;
32547
+ var CHAIN_404_RETRIES = 2;
32548
+ var CHAIN_404_RETRY_MS = 2e3;
32547
32549
  var GeminiClient = class {
32548
32550
  apiKey;
32549
32551
  configError;
@@ -32756,9 +32758,28 @@ var GeminiClient = class {
32756
32758
  if (opts.searchTypes?.length) searchTool.search_types = opts.searchTypes;
32757
32759
  body.tools = [searchTool];
32758
32760
  }
32759
- const data = await this.interactionsApi.fetchJson("POST", "/interactions", {
32760
- body
32761
- });
32761
+ let data;
32762
+ for (let attempt = 0; ; attempt++) {
32763
+ try {
32764
+ data = await this.interactionsApi.fetchJson("POST", "/interactions", {
32765
+ body
32766
+ });
32767
+ break;
32768
+ } catch (err) {
32769
+ if (!(opts.previousInteractionId && err instanceof ApiError && err.status === 404)) throw err;
32770
+ if (attempt < CHAIN_404_RETRIES) {
32771
+ await this.sleep(CHAIN_404_RETRY_MS * (attempt + 1));
32772
+ continue;
32773
+ }
32774
+ throw new McpToolError(
32775
+ `Previous interaction "${opts.previousInteractionId}" was not found (retried ${CHAIN_404_RETRIES}\xD7 \u2014 the interactions store can lag briefly after a turn completes). If the id is old: interactions are retained 55 days on the paid tier (1 day on the free tier) and are scoped to the API key that created them.`,
32776
+ {
32777
+ hint: "Retry once more in a few seconds; if it keeps failing, start a new chain: call gemini_interact again with the last output image passed via `images` (or `images_base64`) plus the same instruction, then chain the NEW interaction id.",
32778
+ cause: err
32779
+ }
32780
+ );
32781
+ }
32782
+ }
32762
32783
  const images = [];
32763
32784
  const textParts = [];
32764
32785
  const searchQueries = [];
package/dist/client.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { basename, dirname, join } from 'node:path';
2
2
  import { fileURLToPath } from 'node:url';
3
- import { loadDotenvSafely, readEnvVar, McpToolError, createApiClient, formatApiError, fileBlob } from '@chrischall/mcp-utils';
3
+ import { loadDotenvSafely, readEnvVar, McpToolError, ApiError, createApiClient, formatApiError, fileBlob } from '@chrischall/mcp-utils';
4
4
  import { resolveModel, filterImageModels } from './models.js';
5
5
  const __dirname = dirname(fileURLToPath(import.meta.url));
6
6
  await loadDotenvSafely({ path: join(__dirname, '..', '.env'), override: false });
@@ -21,6 +21,13 @@ const FILE_MAX_BYTES = 2 * 1024 ** 3;
21
21
  // in ~1s (verified); longer videos take proportionally longer to process.
22
22
  const FILE_POLL_INTERVAL_MS = 2_000;
23
23
  const FILE_POLL_MAX_ATTEMPTS = 150;
24
+ // The interactions store is eventually consistent: a freshly returned id can
25
+ // 404 for a short window right after its turn completes (observed live
26
+ // 2026-07-06 — an id that 404'd on an immediate chain resolved fine minutes
27
+ // later). A chained 404 generated nothing (no cost), so retry before giving up:
28
+ // attempts wait 2s then 4s (~6s total).
29
+ const CHAIN_404_RETRIES = 2;
30
+ const CHAIN_404_RETRY_MS = 2_000;
24
31
  export class GeminiClient {
25
32
  apiKey;
26
33
  configError;
@@ -256,9 +263,33 @@ export class GeminiClient {
256
263
  searchTool.search_types = opts.searchTypes;
257
264
  body.tools = [searchTool];
258
265
  }
259
- const data = await this.interactionsApi.fetchJson('POST', '/interactions', {
260
- body,
261
- });
266
+ let data;
267
+ for (let attempt = 0;; attempt++) {
268
+ try {
269
+ data = await this.interactionsApi.fetchJson('POST', '/interactions', {
270
+ body,
271
+ });
272
+ break;
273
+ }
274
+ catch (err) {
275
+ // A 404 on a chained call means the referenced interaction wasn't
276
+ // found. Two causes: (a) store lag right after the id was created —
277
+ // retry with backoff; (b) genuinely gone — interactions are retained
278
+ // 55 days (paid tier) / 1 day (free tier) and are scoped to the API
279
+ // key's project. The chain is recoverable from the last output file,
280
+ // so the exhausted-retries error says how.
281
+ if (!(opts.previousInteractionId && err instanceof ApiError && err.status === 404))
282
+ throw err;
283
+ if (attempt < CHAIN_404_RETRIES) {
284
+ await this.sleep(CHAIN_404_RETRY_MS * (attempt + 1));
285
+ continue;
286
+ }
287
+ throw new McpToolError(`Previous interaction "${opts.previousInteractionId}" was not found (retried ${CHAIN_404_RETRIES}× — the interactions store can lag briefly after a turn completes). If the id is old: interactions are retained 55 days on the paid tier (1 day on the free tier) and are scoped to the API key that created them.`, {
288
+ hint: 'Retry once more in a few seconds; if it keeps failing, start a new chain: call gemini_interact again with the last output image passed via `images` (or `images_base64`) plus the same instruction, then chain the NEW interaction id.',
289
+ cause: err,
290
+ });
291
+ }
292
+ }
262
293
  // Only surface the `model_output` step — that's the caller-facing result.
263
294
  // `thought` steps hold internal reasoning (and, with includeThoughts, draft
264
295
  // "thinking" images); collecting those would leak reasoning into `text` and
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 = '0.7.0'; // x-release-please-version
2
+ export const VERSION = '0.7.1'; // x-release-please-version
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chrischall/gemini-mcp",
3
- "version": "0.7.0",
3
+ "version": "0.7.1",
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>",
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": "0.7.0",
9
+ "version": "0.7.1",
10
10
  "packages": [
11
11
  {
12
12
  "registryType": "npm",
13
13
  "identifier": "@chrischall/gemini-mcp",
14
- "version": "0.7.0",
14
+ "version": "0.7.1",
15
15
  "transport": {
16
16
  "type": "stdio"
17
17
  },