
Gemini Mcp
io.github.chrischall由 GitHub 账号 chrischall 发布v2.5.1更新于 Nov 7, 2026
Generate and edit images with Google Gemini (Nano Banana / Nano Banana Pro) image models.
概览
本地 MCP 服务器,让助手用 Google Gemini 模型生成和编辑图片、视频与音乐,并把结果保存到磁盘。
- 可以做什么
- 列出可用的 Gemini 图片模型及当前默认模型
- 根据提示词生成图片,进行编辑或多图合成,并基于主提示词生成风格一致的图片组
- 通过 Interactions API 多轮迭代优化图片,支持异步任务与结果轮询
- 生成短视频和音乐,分别以 MP4 和 MP3 写入磁盘
- 上传、列出和删除 Files API 引用文件,并报告 token 用量与估算的美元成本
- 适用场景
- 适合希望助手在对话中直接生成或反复打磨图片、短视频和音乐的场景,包括需要保持角色或场景一致的图片组,以及需要异步轮询的 4K 或 Pro 长耗时生成。
- 运行要求
- 以 stdio 方式在本地运行,通常通过 npx 启动 npm 包。需要在 GEMINI_API_KEY 中提供 Google Gemini API 密钥,并能访问 Gemini API 网络。可选变量用于设置图片模型、输出与输入目录、超时、心跳间隔和自定义价格表。
安装
在 SourceWeft 中
- 打开 控制台中的 Gemini Mcp,将其添加到工作区。
- 为需要使用其工具的对话启用该服务。
Desktop only,通过 STDIO。 STDIO 服务会启动本地进程,因此需要 SourceWeft 桌面宿主。
其他 MCP 客户端
参照 仓库 中的启动说明。
README
gemini-mcp
MCP server for Google Gemini media generation. Exposes thirteen tools to Claude over stdio: list available models, generate/edit/compose images, generate a consistent set of images from a master prompt, multi-turn image refinement (Interactions API), video generation (omni), music generation (Lyria), an async result poll for long generations, and Files API upload/list/delete for reusable image references. Output is written to disk by default (path returned) or returned inline as base64. Built on the Gemini v1beta API (generativelanguage.googleapis.com) using the Nano Banana / Nano Banana Pro (images), omni (video), and Lyria (music) model families.
Developed and maintained by AI (Claude Code).
Environment Variables
Confirmations
Sending a local file to Google (the images / master_images / video_path inputs, or
gemini_upload_file's path) and every delete ask for confirmation first. A client that can
show a confirmation prompt (Claude Code) gets the real prompt, unless MCP_CONFIRM_ELICITATION=off.
Elsewhere the first call does
nothing and returns a preview (the resolved local paths with their MIME types and sizes, or the
method/path being deleted) plus a confirmToken; only a repeat call with the same arguments and
that token proceeds. The token is single-use, expires, and is bound to the exact arguments — a
changed prompt or a swapped file between the two calls is refused. Pure text prompts, URLs,
files/ references and base64 inputs are not gated.
Long generations and client timeouts
4K / Pro-model generations can outrun an MCP host's own tools/call timeout (error -32001).
The server sends notifications/progress heartbeats so hosts that reset their timeout on
progress wait it out. If the host still gives up, the server-side generation usually completes
anyway: the image is written to the output dir, gemini_interact also writes an
<image>.json sidecar recording the interaction_id, and continue_last: true resumes the
interaction the lost response belonged to.
When a chained call 404s
A 404 on a request carrying previous_interaction_id is not proof the chain expired. The
only 404 body observed live is generic — "Requested entity was not found." — and never names
which entity. An unknown or renamed model id, and an expired Files API files/… uri
(~48h TTL), return exactly the same thing. So the server no longer asserts a cause it can't
establish: the upstream text is surfaced verbatim, and gemini_interact runs an experiment to
find out which it was.
Most often the id isn't missing at all — it just isn't visible yet. The interactions store is
eventually consistent, and a freshly created id can 404 while the same id resolves fine minutes
later; heavy turns (4K, Pro, thinking_level: high) are the likeliest to hit it, which is
exactly the turn you most want to chain from. So a chained 404 is retried with exponential
backoff for up to 120s (GEMINI_CHAIN_RETRY_MS) before anything is declared broken. The
404 generates nothing and isn't billed, so the wait costs only time.
After that budget is spent, the tool looks up that id's sidecar, re-attaches the image it produced, and re-issues the request without the chain:
- The re-issue succeeds → the chain really was the problem, and you get your image anyway,
reported as
chain_recovered: { expired_interaction_id, reanchored_on }. The 404'd attempt generates nothing, so this costs the one generation you'd have paid for re-anchoring manually. - The re-issue 404s too → the interaction id was never the cause. You get told exactly that,
with the upstream text, and pointed at the model id and any
files/…uri instead of being sent to chase an interaction that was fine all along. - No sidecar matches the dead id → the original error, rather than a guess. Re-anchoring on the wrong picture would silently corrupt the edit.
Separately, continue_last no longer dies with the server process: with no in-memory id it
resumes from the newest <image>.json sidecar in the output dir and reports
continued_from_sidecar: true. That case was never an expired chain at all — the interaction
was alive upstream the whole time; only our memory of its id was gone.
For hosts whose timeout can't be tamed (e.g. Claude Desktop, a fixed ~30s cap that ignores progress), two guards make re-issuing safe and unnecessary:
async: truereturns ajob_idimmediately instead of the image, so the call can't time out at all; pollgemini_get_resultwith thejob_iduntil it'sdone.idempotency_keymakes a repeat call idempotent — a retry with the same key returns the recorded result (reused: true) instead of billing a second generation. (Even without a key, two identical in-flight calls are deduplicated automatically.)
Tools
Generation tools also share three throughput/latency controls: async: true (return a job_id
immediately), max_wait_ms (wait up to a budget, then hand back the job_id — fast results stay
in-band, slow batches never trip the host timeout), and idempotency_key (a retry returns the
recorded result instead of re-billing). On a hosted deployment, a gemini_image_set result with
more than one image also carries a bundle_url — one signed URL for a zip of every image in
the set. Like every hosted link it lives at most 24h (the host's blob-store ceiling);
gemini_sign_media re-mints an expired one. (A set too large to
zip safely in memory skips the bundle and says so via bundle_skipped; the per-image
links are unaffected.)
Seeing your images (hosted)
On a hosted deployment there is no filesystem, so a generated image has to come back as something you can open. It does: every result includes a URL, with no configuration.
Those links need no auth header — the signature is in the URL — so they work in a browser, in
curl, and in a chat message. They expire after at most 24h — the host's blob store refuses a
longer signature — and the objects behind them are swept on the host's retention schedule. The
r2_key is the durable handle for that window:
gemini_sign_media(hosted deployments only) mints a fresh signed URL from anr2_key, so an expired link never forces you to re-generate — and re-pay for — the image.- The interaction id is stored beside each image, so a hosted deployment recovers a lost
turn the way the local one does:
continue_last: truesurvives a restart, a chained 404 is re-anchored on the image that interaction produced, andgemini_list_recent_mediashows the prompt, model and interaction id for every stored object rather than a wall of keys. gemini_view_media(hosted deployments only) returns the image itself, inline, from anr2_key. A link is not something a model can look at, so without this a generate → refine loop runs blind. It is a separate call rather than bytes on every result: you pay image tokens only on the turns you actually look.gemini_upload_filewithr2_keyturns media this server generated into a Files API reference (the server reads it back with its own key — no signature for you to mint), so a generated image can become the reference image for the next generation in one cheap call.- Idempotent replays (
idempotency_key) re-mint the URLs inside the recorded result before returning it, so a reused result never carries a dead link.
Why this matters: MCP's inline image content blocks (inline: true) are visible to the
assistant but many chat clients never render them to the user, and the assistant cannot
extract bytes back out of its own context to save them elsewhere. A generation could bill
successfully and be invisible. A URL is the portable answer; inline remains available, but
it is no longer the only way to receive media.
How the bytes are served
The host stores each generated object and serves it back at a signed, expiring
URL — https://<host>/b/<account>/gemini/<key>?exp=&sig=. No setup, and no auth
header: the signature in the link is the authorization, so curl and a browser
both work.
Auth is a signed, expiring URL rather than an unlisted key. Random keys would
be simpler, but they never expire and never revoke: anything that ever logged or forwarded the
link keeps working forever. A signature scopes access to one object with a deadline, and
rotating the host's signing key (MCP_BLOB_SIGNING_KEY, which mcp-host injects together with
MCP_BLOB_BASE_URL; this server never chooses either) invalidates every outstanding link at
once. The tradeoff is that links are long and cannot be shortened by hand.
For assistants relaying a result
Show the user the URL. If your sandbox has network egress to the host, fetching it
and attaching the bytes as a file gives the nicest result; otherwise present the link itself.
Whether a given client renders  markdown inline varies by client — a bare URL is the
safe form, and a markdown link is a reasonable enhancement where you know it renders.
Retention
Retention is the host's, not a setting of this server. On mcp-host, the blob store prunes
generated media (gen/) and signed uploads (up/) on its own schedule (see mcp-host
docs/BLOB-STORE.md; default 30 days), while the character/style library (lib/) is written as
retention-exempt, so saved entries never expire. Every signed link is clamped to the store's
24h ceiling, so it never outlives what the store will honour; gemini_sign_media re-mints one
for as long as the object exists. The variables this server reads for it are injected by the
host: MCP_BLOB_BASE_URL and MCP_BLOB_SIGNING_KEY.
Prompts are stored too. Each generated object on a hosted deployment gets a small JSON
record beside it holding the prompt (first 500 characters), model and interaction id — that is
what gemini_list_recent_media shows and what lets a lost turn be recovered. The record lives
and is swept with its object, so it is kept for the same retention window, not longer.
Locally, gemini_interact writes an <image>.json sidecar (model, interaction id, options and
any text the model replied with — not the prompt itself) next to each image in the output dir;
those files are yours to keep or delete and never expire on their own. If your
prompts describe real people, bear in mind they sit in your bucket for the retention window.
Sending reference images without burning context
Every tool that takes a reference image — gemini_image_generate, gemini_image_edit,
gemini_image_set, gemini_interact, plus gemini_video_generate (reference stills) and
gemini_music_generate — accepts them four ways. Only one of them costs model context:
images_base64 is the fallback of last resort. It costs roughly 14k tokens per modest photo,
and it is silently corrupted whenever the file read that produced it was truncated — the
payload still looks like base64, so the failure surfaces as a bad generation rather than an
error. Prefer any of the other three.
images_url — the server fetches it
Fetches are restricted to public https:// URLs — private, loopback and link-local hosts are
refused (IPv6 literals are parsed, so [::ffff:7f00:1] is caught as loopback), every redirect
hop is revalidated, and each hop is bounded by a timeout. The response must be
Content-Type: image/* and is capped at 15MB, enforced while streaming rather than trusted
from Content-Length. A failure names the offending URL. Anything over 6MB is uploaded to the
Files API and referenced by uri instead of inlined, since generateContent caps a whole
request near 20MB.
images_file_uris — upload once, reference many times
Uploads are retained ~48h; after that the reference stops resolving (as a generic 404 —
see the chained-404 section above). gemini_image_set fetches or resolves such a reference
once and passes it to the master and every scene call.
On stdio builds, a local images path that gets referenced more than once in a session is
uploaded to the Files API automatically (keyed on path + mtime + size), so repeated edits of
the same photo stop re-sending the bytes. Editing the file invalidates the cached upload.
Signed upload URLs — no token at all (hosted)
This is the intended path for an agent with a shell: disk file → curl → r2_key → tool call,
with the image never entering the conversation. gemini_get_upload_url mints a short-lived
(~10 min) signed PUT URL, and the shell uploads with zero auth headers — the signature in
the URL is the authorization, mirroring how the download links work.
The signature covers one tenant-scoped object key, the declared content type and the expiry;
uploads are capped at 15MB, enforced while reading the stream. Only raster image types are
accepted (jpeg/png/webp/gif/avif/heic/heif/bmp/tiff) — SVG is deliberately refused, because an
SVG is a scriptable document and /media serves from the server's own origin. The returned
r2_key is then usable three ways: directly as images_r2_keys on any generation tool (the
server reads its own bucket — no bytes in the conversation), permanently via
gemini_save_character, or as a ~48h Files API reference via gemini_upload_file({ r2_key }).
Uploads themselves follow the host's blob-store retention schedule (up/ prefix).
Character & style library (hosted)
Recurring subjects and styles can be saved once, per account, with no expiry (the library's
lib/ objects are written retention-exempt, so the host's prune skips them):
Naming a character attaches its saved reference image and weaves its description into the
prompt; naming a style appends its fragment (and attaches its reference image, if it has one).
gemini_image_set passes character references to the master and every scene call, which is
what keeps the subject consistent across the set.
Quick Start
See SKILL.md for full usage documentation.
来源:README.md,提交 7080f22
工具
0版本历史
16- v2.5.1最新Nov 7, 2026
- v2.4.2Oct 20, 2026
- v2.4.1Oct 16, 2026
- v2.4.0Oct 14, 2026
- v2.3.4Oct 10, 2026
- v2.3.3Oct 7, 2026
- v2.3.2Oct 5, 2026
- v2.3.1Oct 3, 2026
- v2.3.0Sep 25, 2026
- v2.2.0Sep 24, 2026
- v2.1.4Sep 23, 2026
- v2.1.3Sep 23, 2026
- v2.1.2Sep 21, 2026
- v2.1.0Sep 20, 2026
- v2.0.0Sep 19, 2026
- v1.14.2Sep 16, 2026
评分
已满足适用检查项的 50%
该评分衡量此收录条目的完整程度,依据注册中心条目、端点与公开来源计算得出。它不是对服务器本身的评价,也不表示服务器安全或当前可用:可连通性是带日期的检查结果,评分也不包含安装量或用户评价。
- 近 30 天内可连通25 分
请保持端点能够响应 MCP 握手;SourceWeft 每 30 天探测一次。
- 已声明认证方式10 分
请在注册中心条目中声明凭据请求头,或保持端点能够响应探测,以便判定其认证方式。
- 已列出工具15 分
请让服务器在无凭据时响应 tools/list,或发布可在沙箱中无凭据启动的软件包。
- 描述必需15 分
- 图标10 分
- 文档15 分
- 许可证10 分
