Skip to main content
Glama
README.md
# Create Image MCP Server

A Model Context Protocol (MCP) server that generates and edits images using OpenAI's GPT Image 2.6 models (`gpt-image-2.6-sunburst` and `gpt-image-2.6-flare`). This server enables Claude Desktop, Claude Code, and other MCP clients to create images from text descriptions and edit existing images.

## Features

- Text-to-image generation via OpenAI GPT Image 2.6 (precision `sunburst` or fast `flare` model)
- Image editing and style transfer with input image support
- Custom sizes up to 4K (3840x2160), plus quality, compression, and output format controls
- Transparent background support
- Multiple image variations in a single request
- Images saved to disk with text-only responses (no base64 bloat)
- Retry with exponential backoff for transient failures

## Prerequisites

- Node.js >= 22.0.0
- OpenAI API Key

## Installation

### Option 1: NPM Global Install (Recommended)

```bash
npm install -g @gpriday/create-image-mcp
```

The `create-image-mcp` command will be available globally.

### Option 2: Local Development Install

```bash
git clone https://github.com/gregpriday/create-image-mcp.git
cd create-image-mcp
npm install
```

### Configuration

Create a `.env` file in your project root or home directory (`~/.env`):

```bash
OPENAI_API_KEY=your_api_key_here
```

You can get an OpenAI API key from [OpenAI Platform](https://platform.openai.com/api-keys).

**For local development**, validate your configuration with:
```bash
npm run check-env
```

The server resolves settings in this order:
1. Environment variables (including the `env` block of your MCP client config)
2. `.env` in the server's working directory
3. `~/.env`

Only `OPENAI_API_KEY` and `OPENAI_IMAGE_MODEL` are read from `.env` files. Other variables such as `OPENAI_BASE_URL` are ignored there, so a project's `.env` can't redirect your key to another server.

Optionally set `OPENAI_IMAGE_MODEL` to change the default model (defaults to `gpt-image-2.6-sunburst`), for example to pin a dated snapshot such as `gpt-image-2.6-sunburst-YYYY-MM-DD`.

## Usage

### Run the MCP Server

**If installed globally:**
```bash
create-image-mcp
```

**If running locally:**
```bash
node src/index.js
```

The server runs on stdio and communicates via JSON-RPC 2.0. In MCP client configs, launch `create-image-mcp` or `node /path/to/src/index.js` directly rather than `npm start`, since npm prints its own output to stdout.

### Test the Server

```bash
npm test                     # Unit tests
npm run test:integration     # MCP protocol test over stdio (no API calls)
CREATE_IMAGE_LIVE_TEST=1 npm run test:integration   # Also generates one real image (costs a few cents)
npm run test:all             # All tests
```

### Available Tools

#### create_image

Generate or edit images using OpenAI GPT Image.

**Use when:** user says "create an image", "generate a picture", "draw", "make an illustration", "edit an image", "transform a photo", or any visual content creation request.

**Parameters:**

| Parameter | Required | Type | Default | Description |
|-----------|----------|------|---------|-------------|
| `prompt` | Yes | string | - | Image description or editing instructions (1-32,000 chars) |
| `output_file` | Yes | string | - | File path to save the generated image (absolute recommended; `~/` is expanded) |
| `model` | No | enum | `gpt-image-2.6-sunburst` | `gpt-image-2.6-sunburst` (precision) or `gpt-image-2.6-flare` (faster, for drafts) |
| `style` | No | enum | - | Style preset (built-in: `ui-mockup`; add your own in `create-image-styles/`) |
| `input_images` | No | array | - | File paths to input images for editing (PNG/JPEG/WebP, up to 16 images, max 20MB each) |
| `size` | No | string | `1024x1024` | `auto` or `WIDTHxHEIGHT`, e.g. `1536x1024`, `2048x1152`, `3840x2160` (see size rules below) |
| `quality` | No | enum | `auto` | `low`, `medium`, `high`, `auto` |
| `background` | No | enum | `auto` | `transparent`, `opaque`, `auto` |
| `number_of_images` | No | integer | `1` | Number of variations (1-4) |
| `output_mime_type` | No | enum | from extension, else `image/png` | `image/png`, `image/jpeg`, `image/webp` |
| `output_compression` | No | integer | - | 0-100 compression for JPEG/WebP output |
| `moderation` | No | enum | `auto` | `auto` or `low` (less restrictive filtering) |
| `system_message_file` | No | string | - | Text file prepended to the prompt (max 4,000 chars), for brand or style rules |
| `mask` | No | string | - | PNG with alpha channel marking the area to edit (requires `input_images`) |
| `input_fidelity` | No | enum | - | `high` or `low`: how closely edits preserve the input (requires `input_images`) |

**Size rules:** both edges must be multiples of 16, the longest edge at most 3840px, the aspect ratio at most 3:1, and the total between 655,360 and 8,294,400 pixels (1024x640 up to 3840x2160). Larger sizes cost more and take longer.

**Paths and formats:** relative paths resolve against the server's working directory, which for Claude Desktop is usually not your project, so prefer absolute paths. The output format follows the `output_file` extension (`.png`, `.jpg`/`.jpeg`, `.webp`). If you set `output_mime_type` explicitly, the extension is corrected to match, and the response always reports the absolute path that was written.

**Examples:**

Generate a simple image:
```json
{
  "name": "create_image",
  "arguments": {
    "prompt": "A serene mountain landscape at sunset with golden light",
    "output_file": "./landscape.png"
  }
}
```

Generate with specific settings:
```json
{
  "name": "create_image",
  "arguments": {
    "prompt": "A futuristic city skyline with flying cars, cyberpunk style",
    "output_file": "./cyberpunk-city.png",
    "size": "1536x1024",
    "quality": "high",
    "number_of_images": 2
  }
}
```

Generate with transparent background:
```json
{
  "name": "create_image",
  "arguments": {
    "prompt": "A minimalist flat vector logo of an owl",
    "output_file": "./logo.png",
    "background": "transparent"
  }
}
```

Edit an existing image:
```json
{
  "name": "create_image",
  "arguments": {
    "prompt": "Change the background to a beach scene",
    "input_images": ["./photo.jpg"],
    "output_file": "./edited-photo.png"
  }
}
```

Style transfer:
```json
{
  "name": "create_image",
  "arguments": {
    "prompt": "Make this image look like a watercolor painting",
    "input_images": ["./source.png"],
    "output_file": "./watercolor.png"
  }
}
```

**Response Format:**

The tool saves images to disk and returns a text-only response:
```
Image saved to: /Users/you/project/landscape.png (245.3 KB, image/png)
```

For multiple images, files are numbered:
```
Image saved to: /Users/you/project/cyberpunk-city_1.png (312.1 KB, image/png)
Image saved to: /Users/you/project/cyberpunk-city_2.png (298.7 KB, image/png)
```

## Integration with Claude Desktop

Add this server to your Claude Desktop configuration.

### If Installed Globally (Recommended)

#### macOS
Edit `~/Library/Application Support/Claude/claude_desktop_config.json`:

```json
{
  "mcpServers": {
    "create-image": {
      "command": "create-image-mcp",
      "env": {
        "OPENAI_API_KEY": "your_api_key_here"
      }
    }
  }
}
```

#### Windows
Edit `%APPDATA%\Claude\claude_desktop_config.json`:

```json
{
  "mcpServers": {
    "create-image": {
      "command": "create-image-mcp",
      "env": {
        "OPENAI_API_KEY": "your_api_key_here"
      }
    }
  }
}
```

#### Linux
Edit `~/.config/Claude/claude_desktop_config.json`:

```json
{
  "mcpServers": {
    "create-image": {
      "command": "create-image-mcp",
      "env": {
        "OPENAI_API_KEY": "your_api_key_here"
      }
    }
  }
}
```

### If Running Locally

#### macOS
Edit `~/Library/Application Support/Claude/claude_desktop_config.json`:

```json
{
  "mcpServers": {
    "create-image": {
      "command": "node",
      "args": ["/path/to/create-image-mcp/src/index.js"],
      "env": {
        "OPENAI_API_KEY": "your_api_key_here"
      }
    }
  }
}
```

#### Windows
Edit `%APPDATA%\Claude\claude_desktop_config.json`:

```json
{
  "mcpServers": {
    "create-image": {
      "command": "node",
      "args": ["C:\\path\\to\\create-image-mcp\\src\\index.js"],
      "env": {
        "OPENAI_API_KEY": "your_api_key_here"
      }
    }
  }
}
```

#### Linux
Edit `~/.config/Claude/claude_desktop_config.json`:

```json
{
  "mcpServers": {
    "create-image": {
      "command": "node",
      "args": ["/path/to/create-image-mcp/src/index.js"],
      "env": {
        "OPENAI_API_KEY": "your_api_key_here"
      }
    }
  }
}
```

**After updating the configuration, restart Claude Desktop.**

## Integration with Claude Code

### Option 1: Project-Level `.mcp.json` (Recommended)

Add a `.mcp.json` file to your project root. This is the simplest approach and works automatically when Claude Code opens the project.

> **Note:** If `OPENAI_API_KEY` is already set in your shell environment (e.g. in `~/.zshrc`, `~/.bashrc`, or `~/.env`), omit the `env` field entirely. That's the safer choice for a checked-in `.mcp.json`: never commit a real API key. Claude Code also expands `${OPENAI_API_KEY}` in the `env` block.

**If installed globally:**
```json
{
  "mcpServers": {
    "create-image": {
      "command": "create-image-mcp",
      "env": {
        "OPENAI_API_KEY": "your_api_key_here"
      }
    }
  }
}
```

**If running locally:**
```json
{
  "mcpServers": {
    "create-image": {
      "command": "node",
      "args": ["/path/to/create-image-mcp/src/index.js"],
      "env": {
        "OPENAI_API_KEY": "your_api_key_here"
      }
    }
  }
}
```

### Option 2: CLI Command

**For current project only:**
```bash
claude mcp add --scope project create-image -e OPENAI_API_KEY=your_api_key_here -- create-image-mcp
```

**For your user (available in all projects):**
```bash
claude mcp add --scope user create-image -e OPENAI_API_KEY=your_api_key_here -- create-image-mcp
```

**Verify the server is running:**
```bash
claude mcp list
```

## Integration with OpenAI Codex

Add the MCP server using the `codex mcp add` command or by editing `~/.codex/config.toml`.

### Using CLI (Recommended)

**If installed globally:**
```bash
codex mcp add create-image --env OPENAI_API_KEY=your_api_key_here -- create-image-mcp
```

**If running locally:**
```bash
codex mcp add create-image --env OPENAI_API_KEY=your_api_key_here -- node /path/to/create-image-mcp/src/index.js
```

### Manual Configuration

Edit `~/.codex/config.toml`:

```toml
[mcp_servers.create-image]
command = "create-image-mcp"
env = { OPENAI_API_KEY = "your_api_key_here" }
```

## Development

### Dependency Management

- **Semver Ranges**: Dependencies use caret (`^`) ranges for automatic patch/minor security updates
- **Lockfile**: `package-lock.json` is committed for reproducible builds
- **CI/CD**: Use `npm ci` (not `npm install`) to enforce lockfile versions
- **Security**: Run `npm run security:audit` regularly

### Project Structure

```
create-image-mcp/
├── src/
│   ├── index.js               # Main MCP server
│   └── styles.js              # Built-in and user style presets
├── scripts/
│   └── check-env.js           # Environment validation
├── test/
│   ├── unit/
│   │   ├── tool-handler.test.js    # Unit tests
│   │   └── tool-description.test.js # Schema tests
│   └── test-create-image-mcp.js    # Integration tests
├── package.json
├── package-lock.json          # Committed for reproducibility
├── .env                       # API key (git-ignored)
├── .env.example               # API key template
├── .gitignore
├── LICENSE
└── README.md
```

### Scripts

**Development:**
- `npm start` - Start the MCP server (auto-runs environment validation)
- `npm test` - Run unit tests
- `npm run test:integration` - Run the MCP protocol test (set `CREATE_IMAGE_LIVE_TEST=1` for a live generation)
- `npm run test:all` - Run all tests
- `npm run dev` - Run server with auto-reload

**Environment & Security:**
- `npm run check-env` - Validate environment configuration
- `npm run security:audit` - Check for security vulnerabilities
- `npm run security:fix` - Auto-fix security issues
- `npm run security:update` - Update dependencies and audit

## Error Handling

The server provides categorized error handling:

- **Input Validation**: Parameters validated for presence, type, length, and enum membership
- **[AUTH_ERROR]**: Missing or invalid API keys
- **[QUOTA_ERROR]**: API quota, rate limit, or billing errors
- **[TIMEOUT_ERROR]**: Request timeout errors
- **[SAFETY_ERROR]**: Content blocked by safety filters or content policy violations
- **[FILE_ERROR]**: Missing, unreadable, or unsupported input images, masks, or output paths (input types are checked from file contents)
- **[NO_IMAGE]**: The API returned no image
- **[CANCELLED]**: The client cancelled the call; no files are written
- **[API_ERROR]**: General API errors
- **Retry Logic**: Rate limits (429), 408/409, server errors (5xx), and dropped connections are retried up to 3 times with exponential backoff, honoring `Retry-After`. Auth, validation, safety, exhausted-quota, and timeout errors are not retried. Each attempt times out after 5 minutes.
- **Process Stability**: Unhandled rejections and exceptions trigger clean shutdown

## License

MIT

## Contributing

Contributions welcome! Please open an issue or PR.

## Support

For issues or questions:
1. Check the [MCP documentation](https://modelcontextprotocol.io)
2. Review [OpenAI API docs](https://platform.openai.com/docs/api-reference/images)
3. Open an issue in this repository

TDQS

A3.9/5.0

Scored across 1 tool

Disambiguation5/5

With only one tool, there is no possibility of confusion. The tool's name and description clearly define its purpose for image generation and editing.

Naming Consistency5/5

The single tool name follows a clear verb_noun convention (create_image), which is consistent and predictable. There are no other tools to create inconsistency.

Tool Count3/5

A single tool feels thin for a server, but it is appropriately scoped to a narrow domain of image creation and editing. It is borderline but functional.

Completeness5/5

The tool covers both generation and editing of images, fulfilling the stated purpose fully. There are no obvious gaps in the core lifecycle for this domain.

Maintenance

ActivityMaintained
ResponsivenessNo recent community issues