@chrischall/gemini-mcp 1.9.0 → 1.10.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/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +1 -1
- package/dist/bundle.js +8 -5
- package/dist/tools/interact.js +4 -2
- package/dist/tools/shared.js +19 -5
- package/dist/tools/video.js +4 -2
- package/dist/version.js +1 -1
- package/mint.yaml +57 -0
- package/package.json +3 -2
- package/server.json +2 -2
|
@@ -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": "1.
|
|
10
|
+
"version": "1.10.0"
|
|
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": "1.
|
|
18
|
+
"version": "1.10.0",
|
|
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": "1.
|
|
4
|
+
"version": "1.10.0",
|
|
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
|
@@ -32868,7 +32868,7 @@ async function loadStdioDotenv() {
|
|
|
32868
32868
|
}
|
|
32869
32869
|
|
|
32870
32870
|
// src/version.ts
|
|
32871
|
-
var VERSION = "1.
|
|
32871
|
+
var VERSION = "1.10.0";
|
|
32872
32872
|
|
|
32873
32873
|
// src/errors.ts
|
|
32874
32874
|
init_dist();
|
|
@@ -33813,10 +33813,13 @@ function timeoutRiskHint(opts) {
|
|
|
33813
33813
|
return lead + `If the host gives up mid-generation the image is still written to disk (and gemini_interact leaves an <image>.json sidecar with the interaction id) \u2014 no rerun needed, just look in the output dir. For a faster in-band result use a Flash model, drop image_size to 1K/2K, or \u2014 in Claude Code \u2014 set MCP_TOOL_TIMEOUT.`;
|
|
33814
33814
|
}
|
|
33815
33815
|
function buildMeta(model, seed, opts) {
|
|
33816
|
-
const meta3 = { model, seed };
|
|
33816
|
+
const meta3 = reportShape({ model, seed }, opts);
|
|
33817
|
+
if (opts.image_size) meta3.image_size = opts.image_size;
|
|
33818
|
+
return meta3;
|
|
33819
|
+
}
|
|
33820
|
+
function reportShape(meta3, opts) {
|
|
33817
33821
|
if (opts.aspect_ratio) meta3.aspect_ratio = opts.aspect_ratio;
|
|
33818
33822
|
if (opts.orientation) meta3.orientation = opts.orientation;
|
|
33819
|
-
if (opts.image_size) meta3.image_size = opts.image_size;
|
|
33820
33823
|
return meta3;
|
|
33821
33824
|
}
|
|
33822
33825
|
async function emitMedia(named, kind, opts, meta3, onWritten) {
|
|
@@ -36194,7 +36197,7 @@ function registerInteractTools(server, client2) {
|
|
|
36194
36197
|
}
|
|
36195
36198
|
});
|
|
36196
36199
|
client2.session.lastInteractionId = r.id;
|
|
36197
|
-
const meta3 = { model, interaction_id: r.id };
|
|
36200
|
+
const meta3 = reportShape({ model, interaction_id: r.id }, { ...args, aspect_ratio: aspectRatio });
|
|
36198
36201
|
if (chainRecovered) meta3.chain_recovered = chainRecovered;
|
|
36199
36202
|
else if (previousInteractionId) meta3.previous_interaction_id = previousInteractionId;
|
|
36200
36203
|
if (continuedFromSidecar) meta3.continued_from_sidecar = true;
|
|
@@ -36306,7 +36309,7 @@ function registerVideoTools(server, client2) {
|
|
|
36306
36309
|
onInteractionStarted: ctx.reportInteraction
|
|
36307
36310
|
}));
|
|
36308
36311
|
client2.session.lastVideoInteractionId = r.id;
|
|
36309
|
-
const meta3 = { model, interaction_id: r.id };
|
|
36312
|
+
const meta3 = reportShape({ model, interaction_id: r.id }, { ...args, aspect_ratio: aspectRatio });
|
|
36310
36313
|
if (previousInteractionId) meta3.previous_interaction_id = previousInteractionId;
|
|
36311
36314
|
if (r.text) meta3.text = r.text;
|
|
36312
36315
|
if (report) meta3.image_inputs = report;
|
package/dist/tools/interact.js
CHANGED
|
@@ -5,7 +5,7 @@ import { ChainedRequest404Error } from '../client.js';
|
|
|
5
5
|
import { slugify, baseName, resolveImagePath, writeSidecar, resolveOutputDir, readImageAsInline } from '../images.js';
|
|
6
6
|
import { resolveImageInputs } from '../inputs.js';
|
|
7
7
|
import { findInteractionImages, latestInteractionId } from '../sidecar.js';
|
|
8
|
-
import { emit, resolveAspectRatio, orientationSchema, ASPECT_RATIOS, IMAGE_SIZES, MODEL_CHOICE_GUIDE, resolveVideoInput, videoPathSchema, timeoutMsSchema, timeoutRiskHint, idempotencyKeySchema, asyncSchema, maxWaitMsSchema, withProgressHeartbeat, assertLocalInputsAvailable, imagesUrlSchema, imagesFileUrisSchema } from './shared.js';
|
|
8
|
+
import { emit, reportShape, resolveAspectRatio, orientationSchema, ASPECT_RATIOS, IMAGE_SIZES, MODEL_CHOICE_GUIDE, resolveVideoInput, videoPathSchema, timeoutMsSchema, timeoutRiskHint, idempotencyKeySchema, asyncSchema, maxWaitMsSchema, withProgressHeartbeat, assertLocalInputsAvailable, imagesUrlSchema, imagesFileUrisSchema } from './shared.js';
|
|
9
9
|
import { fingerprintRequest } from '../jobs.js';
|
|
10
10
|
import { previewLocalInputsUnlessConfirmed, schemaConfirm } from './_confirm.js';
|
|
11
11
|
// The last-interaction id and the written-outputs set used to live here, at
|
|
@@ -259,7 +259,9 @@ export function registerInteractTools(server, client) {
|
|
|
259
259
|
}
|
|
260
260
|
});
|
|
261
261
|
client.session.lastInteractionId = r.id;
|
|
262
|
-
|
|
262
|
+
// `aspectRatio` is the RESOLVED value (see resolveAspectRatio above), so
|
|
263
|
+
// an `orientation: 'portrait'` request can be seen to have become 9:16.
|
|
264
|
+
const meta = reportShape({ model, interaction_id: r.id }, { ...args, aspect_ratio: aspectRatio });
|
|
263
265
|
// On recovery the prior id was NOT used — reporting it as
|
|
264
266
|
// previous_interaction_id would misrepresent what the model saw.
|
|
265
267
|
if (chainRecovered)
|
package/dist/tools/shared.js
CHANGED
|
@@ -446,15 +446,29 @@ export function timeoutRiskHint(opts) {
|
|
|
446
446
|
}
|
|
447
447
|
/** Build the result metadata echoed to the caller (omitting unset optionals). */
|
|
448
448
|
export function buildMeta(model, seed, opts) {
|
|
449
|
-
const meta = { model, seed };
|
|
450
|
-
|
|
451
|
-
|
|
449
|
+
const meta = reportShape({ model, seed }, opts);
|
|
450
|
+
if (opts.image_size)
|
|
451
|
+
meta.image_size = opts.image_size;
|
|
452
|
+
return meta;
|
|
453
|
+
}
|
|
454
|
+
/**
|
|
455
|
+
* Record the shape a generation produced, into any meta object.
|
|
456
|
+
*
|
|
457
|
+
* The RESOLVED ratio, and the `orientation` only when one was actually asked
|
|
458
|
+
* for — so a caller who said "portrait" sees both what they asked and what it
|
|
459
|
+
* became, while a bare `21:9` is not handed back a word nobody used.
|
|
460
|
+
*
|
|
461
|
+
* It lives apart from `buildMeta` because two tools cannot use that function:
|
|
462
|
+
* `gemini_interact` and `gemini_video_generate` build their metas around
|
|
463
|
+
* `interaction_id` and chain state rather than a seed, and so reported no shape
|
|
464
|
+
* at all until #166. Sharing the rule rather than copying it is what keeps
|
|
465
|
+
* those hand-rolled metas from drifting again.
|
|
466
|
+
*/
|
|
467
|
+
export function reportShape(meta, opts) {
|
|
452
468
|
if (opts.aspect_ratio)
|
|
453
469
|
meta.aspect_ratio = opts.aspect_ratio;
|
|
454
470
|
if (opts.orientation)
|
|
455
471
|
meta.orientation = opts.orientation;
|
|
456
|
-
if (opts.image_size)
|
|
457
|
-
meta.image_size = opts.image_size;
|
|
458
472
|
return meta;
|
|
459
473
|
}
|
|
460
474
|
/**
|
package/dist/tools/video.js
CHANGED
|
@@ -3,7 +3,7 @@ import { McpToolError } from '@chrischall/mcp-utils';
|
|
|
3
3
|
import { slugify, baseName } from '../images.js';
|
|
4
4
|
import { resolveImageInputs } from '../inputs.js';
|
|
5
5
|
import { DEFAULT_VIDEO_MODEL } from '../models.js';
|
|
6
|
-
import { emitMedia, resolveAspectRatio, orientationSchema, timeoutMsSchema, idempotencyKeySchema, asyncSchema, maxWaitMsSchema, withProgressHeartbeat, assertLocalInputsAvailable, imagesUrlSchema, imagesFileUrisSchema } from './shared.js';
|
|
6
|
+
import { emitMedia, reportShape, resolveAspectRatio, orientationSchema, timeoutMsSchema, idempotencyKeySchema, asyncSchema, maxWaitMsSchema, withProgressHeartbeat, assertLocalInputsAvailable, imagesUrlSchema, imagesFileUrisSchema } from './shared.js';
|
|
7
7
|
import { fingerprintRequest } from '../jobs.js';
|
|
8
8
|
import { previewLocalInputsUnlessConfirmed, schemaConfirm } from './_confirm.js';
|
|
9
9
|
/** omni's own aspect-ratio enum — NOT the image tools' ASPECT_RATIOS. */
|
|
@@ -100,7 +100,9 @@ export function registerVideoTools(server, client) {
|
|
|
100
100
|
onInteractionStarted: ctx.reportInteraction,
|
|
101
101
|
}));
|
|
102
102
|
client.session.lastVideoInteractionId = r.id;
|
|
103
|
-
|
|
103
|
+
// The RESOLVED ratio: omni takes only 16:9/9:16, so a caller who asked
|
|
104
|
+
// in words can see which of the two their request became.
|
|
105
|
+
const meta = reportShape({ model, interaction_id: r.id }, { ...args, aspect_ratio: aspectRatio });
|
|
104
106
|
if (previousInteractionId)
|
|
105
107
|
meta.previous_interaction_id = previousInteractionId;
|
|
106
108
|
if (r.text)
|
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 = '1.
|
|
2
|
+
export const VERSION = '1.10.0'; // x-release-please-version
|
package/mint.yaml
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
version: 1
|
|
2
|
+
name: Gemini Images
|
|
3
|
+
slug: gemini
|
|
4
|
+
summary: >-
|
|
5
|
+
Generate and edit images with Google Gemini image models (Nano Banana /
|
|
6
|
+
Nano Banana Pro) via natural language prompts
|
|
7
|
+
env:
|
|
8
|
+
- name: GEMINI_API_KEY
|
|
9
|
+
secret: true
|
|
10
|
+
required: true
|
|
11
|
+
help: >-
|
|
12
|
+
Your Google Gemini API key (aistudio.google.com/apikey)
|
|
13
|
+
- name: GEMINI_IMAGE_MODEL
|
|
14
|
+
required: false
|
|
15
|
+
help: >-
|
|
16
|
+
Override the default image model (default: gemini-3.1-flash-image)
|
|
17
|
+
- name: GEMINI_OUTPUT_DIR
|
|
18
|
+
required: false
|
|
19
|
+
help: >-
|
|
20
|
+
Default directory for generated images (default: current working
|
|
21
|
+
directory)
|
|
22
|
+
- name: GEMINI_INPUT_DIR
|
|
23
|
+
required: false
|
|
24
|
+
help: >-
|
|
25
|
+
Directory to resolve bare input-image filenames against
|
|
26
|
+
- name: GEMINI_TIMEOUT_MS
|
|
27
|
+
required: false
|
|
28
|
+
help: >-
|
|
29
|
+
Upstream request timeout in ms (default: 60000, or 120000 for 4K output)
|
|
30
|
+
- name: GEMINI_CHAIN_RETRY_MS
|
|
31
|
+
required: false
|
|
32
|
+
help: >-
|
|
33
|
+
Retry budget in milliseconds for a chained request that 404s while the
|
|
34
|
+
upstream result settles (default 120000).
|
|
35
|
+
- name: GEMINI_HEARTBEAT_MS
|
|
36
|
+
required: false
|
|
37
|
+
help: >-
|
|
38
|
+
How often, in milliseconds, to emit a progress notification while a
|
|
39
|
+
generation is in flight. Hosts reset their tools/call timeout on progress,
|
|
40
|
+
so this lets a long 4K/Pro generation outlive the default budget.
|
|
41
|
+
egress:
|
|
42
|
+
allow:
|
|
43
|
+
# Only hosts the SERVER process actually fetches. Hosts that appear
|
|
44
|
+
# solely in a URL this server BUILDS and returns are excluded.
|
|
45
|
+
- generativelanguage.googleapis.com
|
|
46
|
+
#
|
|
47
|
+
# NOTE — this server also reaches at least one host determined at
|
|
48
|
+
# RUNTIME, which cannot appear as a literal here:
|
|
49
|
+
# - a signed upload URL returned by the API (often storage.googleapis.com / s3)
|
|
50
|
+
# - a media/CDN host supplied at runtime
|
|
51
|
+
# Confirm the concrete host(s) against a live run and add them, or
|
|
52
|
+
# the isolated tier will block the call.
|
|
53
|
+
#
|
|
54
|
+
# Also: the images_url argument makes this server fetch an ARBITRARY
|
|
55
|
+
# caller-supplied https host. That cannot be enumerated in advance, so on
|
|
56
|
+
# the isolated tier either allow the hosts you intend to pass, or expect
|
|
57
|
+
# image-by-URL to be blocked there.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@chrischall/gemini-mcp",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.10.0",
|
|
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>",
|
|
@@ -33,7 +33,8 @@
|
|
|
33
33
|
".claude-plugin",
|
|
34
34
|
"skills/",
|
|
35
35
|
".mcp.json",
|
|
36
|
-
"server.json"
|
|
36
|
+
"server.json",
|
|
37
|
+
"mint.yaml"
|
|
37
38
|
],
|
|
38
39
|
"scripts": {
|
|
39
40
|
"build": "tsc && npm run bundle",
|
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": "1.
|
|
9
|
+
"version": "1.10.0",
|
|
10
10
|
"packages": [
|
|
11
11
|
{
|
|
12
12
|
"registryType": "npm",
|
|
13
13
|
"identifier": "@chrischall/gemini-mcp",
|
|
14
|
-
"version": "1.
|
|
14
|
+
"version": "1.10.0",
|
|
15
15
|
"transport": {
|
|
16
16
|
"type": "stdio"
|
|
17
17
|
},
|