maginary-mcp
Model Context Protocol server for Maginary — enumerate the prompt-DSL flags the engine accepts, kick off generations, and poll for results, all from inside your MCP-compatible client (Claude Desktop, Cursor, Continue, custom).
why
Maginary uses a Midjourney-style --flag prompt DSL over an async HTTP API. This server:
- surfaces the full parameter catalog to your LLM so it can pick the right flags
- offers a one-shot
generatetool that hitsPOST /api/gens/ - offers
get_generation+wait_for_generationfor polling to a terminal state - works offline for the catalog tools (ships a bundled snapshot; refreshed from the live docs endpoint at startup when reachable)
connect
This is an MCP server — you don't run it directly; your AI client (Claude Desktop, Cursor, etc.) launches and talks to it behind the scenes. Just add one config block and start chatting.
Claude Desktop
Add to ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or the equivalent on your OS:
{
"mcpServers": {
"maginary": {
"command": "uvx",
"args": ["maginary-mcp"]
}
}
}
Restart Claude Desktop. Ask it to generate an image — it will see Maginary's tools automatically.
No account yet? No problem — Claude will walk you through signup (just give it your email). Already have an API key? Add it to skip that step:
"env": { "MAGINARY_API_KEY": "sk-mag-…" }
Requires Python 3.10+ and uv. Alternatively: pip install maginary-mcp.
configuration
Environment variables (all optional for local use):
| var | default | meaning |
|---|---|---|
MAGINARY_API_KEY |
— | Bearer token from app.maginary.ai/dashboard#api-keys. Skips the in-chat signup flow. Catalog tools work without it. |
MAGINARY_BASE_URL |
https://app.maginary.ai/api |
Override for staging or self-hosted. |
MAGINARY_PUBLIC_HOST |
app.maginary.ai |
Hosted mode only. Sent to the backend as X-Forwarded-Host (with -Proto/-For) when MAGINARY_BASE_URL is an internal address, so the backend builds public URLs. |
MAGINARY_MCP_REQUIRE_AUTH |
off | Hosted mode only. On: every /mcp call needs a Bearer (OAuth token or API key); without one the server answers 401 + WWW-Authenticate pointing at /.well-known/oauth-protected-resource, which is how Claude/ChatGPT start the login. Trade-off: a wallet-only agent has no Bearer to send, so with the gate on it must make its first x402 payment over plain HTTP (POST /api/gens/ returns an API key) and connect with that key; the 401 body says so. |
MAGINARY_OAUTH_ISSUER |
https://app.maginary.ai/o |
The authorization server named in the protected-resource metadata (the backend, django-oauth-toolkit). |
MAGINARY_MCP_RESOURCE_URL |
https://mcp.maginary.ai/mcp |
This server's canonical resource identifier (RFC 8707 audience). |
MAGINARY_MCP_LOG_LEVEL |
INFO |
Standard Python log level; goes to stderr (stdout is reserved for MCP JSON-RPC). |
hosted (no-install) — Streamable HTTP
Connect a client straight to the hosted server at https://mcp.maginary.ai/mcp.
Zero install — the server is multi-tenant, so each request is scoped to
whatever credential it arrives with. Two ways to authenticate, pick whichever
fits the client:
Connect (OAuth) — for Claude Desktop, claude.ai, and any other client that speaks MCP's OAuth spec. Add the server with no headers at all:
{
"mcpServers": {
"maginary": { "url": "https://mcp.maginary.ai/mcp" }
}
}
Click "Connect" in the client. It opens a login page on app.maginary.ai,
you sign in and approve the requested scopes, and the client holds the token
from then on — no key to generate or paste. Requires the server to be running
with MAGINARY_MCP_REQUIRE_AUTH=1; without it, no login is asked for at all.
API key — for any client that doesn't do the OAuth dance (or if you'd rather not click through a login), generate a key at app.maginary.ai/dashboard#api-keys and send it yourself:
{
"mcpServers": {
"maginary": {
"url": "https://mcp.maginary.ai/mcp",
"headers": { "Authorization": "Bearer sk-mag-…" }
}
}
}
Both are equivalent once connected — same tools, same account. Catalog tools
work with no credential either way; generate / get_generation /
wait_for_generation need one. Run the hosted server yourself with:
paying inside the tool call (x402 over MCP)
No key at all? Call generate anyway. Out of credits (or no account), the
result is isError: true with the x402 PaymentRequired at the top level
(accepts, resource, …) plus error: "payment_required". An x402-capable
MCP client — the x402 SDK's x402MCPSession — signs accepts[0] and calls
the same tool again with the payment in _meta["x402/payment"]. The server
forwards it to the backend as PAYMENT-SIGNATURE; the backend verifies,
settles on Base and, for a wallet with no account, creates one. The settled
result carries the on-chain receipt in _meta["x402/payment-response"] and
x402_receipt. No API key is returned — subsequent requests use wallet-signed
auth headers (X-Wallet-Address, X-Wallet-Signature, X-Wallet-Timestamp)
instead.
The server holds no payment logic; everything is decided by the backend's
/api/gens/ contract.
wallet-signed authentication
After the first x402 payment creates the wallet's account, all subsequent requests are authenticated by signing a short message with the wallet's private key. Three headers on every request:
| Header | Value |
|---|---|
X-Wallet-Address |
Lowercased 0x EVM address (42 chars) |
X-Wallet-Signature |
EIP-191 personal_sign hex over the challenge string |
X-Wallet-Timestamp |
Unix seconds (integer) |
The challenge string is:
Maginary: authenticate <address> at <timestamp>. This does not move funds.
with <address> lowercased and <timestamp> the same unix seconds sent in
the header. The timestamp must be within 5 minutes of the server's clock
(30 s of future skew tolerated). No API key management needed — the wallet
is the credential.
pip install "maginary-mcp[http]"
maginary-mcp-http # serves /mcp on 0.0.0.0:8642 (MAGINARY_MCP_PORT to change)
# — or —
docker build -t maginary-mcp . && docker run -p 8642:8642 maginary-mcp
The hosted server sets no MAGINARY_API_KEY (keys come per-request). Extra
env: MAGINARY_MCP_HOST (default 0.0.0.0), MAGINARY_MCP_PORT (default 8642).
Claude Skill
The server ships an Agent Skill that
teaches the --flag DSL, model selection, and the async generate→poll flow:
maginary-mcp --install-skill # -> ~/.claude/skills/maginary-image-gen/SKILL.md
The skill stands on its own — hosts without MCP get the DSL plus the raw REST
calls (POST /gens/ → poll). With the server connected, Claude instead calls
search_parameters for the authoritative flag list and generate/wait_for_generation
natively. Re-running updates it; local edits are protected unless you pass --force.
Source: src/maginary_mcp/SKILL.md.
tools
catalog (no auth)
list_parameters(category?, status?, include_reserved=false)— enumerate the catalogsearch_parameters(query, category?, include_reserved=false)— text search over names / aliases / desc / examplesget_parameter(name)— full record for one flag (canonical name or alias)
list_parameters responses include the categories / statuses taxonomy, and both
list/search responses carry source (live vs bundled-snapshot).
generation (auth required)
generate(prompt, callback_url?)—POST /api/gens/. Supports img2img: place image URLs in the prompt. Multiple URLs = multi-input compositing. Use--sref <url>for style-only transfer (not img2img).upload_image(file_path, filename?)— reads a local image file and uploads viaPOST /api/images/upload/. Returns a CDN URL for use in img2img prompts or--sref. Stdio connections only (hosted: use a URL directly or the REST endpoint).execute_action(generation_uuid, action_type, parent_image_index?, prompt?, callback_url?)—POST /api/gens/{uuid}/actions/. Run a follow-up on a completed generation's image (upscale, vary, pan, zoom, img2vid, reroll).get_generation(uuid)—GET /api/gens/{uuid}/. Response includesprocessing_result.available_actionsmapping slots to valid action types.wait_for_generation(uuid, timeout_s=45)— poll todone/failed; atimeoutresult means still running — call again
worked example
Inside an MCP-capable client, once configured:
"Search the maginary catalog for anything about aspect ratio."
The LLM calls search_parameters("aspect") and gets back the --ar entry with values, examples, and supported models.
"Now generate a cinematic portrait 16:9 with the flagship model."
The LLM calls generate("a cinematic portrait --ar 16:9 --flagship"), gets a uuid, then wait_for_generation(uuid) and reads image_urls[] out of the terminal record.
"Upscale the first image."
The LLM checks processing_result.available_actions["0"], sees "upscale_2x", calls execute_action(uuid, "upscale_2x", 0), gets a new uuid, then wait_for_generation(new_uuid).
"Edit this photo to look like a watercolor." (user provides a local image)
The LLM calls upload_image("/tmp/photo.png") → gets a CDN URL, then generate("https://cdn.maginary.ai/…/photo.webp reimagine as watercolor painting"). (stdio only — on hosted, the user provides a URL instead.)
catalog freshness
- Live fetch on startup from
https://maginary.ai/docs/parameters.json, 5-second timeout. - Bundled snapshot at
src/maginary_mcp/parameters_snapshot.jsonused as a fallback whenever live fetch fails (no network, docs site down, etc.). - The snapshot is refreshed manually by the maintainer via
python scripts/refresh_snapshot.py— deliberately not baked into the wheel build so a new snapshot always corresponds to a reviewed commit.
The source field on list_parameters / search_parameters responses tells you which one is active.
development
cd mcp
python -m venv venv && source venv/bin/activate
pip install -e .
maginary-mcp # runs on stdio; kill with Ctrl+D
license
MIT.
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 maginary_mcp-0.3.7.tar.gz.
File metadata
- Download URL: maginary_mcp-0.3.7.tar.gz
- Upload date:
- Size: 64.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5a6b4daf6e79f99d62b0ad4bf3be76b4bf590dd8af338328bdcdd9e0793c34df
|
|
| MD5 |
2e0376352af8d3e05e17ec6a8c7919cc
|
|
| BLAKE2b-256 |
9a19e4a25cb39b16e8e950652a1b8823a0472a32f53db8a43916aebd475344e6
|
Provenance
The following attestation bundles were made for maginary_mcp-0.3.7.tar.gz:
Publisher:
publish.yml on maginaryai/maginary-mcp
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
maginary_mcp-0.3.7.tar.gz -
Subject digest:
5a6b4daf6e79f99d62b0ad4bf3be76b4bf590dd8af338328bdcdd9e0793c34df - Sigstore transparency entry: 2758621129
- Sigstore integration time:
-
Permalink:
maginaryai/maginary-mcp@95884bd2b4e2e1a7d890a58266db946f7a988f8b -
Branch / Tag:
refs/tags/v0.3.7 - Owner: https://github.com/maginaryai
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@95884bd2b4e2e1a7d890a58266db946f7a988f8b -
Trigger Event:
push
-
Statement type:
File details
Details for the file maginary_mcp-0.3.7-py3-none-any.whl.
File metadata
- Download URL: maginary_mcp-0.3.7-py3-none-any.whl
- Upload date:
- Size: 50.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
cc5e3663469c1eadd28454e5e907e47c06bda4cd576c7183b346ffde758e681e
|
|
| MD5 |
22df444ad541c409cdc71a9b6a699a22
|
|
| BLAKE2b-256 |
ad5e996042407bb11a1b9875d4d33209548bba6cb1cbc938946dc3eee51bad29
|
Provenance
The following attestation bundles were made for maginary_mcp-0.3.7-py3-none-any.whl:
Publisher:
publish.yml on maginaryai/maginary-mcp
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
maginary_mcp-0.3.7-py3-none-any.whl -
Subject digest:
cc5e3663469c1eadd28454e5e907e47c06bda4cd576c7183b346ffde758e681e - Sigstore transparency entry: 2758621143
- Sigstore integration time:
-
Permalink:
maginaryai/maginary-mcp@95884bd2b4e2e1a7d890a58266db946f7a988f8b -
Branch / Tag:
refs/tags/v0.3.7 - Owner: https://github.com/maginaryai
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@95884bd2b4e2e1a7d890a58266db946f7a988f8b -
Trigger Event:
push
-
Statement type: