Skip to main content
Glama
Paramrk

Siray Image MCP

by Paramrk

Siray Image MCP

License: MIT

Image generation backed by the Siray API (Flux, Nano Banana, Seedream, GPT-Image, and 50+ other models behind one key), wired up two ways:

  1. An MCP server — any MCP-capable AI agent (Claude Code, Codex, Antigravity, Cursor, Windsurf, VS Code, Claude Desktop, Gemini CLI...) can generate images and backdrops directly into your project.

  2. A local web pageuv run web.py for a prompt box, model picker and gallery.

Built for generating real project assets (hero images, icons, product shots, UI backdrops) without burning API credits on doomed or unusable generations — see Not wasting credits and Backdrops below.

Quickstart

git clone https://github.com/Paramrk/siray-image-mcp.git
cd siray-image-mcp
uv sync
cp .env.example .env        # then paste your Siray key into it
uv run test_core.py         # sanity check, no network

Get a key at siray.ai → console → API keys.

Related MCP server: WujieAI MCP Server

Use from an AI agent

See INSTALL.md for the exact config for Claude Code, Codex, Antigravity, Cursor, Windsurf, VS Code, Claude Desktop and Gemini CLI, plus the two mistakes that break most pastes (a relative uv command GUI agents can't find; VS Code's config using servers instead of mcpServers).

Once connected, the agent has three tools:

tool

for

generate_image(prompt, out_dir, model?, image?, size?, aspect_ratio?, seed?)

any image, saved straight into your project

generate_backdrop(prompt, out_dir, palette, overlay_text_color, ...)

a background plate that won't clash with your UI — see Backdrops

list_models()

the live model catalogue

In any project, just ask: "generate a 1920x1080 hero image of X into public/images".

Backdrops

generate_backdrop requires palette and overlay_text_color — the agent has to read your project's actual colours (CSS variables, tailwind config, theme file) and decide what text goes on top before it can call this tool. That decision is what makes the backdrop match the first time instead of costing a second generation.

The prompt is rewritten with background-plate rules (no text, no logos, no centre subject, calm negative space, tone forced opposite the overlay colour), then the saved file is graded locally — no API call:

measure

means

fails above/below

worst_cell_contrast

WCAG contrast against your overlay colour, on a 6×6 grid

below 4.5

busyness

edge energy; clutter that fights overlaid text

above 12

palette_drift

0–100 distance of the image's dominant colours from your palette

above 30

seam

difference between opposing edges, only checked if tileable=True

above 8

Calibrated against real generations: a purpose-built backdrop measured 7.13 / 2.0 / 7.6. Ordinary images used as backdrops measured ~1.0 contrast and 25–39 drift. The thresholds sit in that gap — they're judgement calls, tune them in backdrop.py.

A FAILED verdict never deletes the file and never auto-retries — it's already paid for, so it's kept, and the report says exactly what to change if you regenerate.

Not wasting credits

core.preflight() refuses requests that are certain to fail or hang, before anything is submitted — every rule below is something observed failing against the live API:

  • an unknown model id (the API answers 503) — suggests the closest real ids

  • a -t2i model given a reference image, or an -i2i model given none

  • size on bytedance/seedream-*, which accepts the parameter and then never finishes

  • a malformed size string, a bad palette hex, or a reference file that doesn't exist

Refusals return as REFUSED (nothing was generated, no credit spent): <what to change> in under a second — both the MCP tools and the web UI surface the reason, not just "error", because an opaque failure is what causes an agent to retry blindly and waste the credit this exists to save.

Dimensions

Pass size="1920x1080" and you get exactly that, on any model — how it gets there differs by family, handled automatically:

model family

what happens

openai/gpt-image-*

rendered at that exact size by the API

google/nano-banana-*, black-forest-labs/flux-*

nearest aspect ratio requested, then resized locally to your exact pixels

bytedance/seedream-*

ignores size and aspect ratio entirely (always 2048²) — preflight refuses anything non-square rather than silently cropping it

Security: no key reaches the browser or the agent's context

The Siray API key lives in .env (gitignored) and is read once, server-side, by core._key(). Nothing else touches it:

  • Web UI: the browser only ever calls this project's own local server (/generate, /models, /gallery). index.html never talks to api.siray.ai and contains no key, token, or Authorization header — web.py does that server-side, in Python, and returns only file paths and text back to the page.

  • MCP server: the agent talks to server.py over a local stdio pipe — no network endpoint, no browser, nothing an agent's own context window or a webpage could read the key out of. The key never appears in a tool's input, output, or error text (checked: see core.explain() and every raise in core.py — they carry paths and model ids, never headers or the key itself).

  • .gitignore excludes .env, .venv/, output/, __pycache__/ and uv.lock. Only .env.example (empty) is committed.

If you fork this and add a hosted deployment (not local), put the key behind your own backend the same way — never ship it in client-side JS.

Models

Ids end in -t2i (text-to-image) or -i2i / -edit / -ref2i (image-to-image, needs image). Default is google/nano-banana-pro-t2i. A few worth knowing:

  • openai/gpt-image-2-t2i, openai/gpt-image-2.5-flare-t2i — exact sizes, ChatGPT's models

  • black-forest-labs/flux-1.1-pro-ultra-t2i — very high resolution

  • bytedance/seedream-4.5-t2i — square only

  • google/nano-banana-pro-i2i — best for editing an existing image

list_models() (tool or core.list_models()) always reflects the live catalogue.

Local web UI

uv run web.py

http://127.0.0.1:8765. Prompt box, live model picker, exact size, aspect ratio, seed, optional reference image, and a gallery of everything in output/.

Testing

uv run test_core.py

No network. Covers filename slugging, extension sniffing, size parsing, aspect snapping, preflight refusals, palette normalisation (agents send arrays, comma strings, and JSON strings — all three are accepted), contrast math, and the seedream size guard.

Project layout

file

purpose

core.py

Siray API client: submit, poll, download, preflight

backdrop.py

prompt composition + local image grading for backdrops

server.py

MCP server — the three tools above

web.py / index.html

local web UI

test_core.py

the test suite

INSTALL.md

per-agent connection config

API notes (learned the hard way)

  • Async only: POST /v1/images/generations/asynctask_id, then poll GET .../async/{task_id}.

  • status can flip to SUCCESS a beat before outputs is populated — poll until both.

  • On success, fail_reason (confusingly) contains the image URL. Ignore it.

  • Output URLs are api.siray.ai/redirect/...; redirects are followed by hand in core._http_fetch because httpx's own follower choked on one.

Contributing

Issues and PRs welcome. Keep additions to the same shape: a rule in core.preflight() or backdrop.py should trace back to something actually observed failing against the live API, with a test in test_core.py.

License

MIT

Available Tools

3 tools
generate_backdropA

Generate a background plate that the project's UI can sit on top of.

STOP: before calling this, read the project's actual colours — the CSS custom properties, tailwind.config, theme file, or an existing screenshot — and pass them as palette. Do not guess them, and do not invent a palette from the prompt. Whatever text or UI will sit on this backdrop determines overlay_text_color. Getting these two right is what stops the backdrop from clashing and needing a second paid generation.

The prompt is rewritten to enforce background-plate discipline (no text, no logos, no centre subject, calm negative space, tone set opposite the overlay colour), then the saved file is measured locally: worst-region contrast against overlay_text_color, clutter, drift from palette, and edge seam if tileable.

The file is ALWAYS kept — it is already paid for. A FAILED verdict tells you exactly what to change if you choose to regenerate; it is not an automatic retry.

Args: prompt: The scene or texture, e.g. "soft abstract mesh gradient". out_dir: Absolute path to save into. Created if missing. palette: Hex colours from the project, e.g. ["#0f1115", "#6ea8fe"]. A single comma-separated string works too. overlay_text_color: Hex colour of the text/UI going on top, e.g. "#e7e9ee". size: Exact dimensions, e.g. "1920x1080". model: Omit for the default. Do not use bytedance/seedream-* for a non-square backdrop — it only renders 2048x2048. tileable: True for a repeating pattern; the edge seam is then measured. seed: Integer for reproducible output.

Returns the saved path, the measurements, and a PASS/FAILED verdict.

ParametersJSON Schema
NameRequiredDescriptionDefault
seedNo
sizeNo
modelNo
promptYes
out_dirYes
paletteYes
tileableNo
overlay_text_colorYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries full burden for behavior, and it delivers: it discloses that the prompt is rewritten to enforce background-plate rules, that the saved file is locally measured for contrast/clutter/drift/edge seam, that the file is always kept because it is already paid for, and that a FAILED verdict is not an automatic retry. This gives the agent important externally invisible behavior.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well structured and not wasteful: a one-line purpose, a prioritized STOP instruction block, then a plain-language behavior block, then a compact Args list. The all-caps/STOP stands out without being noise, and every sentence adds operational or behavioral value.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity (8 params, 4 required, no annotations), the description is complete enough: it explains all parameters, return values (saved path, measurements, PASS/FAILED verdict), failure handling, and important warnings. The presence of an output schema covers shape details, so the description fills the remaining contextual gaps.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, but the Args section documents all 8 parameters with concrete examples and caveats: palette accepts an array or single string, seed gives reproducible output, tileable triggers seam measurement, out_dir is created if missing, size is exact dimensions, and model should be omitted by default. This fully compensates for the sparse schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The first sentence states a specific verb and resource: 'Generate a background plate that the project's UI can sit on top of.' The rest of the description scopes the tool further by mentioning background-plate discipline, avoiding text/logos/centre subject, and measuring contrast for overlay text, which clearly distinguishes it from a general image generator like generate_image.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The STOP block gives strong contextual guidance: read actual project colors before calling, pass them as palette, never invent palette from the prompt, derive overlay_text_color from UI text, avoid seedream models for non-square backdrops, and treat FAILED as a diagnostic rather than a retry trigger. It does not explicitly mention when to prefer generate_image instead, so it misses explicit exclusions/alternatives, but the usage context is clear.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

generate_imageA

Generate an image with Siray and save it into the current project.

Args: prompt: What to draw. Be specific about subject, style, lighting, background. out_dir: Absolute path of the folder to save into, e.g. the project's assets/images folder. Created if missing. model: Siray model id, e.g. "bytedance/seedream-4.5-t2i", "google/nano-banana-pro-t2i", "black-forest-labs/flux-1.1-pro-ultra-t2i". Omit for the default. Call list_models() for the live list. image: Optional reference image for image-to-image / editing — a URL or a local file path. When you pass this you MUST also pass an -i2i / -edit model (e.g. "google/nano-banana-pro-i2i"); -t2i models reject it. Note: bytedance/seedream-* ignores size and aspect ratio entirely. size: exact output dimensions, e.g. "1920x1080". Use this whenever the user names dimensions. openai/* models render at that size natively; for other models the nearest aspect ratio is requested and the file is resized to exactly this. aspect_ratio: e.g. "16:9", "1:1", "9:16". Ignore when passing size. seed: Integer for reproducible output.

Returns the saved file path(s).

ParametersJSON Schema
NameRequiredDescriptionDefault
seedNo
sizeNo
imageNo
modelNo
promptYes
out_dirYes
aspect_ratioNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full behavioral burden and handles it well. It discloses side effects such as creating out_dir, model compatibility constraints, exact-size resizing behavior, seed reproducibility, and the return value of saved file paths.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with its core purpose and follows with a tight bulleted Args section. Every sentence adds operational value, and the length is justified by the complexity of seven parameters with conditional constraints.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a seven-parameter generation tool with no annotations, this is remarkably complete. It covers required inputs, optional customizations, model selection, image-to-image requirements, resizing behavior, and what the tool returns, leaving no critical gap for an agent to call it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must explain every parameter, and it does. Each parameter receives meaningful detail, including examples, defaults, conditional requirements, and interaction rules between image and model, and between size and aspect_ratio.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly identifies the action and target: 'Generate an image with Siray and save it into the current project.' It gives a specific verb and resource, but it does not explicitly distinguish itself from the sibling generate_backdrop tool, so it is clear without full sibling differentiation.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives strong parameter-level usage guidance: when to pass size, when to ignore aspect_ratio, and when an -i2i/-edit model is required. It references list_models() for the live model list, but it does not provide explicit when-to-use versus generate_backdrop guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_modelsA

List Siray's active image models, live from the API. Default is marked.

Ids ending in -t2i are text-to-image; -i2i / -edit / -ref2i need an image.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the behavioral disclosure burden. It discloses that results are 'live from the API,' that a default is marked, and that ID suffixes encode whether an image input is required. These are useful operational details beyond the schema.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is two compact sentences with the core purpose front-loaded and the model ID convention provided as useful secondary context. Every sentence adds value and there is no filler or repetition of schema information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a zero-argument listing tool with an output schema, the description adequately covers purpose, freshness, default marking, and ID semantics. It lacks an explicit connection to when to use it alongside the generation siblings, but the overall context is sufficient for correct invocation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

There are zero parameters, so schema coverage is effectively 100% and the description has no parameter burden. The baseline for a zero-parameter tool is 4, and the description appropriately focuses on output behavior rather than arguments.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb and resource: 'List Siray's active image models.' It clearly identifies a read-only catalog operation and distinguishes itself from the generate_* siblings by describing an informational listing rather than an image-generation action.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The usage is implied: an agent would call this tool when it needs to discover available model IDs or check the active/default model. However, the description does not explicitly say when to prefer list_models over generate_image or generate_backdrop, nor does it describe a discovery-before-generation workflow.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 3 tool updatesv0.1.0
    • First observedgenerate_backdrop
    • First observedgenerate_image
    • First observedlist_models

TDQS

A4.6/5.0

Scored across 3 tools

Disambiguation5/5

The two generation tools are clearly separated by purpose: generate_image handles general image creation/editing, while generate_backdrop is a specialized, measurement-driven operation for background plates. list_models is entirely distinct, so an agent can confidently select the right tool by name and description.

Naming Consistency5/5

All tool names follow the same verb_noun snake_case pattern: generate_image, generate_backdrop, and list_models. There are no mixed conventions, vague single-word names, or inconsistent prefixes.

Tool Count5/5

Three tools is well-scoped for a narrow image-generation MCP: one general generation tool, one specialized backdrop tool, and one model discovery tool. Each tool earns its place, and the count is within the ideal range.

Completeness5/5

The server covers the core image-generation lifecycle: discovering available models, generating images from prompts, supporting image-to-image/editing via the image argument, and providing a dedicated backdrop workflow with built-in validation. There are no obvious dead ends or missing critical operations for an image generation domain.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers