Metadata-Version: 2.4
Name: figurify-mcp
Version: 0.2.0
Summary: Ship-ready MCP server for Gemini + Imagen diagram/plot generation. Runs on Claude, ChatGPT, VSCode Copilot, Cursor.
Project-URL: Homepage, https://github.com/genaimanoj/figurify-mcp
Project-URL: Repository, https://github.com/genaimanoj/figurify-mcp
Project-URL: Issues, https://github.com/genaimanoj/figurify-mcp/issues
Project-URL: Changelog, https://github.com/genaimanoj/figurify-mcp/blob/main/CHANGELOG.md
Author-email: Manoj Bhandari <genaimanoj@gmail.com>
License-Expression: MIT
License-File: LICENSE
Keywords: chatgpt,claude,diagram,gemini,imagen,infographic,mcp,model-context-protocol
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Multimedia :: Graphics
Classifier: Topic :: Scientific/Engineering :: Visualization
Classifier: Typing :: Typed
Requires-Python: >=3.10
Requires-Dist: fastmcp>=0.2.0
Requires-Dist: google-genai>=1.0
Requires-Dist: matplotlib>=3.8
Requires-Dist: mcp>=1.0.0
Requires-Dist: pillow>=10.0
Requires-Dist: pydantic-settings>=2.0
Requires-Dist: pydantic>=2.0
Requires-Dist: python-dotenv>=1.0
Provides-Extra: dev
Requires-Dist: mypy>=1.10; extra == 'dev'
Requires-Dist: pre-commit>=3.8; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
Requires-Dist: pytest-cov>=5.0; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Requires-Dist: ruff>=0.6; extra == 'dev'
Description-Content-Type: text/markdown

# figurify-mcp

[![CI](https://github.com/genaimanoj/figurify-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/genaimanoj/figurify-mcp/actions/workflows/ci.yml)
[![PyPI version](https://img.shields.io/pypi/v/figurify-mcp)](https://pypi.org/project/figurify-mcp/)
[![Python 3.10+](https://img.shields.io/pypi/pyversions/figurify-mcp)](https://pypi.org/project/figurify-mcp/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

**Ship-ready** MCP server for Gemini + Imagen diagram, infographic, plot, and evaluation generation. One codebase runs on **Claude Code / Desktop, ChatGPT Apps SDK, VSCode GitHub Copilot, Cursor**, and any MCP-compliant client.

- 5 task tools + 5 meta tools, 2 prompt templates, 3 resources
- Smart model routing (April 2026 Gemini catalog: Gemini 3 Flash/Pro, Nano Banana 2/Pro, Imagen 4 Fast/Ultra)
- **Token-budget aware** via `search_tools` / `describe_tool` / `recommend_model` / `estimate_cost`
- Stdio + Streamable HTTP transports from one binary
- 44 passing pytest cases, ruff-clean, MIT licensed, Docker-packaged, PyPI-ready

Inspired by [llmsresearch/paperbanana](https://github.com/llmsresearch/paperbanana); design patterns from [jlowin/fastmcp](https://github.com/jlowin/fastmcp), [modelcontextprotocol/servers](https://github.com/modelcontextprotocol/servers), [github/github-mcp-server](https://github.com/github/github-mcp-server), [Composio search_tools](https://docs.composio.dev/reference/meta-tools/search_tools), and the [Speakeasy progressive-disclosure pattern](https://www.speakeasy.com/blog/100x-token-reduction-dynamic-toolsets).

---

## Tool catalog

### Generation (5)
| Tool | Cost recipe | When Claude/GPT/Copilot picks it |
|---|---|---|
| `create_simple_diagram` | 1× Imagen (~$0.04) | "draw X", "sketch Y", "quick picture of Z" |
| `create_infographic` | 1× VLM + 1× Imagen (~$0.12) | "infographic", "poster", "visual summary of X" |
| `create_methodology_diagram` | 1× VLM + N × (Imagen + critique) (~$0.25 at iter=2) | paper methodology text, NeurIPS-style figures |
| `create_statistical_plot` | 1× VLM + matplotlib subprocess (~$0.002) | tabular data → chart |
| `evaluate_diagram` | 1× VLM judge (~$0.015) | "compare / score / judge these two diagrams" |

### Meta / token-savers (5)
| Tool | Purpose |
|---|---|
| `search_tools(query, tags?, limit=5)` | Rank slim tool cards — client avoids loading every schema upfront |
| `describe_tool(name)` | Full JSON schema for one tool (progressive disclosure) |
| `recommend_model(task, task_kind="auto")` | Maps free-form intent → routed Gemini model + ~USD/call + rationale |
| `estimate_cost(tool_name, iterations=2)` | Breakdown of VLM + image calls before you pay |
| `list_available_models()` | Full Gemini + Imagen catalog with cost / latency tiers |

### Prompts (slash-command candidates)
- `draft_methodology_figure(methodology_text, caption)`
- `plan_visual_output(user_request)`

### Resources (static, readable without tool calls)
- `figurify://styles/methodology_guidelines`
- `figurify://styles/infographic_guidelines`
- `figurify://catalog/models`

All generation tools return `[ImageContent, TextContent]` MCP content blocks so images render **inline** in Claude, ChatGPT, Copilot, Cursor — no base64 blobs leaking into prompts.

---

## Smart model routing

```python
# figurify_mcp/models.py
pick_image_model("simple")          # → gemini-3.1-flash-image-preview   (Nano Banana 2)
pick_image_model("simple", "4K")    # → gemini-3-pro-image-preview        (auto-upgrade)
pick_image_model("detailed")        # → gemini-3-pro-image-preview        (Nano Banana Pro)
pick_image_model("fast_draft")      # → imagen-4.0-fast-generate-001
pick_image_model("photoreal")       # → imagen-4.0-ultra-generate-001
pick_vlm_model("reasoning")         # → gemini-3.1-pro-preview
pick_vlm_model("cheap_text")        # → gemini-3.1-flash-lite-preview
pick_vlm_model("critic")            # → gemini-3-flash
```

Pin a model globally via `FIGURIFY_VLM_MODEL` / `FIGURIFY_IMAGE_MODEL` — env overrides always win.

---

## Installation

```bash
pip install figurify-mcp
# or
uv pip install figurify-mcp
```

Get a free API key at [aistudio.google.com/apikey](https://aistudio.google.com/apikey).

## Host configs

### Claude Desktop

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

```json
{
  "mcpServers": {
    "figurify": {
      "command": "uvx",
      "args": ["figurify-mcp"],
      "env": { "GOOGLE_API_KEY": "your-key-here" }
    }
  }
}
```

Restart Claude Desktop — the 10 tools appear automatically.

### Claude Code / Cursor

```bash
claude mcp add figurify -s user \
  -e GOOGLE_API_KEY=$GOOGLE_API_KEY \
  -- uvx figurify-mcp
```

### VSCode GitHub Copilot — `.vscode/mcp.json`

```json
{
  "servers": {
    "figurify": {
      "command": "uvx",
      "args": ["figurify-mcp"],
      "env": { "GOOGLE_API_KEY": "your-key-here" }
    }
  }
}
```

### ChatGPT Apps SDK / remote HTTP

```bash
docker run --rm -p 8765:8765 \
  -e GOOGLE_API_KEY=$GOOGLE_API_KEY \
  ghcr.io/genaimanoj/figurify-mcp
# then register https://your-host/mcp in the Apps SDK console
```

> **Why `uvx`?** It downloads, caches, and runs the package in one command — no venv, no manual install. First run takes ~5 s; every subsequent run is instant from cache.

## Transports

```bash
figurify-mcp --transport stdio                              # Claude Desktop / Code / Cursor (default)
figurify-mcp --transport http --host 0.0.0.0 --port 8765   # ChatGPT / VSCode remote / web
figurify-mcp --transport sse  --port 8765                   # legacy (deprecated per MCP 2025-11-25)
```

## Dev setup

```bash
git clone https://github.com/genaimanoj/figurify-mcp
cd figurify-mcp
uv venv && source .venv/bin/activate
uv pip install -e '.[dev]'
cp .env.example .env   # set GOOGLE_API_KEY
pre-commit install
pytest -q              # 44 tests, ~2s
```

---

## How token budget is saved

A host connecting to many MCP servers pays context tokens for every tool schema upfront. This server offers three levels of progressive disclosure:

1. **List-only mode** — clients that only want one endpoint load `search_tools` and nothing else. When a user asks something, the client calls `search_tools("intent")` and receives slim cards `{name, score, description, tags, required_params}`. Full schema is fetched only for the chosen tool via `describe_tool(name)`.
2. **Cost-aware routing** — before committing to a generation, clients call `estimate_cost(tool_name)` to see a per-model breakdown, or `recommend_model(intent)` to pick the cheapest viable model.
3. **Prompts & resources** — common request patterns (methodology diagram, visual routing) are exposed as MCP Prompts so hosts surface them as slash commands without the client needing to compose templates.

Measured impact: a fresh host cold-start that lists `search_tools` alone loads ~0.5 KB of schema instead of ~6 KB for the full catalog — ~90% upfront reduction, with no loss of functionality.

---

## Design decisions

- **FastMCP 2.x** over the raw SDK — 30% less boilerplate, built-in transports, prompts + resources primitives.
- **MCP content blocks (`ImageContent` + `TextContent`)** — renders inline in every compliant host. Base64-in-a-dict is a common anti-pattern that fails silently in ChatGPT / Claude Desktop.
- **`fastmcp.exceptions.ToolError`** — surfaces as `isError: true` per MCP spec so hosts show the user a real error instead of interpreting the exception string as output.
- **`pydantic-settings` + `.env`** — config is ordinary env vars; `Settings.ensure_ready()` fails fast at startup in stdio mode.
- **Typed params via `Annotated[..., Field(description=...)]` + `Literal[...]`** — hosts render dropdowns and range validators automatically.
- **Tags on every tool** (`image`, `academic`, `fast`, `meta`, `routing`…) — lets `search_tools` and host UIs filter.
- **Docstring convention** — every tool starts with `**Use this when…** / **Do NOT use…**` so LLM hosts route intent correctly.

---

## Layout

```
FigurifyMCP/
├── pyproject.toml              # PyPI metadata, ruff + mypy + pytest configs
├── Dockerfile                  # non-root, HTTP transport on :8765/mcp
├── LICENSE                     # MIT
├── CHANGELOG.md, CONTRIBUTING.md, SECURITY.md
├── .github/workflows/ci.yml    # ruff + pytest on py3.10/3.11/3.12 + trusted PyPI publish
├── figurify_mcp/
│   ├── server.py               # FastMCP app, CLI, 10 tools + 2 prompts + 3 resources
│   ├── meta.py                 # search_tools / describe_tool / recommend_model / estimate_cost
│   ├── models.py               # Gemini registry + pick_vlm_model / pick_image_model
│   ├── config.py               # pydantic-settings
│   ├── prompts.py              # embedded VLM prompt templates
│   ├── utils.py                # image_content, text_content, save_png, subprocess runner
│   ├── clients/
│   │   ├── imagen.py           # google-genai image gen wrapper
│   │   └── gemini_vlm.py       # google-genai text + vision wrapper
│   └── tools/
│       ├── simple.py           ├── infographic.py
│       ├── methodology.py      ├── plot.py
│       └── evaluate.py
└── tests/                      # 44 hermetic tests — no network
    ├── test_registry.py        ├── test_meta.py
    ├── test_server_contract.py └── test_utils.py
```

---

## CI / release

- `.github/workflows/ci.yml` — ruff lint + format check + pytest on 3.10 / 3.11 / 3.12.
- Pushing a `v*` tag triggers the `publish` job which builds wheels and uploads to PyPI via trusted publishing.
- Dockerfile publishes non-root, adjustable via `--transport` at container runtime.

## License

MIT. See [LICENSE](LICENSE).
