Multimodal MCP server for generating images and describing assets across providers.
Project description
mmodal-mcp
Give any MCP client—CLI tools, packaged vendor agents, custom automations, or IDE integrations—the visual skills they’re missing. mmodal-mcp is a FastMCP server that wraps LiteLLM so assistants can generate new imagery and produce rich descriptions of existing assets (images, decks, spreadsheets, PDFs) through guided, agent-friendly prompts.
Why It Matters
- Fill the gap: Most copilots and command-line assistants can’t inspect PDFs, decks, or screenshots. This server adds that superpower through MCP tools.
- Consistent guidance: Validation returns actionable checklists, so autonomous agents can retry with confidence.
- Bring your own provider: Point LiteLLM at Gemini/Imagen, OpenAI DALL·E, or your own inference stack—no code changes required.
- Fits any MCP client: Use it from CLI tools, packaged vendor agents, custom automation, or GUI wrappers—if the client speaks MCP, it can use mmodal-mcp.
Quick MCP Configs
Custom Agents & CI Automation
uv run python scripts/fastmcp_pipeline.py
The script launches the server via stdio, calls each tool, and prints sanitized responses—ideal for bespoke agents, QA jobs, or integration tests.
Claude Code CLI
claude mcp add mmodal \
-e LITELLM_DEFAULT_MODEL=gemini/imagen-4.0-generate-001 \
-e LITELLM_DEFAULT_API_KEY=your-gemini-key \
-- uvx --from mmodal-mcp mmodal-mcp
Claude Desktop (macOS / Windows)
{
"mmodal": {
"command": "uvx",
"args": ["--from", "mmodal-mcp", "mmodal-mcp"],
"env": {
"LITELLM_DEFAULT_MODEL": "gemini/imagen-4.0-generate-001",
"LITELLM_DEFAULT_API_KEY": "your-gemini-key"
}
}
}
Save in ~/Library/Application Support/Claude/mcp/config.json (macOS) or %APPDATA%/Claude/mcp/config.json (Windows) and restart Claude Desktop.
Cursor / Windsurf / Other MCP-Aware IDEs
{
"mcpServers": {
"mmodal": {
"command": "uvx",
"args": ["--from", "mmodal-mcp", "mmodal-mcp", "--transport", "sse"],
"env": {
"LITELLM_DEFAULT_MODEL": "gemini/imagen-4.0-generate-001",
"LITELLM_DEFAULT_API_KEY": "your-gemini-key"
}
}
}
}
Use --transport stdio if the client expects stdio (stdio is the default).
OpenAI Codex CLI (~/.codex/config.toml)
[mcp_servers.mmodal]
command = "uvx"
args = ["--from", "mmodal-mcp", "mmodal-mcp"]
env = { LITELLM_DEFAULT_MODEL = "openai/dall-e-3", LITELLM_DEFAULT_API_KEY = "your-openai-key" }
startup_timeout_ms = 20000
Gemini CLI (~/.gemini/settings.json)
{
"mcpServers": {
"mmodal": {
"command": "uvx",
"args": ["--from", "mmodal-mcp", "mmodal-mcp"],
"env": {
"LITELLM_DEFAULT_MODEL": "gemini/imagen-4.0-generate-001",
"LITELLM_DEFAULT_API_KEY": "your-gemini-key"
}
}
}
}
Features
- Multiple Formats: Support for PNG, JPEG, and WebP output formats.
- Quality Control: Auto, high, medium, and low quality settings.
- Background Control: Transparent, opaque, or auto background options.
- FastMCP Framework: Built with the latest MCP Python SDK.
- LiteLLM Integration: Provider-agnostic LLM/image access powered by LiteLLM.
- Assistant-Friendly Tools: Guided MCP tools for generating, describing, and validating assets.
- Automated Validation: Optional LLM-powered checks to confirm assets match expectations.
- Multiple Transports: STDIO, HTTP, and SSE transport support.
- Structured Output: Validated tool responses with proper schemas.
- Resource Access: MCP resources for image retrieval and management.
- Local Storage: Organized directory structure with metadata.
- URL-based Access: Transport-aware URL generation for images.
- Dual Access: Immediate base64 data + persistent resource URIs.
- Smart Caching: Lightweight in-memory LRU cache with TTL controls.
- Auto Cleanup: Configurable file retention policies.
- Type Safety: Full type hints with Pydantic models.
- Error Handling: Comprehensive error handling and logging.
- Configuration: Environment-based configuration management.
- Testing: Pytest-based test suite with async support.
- Dev Tools: Hot reload for development.
Getting Started
Prerequisites
- Python 3.10 or higher
uvpackage manager (recommended)
Installation
-
Clone the repository:
git clone <repository-url> cd mmodal-mcp
-
Install dependencies using uv:
uv syncThis will automatically create a virtual environment and install all required dependencies from
pyproject.toml.
MCP Tools at a Glance
| Tool | Purpose | Key Inputs |
|---|---|---|
generate_image |
Produce a new image that matches a detailed prompt. | Prompt, quality/background/dimensions, style & acceptance criteria, validate_output, validation_focus. |
describe_asset |
Summarize existing assets so assistants can reference them. | File path/ID, optional purpose & audience, structure_detail, auto_validate, validation_focus. |
validate_asset |
Confirm an asset matches a provided description or criteria. | File path/ID, expected description, optional evaluation_focus, structure_detail. |
All tools share common LiteLLM plumbing and use configurable prompt templates so you can tailor the experience for your assistant or brand voice.
Every response follows the same structure:
{
"data": {...},
"metadata": {...},
"validation": {...} | null,
"assistant_hint": "...",
"retry_suggestions": ["..."],
"retry_history": [ ... ],
"final_guidance": "..."
}
This makes it easy for agents to inspect validation results, apply automated retries, and show users next steps.
Configuration
-
Create a
.envfile: Copy the.env.examplefile to.env:cp .env.example .env
-
Set your configuration: The server reads its settings from environment variables (see
.env.examplefor a guided template). Update the values to match your provider and runtime. A quick reference is provided below.
Key Environment Variables
| Variable | Purpose | Example |
|---|---|---|
LITELLM_DEFAULT_MODEL |
Fallback LiteLLM model identifier (provider/model) |
gemini/gemini-1.5-flash |
LITELLM_DEFAULT_API_KEY |
Default API key LiteLLM should use | ${GEMINI_API_KEY} |
LITELLM_DEFAULT_API_BASE |
Override base URL (optional) | https://custom.endpoint.googleapis.com |
LITELLM_DEFAULT_EXTRA_PARAMS |
JSON-encoded kwargs applied to all calls | {"quality": "high"} |
LITELLM_IMAGE_MODEL |
Optional override for image generation | gemini/gemini-image-001 |
LITELLM_DOCS_MODEL |
Optional override for asset/document descriptions | gemini/gemini-2.0-pro |
LITELLM_TEXT_MODEL |
Optional override for validation/text flows | gemini/gemini-2.0-pro |
LITELLM_*_API_KEY / API_BASE / EXTRA_PARAMS |
Per-domain overrides that fall back to defaults | see .env.example |
IMAGE_GENERATION_PROMPT_PREFIX |
Text prepended to every generation prompt | see .env.example |
ASSET_DESCRIPTION_SYSTEM_PROMPT |
System message for description calls | see .env.example |
ASSET_DESCRIPTION_PROMPT_TEMPLATE |
Default user prompt for description calls | see .env.example |
ASSET_STRUCTURE_GUIDANCE_VISUAL |
Guidance for composition/style analysis when requested | see .env.example |
ASSET_STRUCTURE_GUIDANCE_DOCUMENT |
Guidance for layout/structure analysis when requested | see .env.example |
ASSET_VALIDATION_SYSTEM_PROMPT |
System message for validation calls | see .env.example |
ASSET_VALIDATION_PROMPT_TEMPLATE |
Default user prompt for validation calls | see .env.example |
IMAGE_DIR |
Directory for generated images + metadata | images |
CACHE_TTL_SECONDS |
Seconds before cached base64 payloads expire (0 disables expiry) |
3600 |
CACHE_MAX_ITEMS |
Max items in the in-memory LRU cache | 256 |
FILE_RETENTION_DAYS |
Cleanup window for on-disk files | 7 |
CLEANUP_CHECK_INTERVAL_SECONDS |
Delay before rechecking when the image directory is missing | 60 |
CLEANUP_RUN_INTERVAL_SECONDS |
Delay between cleanup sweeps when the directory exists | 3600 |
IMAGE_MIN_DIMENSION |
Minimum allowed width/height (pixels) for generated images | 64 |
IMAGE_MAX_DIMENSION |
Maximum allowed width/height (pixels) for generated images | 4096 |
Example Configurations
# Google Gemini (single key for everything)
LITELLM_DEFAULT_MODEL="gemini/gemini-1.5-flash"
LITELLM_DEFAULT_API_KEY="${GEMINI_API_KEY}"
LITELLM_DEFAULT_EXTRA_PARAMS='{"safetySettings": {"harmCategory": "HARM_CATEGORY_DEROGATORY"}}'
# Hybrid Gemini setup (separate image + doc credentials)
LITELLM_DEFAULT_MODEL="gemini/gemini-1.5-flash"
LITELLM_DEFAULT_API_KEY="${GEMINI_IMAGE_KEY}"
LITELLM_DOCS_MODEL="gemini/gemini-2.0-pro"
LITELLM_DOCS_API_KEY="${GEMINI_DOC_KEY}"
LITELLM_TEXT_MODEL="gemini/gemini-2.0-pro"
# OpenAI DALL-E 3 with GPT-4o for text
LITELLM_DEFAULT_MODEL="openai/dall-e-3"
LITELLM_DEFAULT_API_KEY="${OPENAI_API_KEY}"
LITELLM_DEFAULT_EXTRA_PARAMS='{"quality": "high", "style": "vivid"}'
LITELLM_TEXT_MODEL="openai/gpt-4o-mini"
ASSET_DESCRIPTION_SYSTEM_PROMPT="You are a product designer describing assets for an engineering team."
# Local inference proxy
LITELLM_DEFAULT_MODEL="local/flux-schnell"
LITELLM_DEFAULT_API_BASE="http://localhost:8080"
LITELLM_DEFAULT_EXTRA_PARAMS='{"guidance_scale": 7.5}'
LITELLM_TEXT_MODEL="local/qwen-2"
Example Tool Calls
# generate_image
{
"prompt": "An exploded diagram of a drone motor",
"quality": "high",
"background": "transparent",
"dimensions": [1024, 1024],
"image_format": "PNG",
"style": "technical illustration",
"acceptance_criteria": "Label each part, include measurements",
"validate_output": true,
"validation_focus": "Ensure all callouts appear",
"max_validation_retries": 2
}
# describe_asset
{
"uri": "docs/product-roadmap.pdf",
"purpose": "Engineering weekly sync",
"audience": "Full-stack team",
"structure_detail": true,
"auto_validate": true,
"validation_focus": "Highlight milestones"
}
# validate_asset
{
"uri": "images/drone-motor.png",
"expected_description": "Exploded drone motor diagram showing bearings, stator, rotor",
"structure_detail": true,
"evaluation_focus": "Check that all labeled parts are visible"
}
Running the Server
Development Mode (with hot reloading):
To run the server in development mode, use the dev script defined in pyproject.toml:
uv run dev
The server will be available at http://127.0.0.1:8000.
MCP Transports:
Run the server with different transport options:
uv run mmodal-mcp # STDIO transport (default)
uv run mmodal-mcp --transport sse # SSE endpoint (Server-Sent Events)
mcp dev main:mcp # Launch with MCP Inspector
Production Mode:
For production, you can run the server directly with an ASGI server like uvicorn:
uvicorn main:mcp --port 8000
Running Tests
To run the test suite, use pytest:
uv run pytest
For verbose output with detailed test information:
uv run pytest -v
This will run all the tests in the tests/ directory and provide a report of the results.
Development Workflow
-
Install dependencies (including dev tools):
uv sync -
Run tests after making changes:
uv run pytest -v
-
Test the MCP server locally:
# Run with stdio transport uv run mmodal-mcp # Or run the demo pipeline uv run python scripts/fastmcp_pipeline.py
-
Development mode with hot reload:
uv run dev
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file mmodal_mcp-0.8.5.tar.gz.
File metadata
- Download URL: mmodal_mcp-0.8.5.tar.gz
- Upload date:
- Size: 27.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1788bd6569651f7726dfa0790b990ad81a83bf7868bc018328bbb63cd557cf55
|
|
| MD5 |
8101e62cf5c96a717c2939003ea2e77e
|
|
| BLAKE2b-256 |
28090d521824c884865d7e6e6c0c27d29a2006b866141c0a02fc2685ded4754d
|
Provenance
The following attestation bundles were made for mmodal_mcp-0.8.5.tar.gz:
Publisher:
python-publish.yml on mikeparcewski/mmodal-mcp
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
mmodal_mcp-0.8.5.tar.gz -
Subject digest:
1788bd6569651f7726dfa0790b990ad81a83bf7868bc018328bbb63cd557cf55 - Sigstore transparency entry: 682377105
- Sigstore integration time:
-
Permalink:
mikeparcewski/mmodal-mcp@a19163415cb05e4c6f521237d9661b50c0edc5aa -
Branch / Tag:
refs/tags/v0.8.5 - Owner: https://github.com/mikeparcewski
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-publish.yml@a19163415cb05e4c6f521237d9661b50c0edc5aa -
Trigger Event:
release
-
Statement type:
File details
Details for the file mmodal_mcp-0.8.5-py3-none-any.whl.
File metadata
- Download URL: mmodal_mcp-0.8.5-py3-none-any.whl
- Upload date:
- Size: 21.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c5f1b99940c43c19a1e8edf1af946127906e3679110fc527d0a954b7c4175520
|
|
| MD5 |
4f0baaeec536c68a4a6dbb0d13e7baa9
|
|
| BLAKE2b-256 |
4d8f9a94c88e9a420918e3b566a9ddeda27d6e74c43bfdb4923772fd0aaf23e4
|
Provenance
The following attestation bundles were made for mmodal_mcp-0.8.5-py3-none-any.whl:
Publisher:
python-publish.yml on mikeparcewski/mmodal-mcp
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
mmodal_mcp-0.8.5-py3-none-any.whl -
Subject digest:
c5f1b99940c43c19a1e8edf1af946127906e3679110fc527d0a954b7c4175520 - Sigstore transparency entry: 682377150
- Sigstore integration time:
-
Permalink:
mikeparcewski/mmodal-mcp@a19163415cb05e4c6f521237d9661b50c0edc5aa -
Branch / Tag:
refs/tags/v0.8.5 - Owner: https://github.com/mikeparcewski
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-publish.yml@a19163415cb05e4c6f521237d9661b50c0edc5aa -
Trigger Event:
release
-
Statement type: