Guide · 6 steps · ~20 minutes

How to add image generation to an AI agent

Give the agent image tools the same way you give it any other tool: connect an MCP server if the agent is one you do not control, or define the endpoints as function-calling tools if it is yours. Then teach it three habits — pass URLs between steps rather than bytes, batch anything independent into one call, and check the balance before it spends. Wiring up a generation endpoint takes ten minutes. Building an agent that produces usable assets without burning your credits, drifting stylistically or retrying its own bugs takes a few more decisions. These are the six that matter, in the order you have to make them.

By the imagemcpserver.com teamPublished Updated 10 min read

The six decisions

01

Decide who is choosing: the model, or your code

This one decision determines the whole shape. If the model decides which operation to run based on what the user asked, you want tools with schemas — MCP if the agent is somebody else’s, your framework’s function calling if it is yours. If your code already knows the sequence, call the REST endpoints directly; a tool layer between your function and a POST request buys you nothing.

Model chooses → tools

Code chooses → REST

Someone else’s client → MCP

02

Give it a credential it cannot leak

The key goes in an environment variable or a client-managed secret, never in a file the agent might commit. Keys are individually revocable, so issue a separate one per surface — one for your editor, one for CI, one for production — and you can kill any of them without touching the others.

IMAGEMCP_API_KEY in env

x-api-key header for MCP

One key per surface

03

Teach it that outputs are inputs

Generation, editing, cutout, upscale and conversion each return a hosted URL and accept one. That single convention is what makes chaining free: generate returns a URL, edit takes that URL and returns another, background removal takes that one, and so on. The agent passes references, not pixels, so a five-step pipeline costs about the same context as one step. Compression is the deliberate exception — it returns a data URI, which is why it goes last.

generate → url

edit(url) → url

compress(url) → bytes, so: last

04

Batch everything that does not depend on the last result

Most image work in a real pipeline is embarrassingly parallel — twenty product photos, six avatars, four aspect ratios of one concept. Sequential calls make it feel slow for no reason. multicall takes a list of tool calls and runs them concurrently in a single round trip, pricing each item by its own tool and deducting the total once, up front.

Sequential: 20 round trips

multicall: 1 round trip

Same credits either way

05

Put the budget in writing

An agent with a spending tool needs the same care as one with a deploy tool. Checking the balance is a free call, so make it the first step of any batch. Cap how many images one run may produce. State when it should stop and ask. Written constraints are followed far more reliably than implied ones.

get_user_info before a batch

Cap batch size explicitly

Draft cheap, finalise expensive

06

Make failure a decision, not a retry loop

Three failures matter and each needs a different response. Out of credits: stop and report — retrying cannot help. Model unavailable: fall back to the default model. Bad arguments: that is a bug in what the agent sent, and an identical retry fails identically. An agent that retries everything three times turns one bad call into three charges.

No credits → stop

Bad model → fall back

Bad args → fix, do not retry

Wiring it into your stack

None of this is framework-specific — an image tool is an HTTP call with a schema attached. What changes between stacks is only where you put the schema.

The tool definition, ready to paste

For anything that is not an MCP client, this is what the model needs to see. The enum on the aspect ratio is doing more work than it looks like — it is the difference between an agent that gets the shape right first time and one that invents "widescreen" and burns a credit finding out.

Route the call to POST /v1/generate in your handler and hand result.imageUrl back to the model as the tool result — not the image itself.

{
  "name": "generate_image",
  "description":
    "Generate an image from a text prompt. Returns a hosted URL that other image tools accept as input.",
  "parameters": {
    "type": "object",
    "properties": {
      "prompt": {
        "type": "string",
        "description": "What to draw. Be explicit about subject, style and composition."
      },
      "aspectRatio": {
        "type": "string",
        "enum": ["1:1", "16:9", "9:16", "4:3", "3:4", "21:9"],
        "description": "Defaults to 1:1."
      },
      "referenceImages": {
        "type": "array",
        "items": { "type": "string" },
        "description": "URLs of approved images to match in style."
      }
    },
    "required": ["prompt"]
  }
}

A worked pipeline, end to end

Six product photos arrive from a supplier. They need to be catalogue-ready. This is the whole run — check, batch, chain, compress — with nothing buffered until the final step.

const api = "https://api.imagemcpserver.com";
const auth = { Authorization: `Bearer ${key}`,
               "Content-Type": "application/json" };

// 1 — free call: can we afford this?
const { user } = await get("/v1/me");
if (user.credits < 6 * 24) {
  throw new Error("not enough credits");
}

// 2 — batch the cutouts, in parallel
const { results } = await post("/v1/multicall", {
  requests: photos.map((p) => ({
    tool: "remove_background",
    args: { image: p.url },
  })),
});

// 3 — chain: each cutout feeds the upscale
const upscaled = await post("/v1/multicall", {
  requests: results.map((r) => ({
    tool: "upscale_image",
    args: { image: r.imageUrl, scale: "4x" },
  })),
});

// 4 — ship it light (returns base64, so write it out here)
const final = await post("/v1/multicall", {
  requests: upscaled.results.map((r) => ({
    tool: "compress_image",
    args: { image: r.imageUrl, quality: 80,
            targetFormat: "webp" },
  })),
});

3 round trips, not 18

Each stage is one batched request instead of six sequential ones.

URLs between stages

Only references move until compression, which returns the bytes you write to disk.

144 credits, known in advance

6 × (8 + 15 + 1). Checked against the balance before anything ran.

18 log entries

Every call recorded with its tool and exact cost, auditable afterwards.

Let it check its own work

The gap between a demo and a pipeline you can leave running is verification. An agent that regenerates whenever it feels uncertain is expensive; an agent that runs four deterministic checks and only regenerates when one fails is not. None of these needs a model — they are assertions on the response you already have.

Did it come back at all?

A missing result.imageUrl is a failed call wearing a success shape. Check the field exists before you chain the next step onto undefined.

Are the dimensions what you asked for?

Aspect ratio is a hint to the model, not a guarantee. Read the actual width and height before writing the file into a layout that assumes 16:9.

Does the cutout actually have alpha?

A background removal that returns a fully opaque PNG has silently failed. One check on the alpha channel is far cheaper than a human noticing it in production.

Is it small enough to ship?

Compression reports originalSize, compressedSize and savedPercentage. If the output is still over your budget, drop the quality and re-encode — one credit, no model involved.

Keep the judgement call for a human, or a cheap model

“Is this on brand?” is not a deterministic check and pretending otherwise is how you end up with an agent regenerating the same hero eleven times. Approve one reference image by hand, then pass its URL as a reference for the rest of the batch — consistency becomes a parameter instead of a judgement.

Five mistakes that cost real money

Retrying every failure three times

One bad argument becomes three charges. Retry transient failures; fix the rest.

Cutting out before upscaling

The upscaler returns transparency as white, so a cutout fed into it loses its alpha channel. Upscale first, cut out last.

Iterating on a premium model

Draft on the fast tier. Only re-run the approved prompt on the expensive one.

No reference image in a batch

Twenty images, twenty art directions. The fix costs nothing and takes one field.

Writing uncompressed output to a repo

A generated PNG is not a shipped asset. One credit stands between the two.

Agent pipeline questions

Which AI agent is best for image generation?

The one you already use. Image generation is a tool call, not a category of agent — Claude Desktop, Claude Code, Cursor, Windsurf, VS Code with Copilot, Cline and ChatGPT can all do it once a server is connected, and any framework with function calling can do it with a JSON schema. Pick on how well the agent handles multi-step work and file writing, because that is what actually differs.

Do I need MCP, or is plain function calling enough?

Function calling is enough if you own the agent. Define the tools in your framework, call the endpoints, done. MCP earns its place when the agent is somebody else’s — an editor or a desktop assistant you cannot ship code into — because one server reaches all of them without a per-client integration.

Should the agent hold image bytes in memory?

Almost never. Generation, editing, cutout, upscale and format conversion all return a hosted URL and accept one, so the agent passes references between steps instead of base64 blobs. Compression is the exception — it hands back a data URI — which is why it belongs at the very end of a chain, where the bytes go straight to disk rather than back into context.

How do I stop an agent looping on image generation?

Give it a budget in words, make it check the balance first, and cap the batch size. Checking credits is a free call, so an agent can always know what it can afford before it starts spending.

What should the agent do when a call fails?

Read the error and adapt rather than retry blindly. Insufficient credits should stop the run and report; an unavailable model should fall back to the default; a malformed input is a bug in the agent’s own arguments and retrying identically will fail identically.

How do I keep a batch of images visually consistent?

Generate one, approve it, then pass its URL in referenceImages for everything else in the batch. This matters more than model choice and more than prompt length.

Can this run without a human in the loop at all?

Yes, and that is the interesting case — a nightly job that fills missing assets, a build step that generates any Open Graph image a route is lacking. Write the constraints down, cap the spend, add automatic checks on the output, and read the request log afterwards.

Next