@chrischall/gemini-mcp 2.3.4 → 2.4.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.
- package/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +1 -1
- package/.mcp.json +5 -2
- package/README.md +20 -17
- package/dist/bundle.js +31785 -312
- package/dist/client.js +12 -3
- package/dist/fetch-image.js +70 -138
- package/dist/images.js +16 -23
- package/dist/media-url.js +4 -59
- package/dist/models.js +11 -6
- package/dist/pricing.js +4 -0
- package/dist/storage/media.js +3 -15
- package/dist/tools/_confirm.js +13 -33
- package/dist/tools/files.js +8 -8
- package/dist/tools/interact.js +1 -1
- package/dist/tools/library.js +6 -6
- package/dist/tools/shared.js +7 -4
- package/dist/tools/uploads.js +1 -1
- package/dist/version.js +1 -1
- package/mint.yaml +19 -3
- package/package.json +4 -3
- package/server.json +4 -4
- package/skills/gemini-mcp/SKILL.md +37 -18
package/dist/tools/library.js
CHANGED
|
@@ -119,10 +119,10 @@ export function registerLibraryTools(server, client) {
|
|
|
119
119
|
tool: 'gemini_delete_character',
|
|
120
120
|
action: 'character.delete',
|
|
121
121
|
message: 'Review and confirm this deletion:',
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
path: `characters/${args.name}`,
|
|
122
|
+
summary: 'Delete a saved character (its reference image and description)',
|
|
123
|
+
account: undefined,
|
|
125
124
|
target: args.name,
|
|
125
|
+
request: { method: 'DELETE', path: `characters/${args.name}` },
|
|
126
126
|
payload: { name: args.name },
|
|
127
127
|
args,
|
|
128
128
|
confirmToken: args.confirmToken,
|
|
@@ -189,10 +189,10 @@ export function registerLibraryTools(server, client) {
|
|
|
189
189
|
tool: 'gemini_delete_style',
|
|
190
190
|
action: 'style.delete',
|
|
191
191
|
message: 'Review and confirm this deletion:',
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
path: `styles/${args.name}`,
|
|
192
|
+
summary: 'Delete a saved style preset',
|
|
193
|
+
account: undefined,
|
|
195
194
|
target: args.name,
|
|
195
|
+
request: { method: 'DELETE', path: `styles/${args.name}` },
|
|
196
196
|
payload: { name: args.name },
|
|
197
197
|
args,
|
|
198
198
|
confirmToken: args.confirmToken,
|
package/dist/tools/shared.js
CHANGED
|
@@ -14,7 +14,10 @@ import { buildZip } from '../zip.js';
|
|
|
14
14
|
const DEFAULT_SINK = createDiskSink();
|
|
15
15
|
/** Supported output aspect ratios (Gemini image API). */
|
|
16
16
|
export const ASPECT_RATIOS = ['1:1', '2:3', '3:2', '3:4', '4:3', '4:5', '5:4', '9:16', '16:9', '21:9', '1:4', '4:1', '1:8', '8:1'];
|
|
17
|
-
/**
|
|
17
|
+
/**
|
|
18
|
+
* Supported output resolutions. `512` (0.5K) is gemini-3.1-flash-image only — Nano Banana 2.1, the
|
|
19
|
+
* default, documents 1K/2K/4K — while `1K`/`2K`/`4K` work on all image models.
|
|
20
|
+
*/
|
|
18
21
|
export const IMAGE_SIZES = ['512', '1K', '2K', '4K'];
|
|
19
22
|
/**
|
|
20
23
|
* The words people actually use for shape, as a shorthand over
|
|
@@ -77,7 +80,7 @@ export const orientationSchema = z
|
|
|
77
80
|
* When to pick which Nano Banana model — shared by every tool's `model` param
|
|
78
81
|
* so the guidance can't drift between them.
|
|
79
82
|
*/
|
|
80
|
-
export const MODEL_CHOICE_GUIDE = 'gemini-
|
|
83
|
+
export const MODEL_CHOICE_GUIDE = 'gemini-nano-banana-2.1 (Nano Banana 2.1, the default) is the generalist: fast, 4K, reliable text, strong ' +
|
|
81
84
|
'multi-reference consistency. gemini-3-pro-image (Pro) is for the hardest work — best world knowledge, brand ' +
|
|
82
85
|
'precision. gemini-3.1-flash-lite-image (Lite) is cheapest: 1K only, no search grounding.';
|
|
83
86
|
/**
|
|
@@ -299,7 +302,7 @@ export const sharedImageSchema = {
|
|
|
299
302
|
.optional()
|
|
300
303
|
.describe('Exact output aspect ratio. For a plain landscape/portrait/square request, `orientation` is the shorthand; this wins if both are given.'),
|
|
301
304
|
orientation: orientationSchema,
|
|
302
|
-
image_size: z.enum(IMAGE_SIZES).optional().describe('Output resolution (512 = 0.5K,
|
|
305
|
+
image_size: z.enum(IMAGE_SIZES).optional().describe('Output resolution (512 = 0.5K, gemini-3.1-flash-image only)'),
|
|
303
306
|
output_dir: z.string().optional().describe('Directory to write images to (default: $GEMINI_OUTPUT_DIR or ~/Downloads/gemini-mcp)'),
|
|
304
307
|
inline: z.boolean().optional().describe('Return the image as an inline image block you can SEE, instead of a path (stdio) or link (hosted). The default costs nothing to carry and hands back a reference you can reuse; use this when you need to check the result yourself. On the hosted connector gemini_view_media does the same for an image you already have'),
|
|
305
308
|
seed: z.number().int().optional().describe('Seed for reproducible generation; random if omitted'),
|
|
@@ -544,7 +547,7 @@ export async function emitMedia(named, kind, opts, meta, onWritten) {
|
|
|
544
547
|
const unavailable = persisted.some((p) => p.unavailable)
|
|
545
548
|
? {
|
|
546
549
|
media_url_unavailable: 'The media was stored but no public URL could be generated for it, so the values above are bare object keys, not links. ' +
|
|
547
|
-
'This is a
|
|
550
|
+
'This is a hosting misconfiguration — the host did not provide a blob store (mcp-host injects MCP_BLOB_BASE_URL and MCP_BLOB_SIGNING_KEY) — so ask the server operator, or use inline: true to receive the bytes directly.',
|
|
548
551
|
}
|
|
549
552
|
: {};
|
|
550
553
|
const detailed = persisted.filter((p) => p.key !== undefined);
|
package/dist/tools/uploads.js
CHANGED
|
@@ -86,7 +86,7 @@ export function registerUploadUrlTools(server, client) {
|
|
|
86
86
|
'(the signature in the URL is the auth, and it covers the content type). On a 2xx, reference the `r2_key` from ' +
|
|
87
87
|
'THIS result — not the PUT response: images_r2_keys on generation tools (master_images_r2_keys on ' +
|
|
88
88
|
'gemini_image_set), gemini_save_character to keep it with no expiry, or gemini_upload_file({ r2_key }) for a ' +
|
|
89
|
-
'~48h files/… reference. Uploads themselves follow the
|
|
89
|
+
'~48h files/… reference. Uploads themselves follow the host\'s blob-store retention schedule.',
|
|
90
90
|
});
|
|
91
91
|
});
|
|
92
92
|
}
|
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.
|
|
2
|
+
export const VERSION = '2.4.1'; // x-release-please-version
|
package/mint.yaml
CHANGED
|
@@ -13,16 +13,28 @@ env:
|
|
|
13
13
|
- name: GEMINI_IMAGE_MODEL
|
|
14
14
|
required: false
|
|
15
15
|
help: >-
|
|
16
|
-
Override the default image model (default: gemini-
|
|
16
|
+
Override the default image model (default: gemini-nano-banana-2.1)
|
|
17
17
|
- name: GEMINI_OUTPUT_DIR
|
|
18
18
|
required: false
|
|
19
19
|
help: >-
|
|
20
|
-
Default directory for generated images (default:
|
|
21
|
-
|
|
20
|
+
Default directory for generated images (default: ~/Downloads/gemini-mcp,
|
|
21
|
+
not the cwd). When set, a per-call output_dir must be inside it.
|
|
22
22
|
- name: GEMINI_INPUT_DIR
|
|
23
23
|
required: false
|
|
24
24
|
help: >-
|
|
25
25
|
Directory to resolve bare input-image filenames against
|
|
26
|
+
- name: GEMINI_UPLOAD_DIR
|
|
27
|
+
required: false
|
|
28
|
+
help: >-
|
|
29
|
+
Directories (path.delimiter-separated) that local files uploaded to the
|
|
30
|
+
Gemini Files API must come from. Mostly a local-install knob: on a hosted
|
|
31
|
+
server, uploads come from gemini_get_upload_url instead.
|
|
32
|
+
- name: GEMINI_REFERENCE_DIR
|
|
33
|
+
required: false
|
|
34
|
+
help: >-
|
|
35
|
+
Directories (path.delimiter-separated) that local reference images must
|
|
36
|
+
come from (else GEMINI_UPLOAD_DIR). Unset on a hosted server, only
|
|
37
|
+
$MCP_DATA_DIR/uploads is allowed, so leave it unset there.
|
|
26
38
|
- name: GEMINI_TIMEOUT_MS
|
|
27
39
|
required: false
|
|
28
40
|
help: >-
|
|
@@ -38,6 +50,10 @@ env:
|
|
|
38
50
|
How often, in milliseconds, to emit a progress notification while a
|
|
39
51
|
generation is in flight. Hosts reset their tools/call timeout on progress,
|
|
40
52
|
so this lets a long 4K/Pro generation outlive the default budget.
|
|
53
|
+
- name: GEMINI_DEBUG
|
|
54
|
+
required: false
|
|
55
|
+
help: >-
|
|
56
|
+
When set, emit heartbeat diagnostics to stderr. Off by default.
|
|
41
57
|
- name: GEMINI_RATE_CARD
|
|
42
58
|
required: false
|
|
43
59
|
help: >-
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@chrischall/gemini-mcp",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.4.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>",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
],
|
|
39
39
|
"scripts": {
|
|
40
40
|
"build": "tsc && npm run bundle",
|
|
41
|
-
"bundle": "esbuild src/index.ts --bundle --alias:zod/v4=./node_modules/zod/v4/index.cjs --platform=node --format=esm --external:dotenv --outfile=dist/bundle.js",
|
|
41
|
+
"bundle": "esbuild src/index.ts --bundle --alias:zod/v4=./node_modules/zod/v4/index.cjs --platform=node --format=esm --external:dotenv --banner:js=\"import { createRequire as __createRequire } from 'module'; import { fileURLToPath as __fileURLToPath } from 'url'; import { dirname as __pathDirname } from 'path'; const require = __createRequire(import.meta.url); const __filename = __fileURLToPath(import.meta.url); const __dirname = __pathDirname(__filename);\" --outfile=dist/bundle.js",
|
|
42
42
|
"dev": "node dist/index.js",
|
|
43
43
|
"test": "npm run typecheck && vitest run",
|
|
44
44
|
"test:watch": "vitest",
|
|
@@ -46,9 +46,10 @@
|
|
|
46
46
|
"typecheck": "tsc -p tsconfig.test.json"
|
|
47
47
|
},
|
|
48
48
|
"dependencies": {
|
|
49
|
-
"@chrischall/mcp-utils": "^3.0.
|
|
49
|
+
"@chrischall/mcp-utils": "^3.0.3",
|
|
50
50
|
"@modelcontextprotocol/server": "^2.3.0",
|
|
51
51
|
"dotenv": "^18.0.2",
|
|
52
|
+
"undici": "^8.12.2",
|
|
52
53
|
"zod": "^4.6.5"
|
|
53
54
|
},
|
|
54
55
|
"devDependencies": {
|
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.
|
|
9
|
+
"version": "2.4.1",
|
|
10
10
|
"packages": [
|
|
11
11
|
{
|
|
12
12
|
"registryType": "npm",
|
|
13
13
|
"identifier": "@chrischall/gemini-mcp",
|
|
14
|
-
"version": "2.
|
|
14
|
+
"version": "2.4.1",
|
|
15
15
|
"transport": {
|
|
16
16
|
"type": "stdio"
|
|
17
17
|
},
|
|
@@ -25,14 +25,14 @@
|
|
|
25
25
|
},
|
|
26
26
|
{
|
|
27
27
|
"name": "GEMINI_IMAGE_MODEL",
|
|
28
|
-
"description": "Override the default image model (default: gemini-
|
|
28
|
+
"description": "Override the default image model (default: gemini-nano-banana-2.1)",
|
|
29
29
|
"isRequired": false,
|
|
30
30
|
"format": "string",
|
|
31
31
|
"isSecret": false
|
|
32
32
|
},
|
|
33
33
|
{
|
|
34
34
|
"name": "GEMINI_OUTPUT_DIR",
|
|
35
|
-
"description": "Default directory for generated images (default:
|
|
35
|
+
"description": "Default directory for generated images (default: ~/Downloads/gemini-mcp). When set, a per-call output_dir must be inside it.",
|
|
36
36
|
"isRequired": false,
|
|
37
37
|
"format": "string",
|
|
38
38
|
"isSecret": false
|
|
@@ -69,7 +69,7 @@ Note: Image generation requires a billing-enabled Google Cloud project.
|
|
|
69
69
|
| Variable | Required | Description |
|
|
70
70
|
|---|---|---|
|
|
71
71
|
| `GEMINI_API_KEY` | Yes | Your Google Gemini API key |
|
|
72
|
-
| `GEMINI_IMAGE_MODEL` | No | Override the default image model (default: `gemini-
|
|
72
|
+
| `GEMINI_IMAGE_MODEL` | No | Override the default image model (default: `gemini-nano-banana-2.1`) |
|
|
73
73
|
| `GEMINI_OUTPUT_DIR` | No | Default directory for saved images (default: ~/Downloads/gemini-mcp) |
|
|
74
74
|
| `GEMINI_INPUT_DIR` | No | Directory to resolve bare input-image filenames against (e.g. point at Cowork's `uploads/` folder so `images: ["house.jpg"]` works) |
|
|
75
75
|
|
|
@@ -84,7 +84,8 @@ Note: Image generation requires a billing-enabled Google Cloud project.
|
|
|
84
84
|
|
|
85
85
|
| Model | When to use | Reference-image caps (of 14 max) |
|
|
86
86
|
|-------|-------------|----------------------------------|
|
|
87
|
-
| `gemini-
|
|
87
|
+
| `gemini-nano-banana-2.1` (Nano Banana 2.1, **default**) | The versatile generalist workhorse for all tasks — an update to Nano Banana 2 with better visual quality, prompt adherence, character consistency and text rendering; 1K/2K/4K, $0.0336 per 1K image | up to 10 objects + 4 characters |
|
|
88
|
+
| `gemini-3.1-flash-image` (Nano Banana 2, **deprecated** 2026-10-06, no shutdown date yet) | The previous generalist workhorse — balances speed with state-of-the-art 4K generation, world knowledge, and reliable text rendering; excels at multi-reference-image processing and consistency. Only model with video input + image_search grounding | 10 objects + 4 characters + 3 style refs |
|
|
88
89
|
| `gemini-3-pro-image` (Nano Banana Pro) | The premium choice for the most complex visual tasks — highest world knowledge, advanced localization, accurate brand consistency, precision creative control | 6 objects + 5 characters |
|
|
89
90
|
| `gemini-3.1-flash-lite-image` (Nano Banana 2 Lite) | The fastest/cheapest for simple tasks — 1K output only, no Google Search grounding | 14 objects (no character consistency) |
|
|
90
91
|
|
|
@@ -95,7 +96,7 @@ Note: Image generation requires a billing-enabled Google Cloud project.
|
|
|
95
96
|
| `gemini_image_edit(prompt, images_url?, images_file_uris?, images?, images_base64?, google_search?, seed?, filename?, model?, aspect_ratio?, image_size?, thinking_level?, output_dir?, inline?)` | Edit or compose input image(s) with a text instruction. Requires ≥1 input from any of the four reference forms |
|
|
96
97
|
| `gemini_image_set(master_prompt, scenes? \| count?, reference_mode?, master_images_url?, master_images_file_uris?, master_images?, master_images_base64?, google_search?, seed?, basename?, model?, thinking_level?, ...)` | Master image (optionally seeded from a reference photo) plus N consistent images referencing it. `master_images_url` / `master_images_file_uris` are resolved **once** and passed to the master *and* every scene |
|
|
97
98
|
|
|
98
|
-
### Reference images —
|
|
99
|
+
### Reference images — several ways in, one that costs context
|
|
99
100
|
|
|
100
101
|
These apply to **every** tool that takes a reference image: the four image tools, plus
|
|
101
102
|
`gemini_video_generate` (reference stills) and `gemini_music_generate`.
|
|
@@ -104,7 +105,9 @@ These apply to **every** tool that takes a reference image: the four image tools
|
|
|
104
105
|
|---|---|---|
|
|
105
106
|
| `images_url` (`master_images_url`) | the **server** downloads the https URL | none |
|
|
106
107
|
| `images_file_uris` (`master_images_file_uris`) | a `files/<id>` reference from `gemini_upload_file` | none |
|
|
108
|
+
| `images_r2_keys` (`master_images_r2_keys`) | the server reads its **own store** — an `r2_key` from `gemini_get_upload_url` or a generation result (hosted deployments only) | none |
|
|
107
109
|
| `images` | read off local disk (stdio builds only) | none |
|
|
110
|
+
| `characters` / `style` | saved library entries, attached by name (hosted deployments only) | none |
|
|
108
111
|
| `images_base64` | **through the tool-call JSON** | **~14k tokens per JPEG** |
|
|
109
112
|
|
|
110
113
|
**Reach for `images_base64` last.** It costs ~14k tokens per modest photo, and a truncated file
|
|
@@ -129,17 +132,32 @@ not an error.
|
|
|
129
132
|
| `gemini_list_files(page_size?)` | List current uploads with MIME types and expiry |
|
|
130
133
|
| `gemini_delete_file(file_uri, confirmToken?)` | Delete an upload before its ~48h expiry (confirmed first — see Notes) |
|
|
131
134
|
|
|
132
|
-
|
|
133
|
-
|
|
135
|
+
### Hosted deployment only
|
|
136
|
+
|
|
137
|
+
A hosted deployment has no filesystem, so these tools stand in for it. There is no `POST /upload`
|
|
138
|
+
endpoint (it went with the retired Worker connector): an agent with a shell uploads through a
|
|
139
|
+
signed URL instead.
|
|
140
|
+
|
|
141
|
+
| Tool | Description |
|
|
142
|
+
|------|-------------|
|
|
143
|
+
| `gemini_get_upload_url(filename, content_type)` | Mint a ~10-minute signed **PUT** URL. `curl -X PUT -H "Content-Type: <type>" --data-binary @file "<upload_url>"` needs no auth header. The result's `r2_key` goes to `images_r2_keys`, `gemini_save_character`, or `gemini_upload_file({ r2_key })` |
|
|
144
|
+
| `gemini_sign_media(r2_key)` | Mint a fresh signed link for stored media (links live at most 24h) — an expired link is not a reason to re-generate |
|
|
145
|
+
| `gemini_view_media(r2_key)` | Return a stored image inline so you can look at what was made before refining it |
|
|
146
|
+
| `gemini_list_recent_media(limit?, since_day?)` | Recent stored media with prompt, model and interaction id — how a lost result or turn is found again |
|
|
147
|
+
| `gemini_save_character` / `gemini_list_characters` / `gemini_delete_character` | Per-account character library (reference image + description, no expiry); attach with `characters: ["name"]` |
|
|
148
|
+
| `gemini_save_style` / `gemini_list_styles` / `gemini_delete_style` | Per-account style presets (prompt fragment, optional reference image, no expiry); attach with `style: "name"` |
|
|
134
149
|
|
|
135
150
|
```bash
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
#
|
|
151
|
+
# 1. tool: gemini_get_upload_url { filename: "photo.jpg", content_type: "image/jpeg" }
|
|
152
|
+
# → { upload_url, r2_key, expires_at, curl_hint }
|
|
153
|
+
# 2. shell:
|
|
154
|
+
curl -sS -X PUT -H "Content-Type: image/jpeg" --data-binary @photo.jpg "$UPLOAD_URL"
|
|
155
|
+
# 3. tool: gemini_image_edit { prompt: "make it winter", images_r2_keys: ["<r2_key from step 1>"] }
|
|
141
156
|
```
|
|
142
157
|
|
|
158
|
+
Uploads are raster images only, capped at 15MB, and follow the host's retention schedule; save
|
|
159
|
+
anything you want to keep with `gemini_save_character`.
|
|
160
|
+
|
|
143
161
|
### Multi-turn (Interactions API)
|
|
144
162
|
| Tool | Description |
|
|
145
163
|
|------|-------------|
|
|
@@ -182,15 +200,16 @@ gemini_image_edit(prompt: "make the background blue", images_url: ["https://exam
|
|
|
182
200
|
→ the server fetches the URL itself; returns path to edited PNG
|
|
183
201
|
```
|
|
184
202
|
|
|
185
|
-
**Reuse one photo across many generations (hosted
|
|
203
|
+
**Reuse one photo across many generations (hosted deployment, agent with a shell):**
|
|
186
204
|
```
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
gemini_image_edit(prompt: "make it winter",
|
|
192
|
-
gemini_image_edit(prompt: "make it sunrise",
|
|
193
|
-
→ two edits, one upload, zero image bytes in context.
|
|
205
|
+
gemini_get_upload_url(filename: "photo.jpg", content_type: "image/jpeg")
|
|
206
|
+
→ { upload_url, r2_key: "up/…/photo.jpg" }
|
|
207
|
+
$ curl -sS -X PUT -H "Content-Type: image/jpeg" --data-binary @photo.jpg "$UPLOAD_URL"
|
|
208
|
+
|
|
209
|
+
gemini_image_edit(prompt: "make it winter", images_r2_keys: ["up/…/photo.jpg"])
|
|
210
|
+
gemini_image_edit(prompt: "make it sunrise", images_r2_keys: ["up/…/photo.jpg"])
|
|
211
|
+
→ two edits, one upload, zero image bytes in context. To keep the photo past the
|
|
212
|
+
upload retention window, gemini_save_character it and pass characters: ["name"].
|
|
194
213
|
```
|
|
195
214
|
|
|
196
215
|
**Generate a consistent set (master + scenes):**
|