"""
MCP server exposing Gemini image editing and analysis tools over Streamable HTTP.
"""
import base64
import io
import os
from google import genai
from google.genai import types
from PIL import Image as PILImage
from mcp.server.fastmcp import FastMCP, Image
IMAGE_EDIT_MODEL = "gemini-3-pro-image-preview"
IMAGE_ANALYZE_MODEL = "gemini-2.5-pro"
PORT = int(os.environ.get("PORT", "8000"))
mcp = FastMCP("gemini-image-mcp", host="0.0.0.0", port=PORT)
@mcp.tool()
def image_edit(image_base64: str, mime_type: str, prompt: str) -> Image:
"""Edit an existing image based on a text prompt.
Args:
image_base64: Base64-encoded image data
mime_type: MIME type of the image (e.g., image/png)
prompt: Text prompt describing the desired edit
"""
client = genai.Client(api_key=os.environ["GEMINI_API_KEY"])
image_bytes = base64.b64decode(image_base64)
pil_image = PILImage.open(io.BytesIO(image_bytes))
response = client.models.generate_content(
model=IMAGE_EDIT_MODEL,
contents=[prompt, pil_image],
config=types.GenerateContentConfig(
response_modalities=["IMAGE", "TEXT"],
),
)
for part in response.candidates[0].content.parts:
if part.inline_data is not None:
fmt = part.inline_data.mime_type.split("/")[-1]
return Image(data=part.inline_data.data, format=fmt)
raise ValueError("Gemini did not return an edited image")
@mcp.tool()
def image_analyze(image_base64: str, mime_type: str, question: str) -> str:
"""Analyze an image and answer a question about it.
Args:
image_base64: Base64-encoded image data
mime_type: MIME type of the image (e.g., image/png)
question: Question to ask about the image
"""
client = genai.Client(api_key=os.environ["GEMINI_API_KEY"])
image_bytes = base64.b64decode(image_base64)
pil_image = PILImage.open(io.BytesIO(image_bytes))
response = client.models.generate_content(
model=IMAGE_ANALYZE_MODEL,
contents=[question, pil_image],
)
return response.text
if __name__ == "__main__":
mcp.run(transport="streamable-http")