idml-engine
Headless InDesign document composition via MCP: parse IDML templates, convert content to ICML stories, and compose complete newspaper IDML files conversationally.
README
idml-engine
Headless InDesign document composition. Parse a designer's IDML, convert editorial content to styled ICML stories, and compose complete newspaper IDML documents — no InDesign required at build time.
Built to replace two things at a working newspaper (The Wayland Post):
- DocsFlow (the commercial Google Docs → InDesign plugin) for one-way, batch content placement, and
- a Scripts-panel ExtendScript handoff that needed a human to click a button inside InDesign for every build.
An issue that took a staffed InDesign session now composes in about one second, headlessly, and the editor opens a finished IDML to refine.
How it works
content (Google Docs / DOCX / Markdown / HTML / JSON)
│ ingest.py — normalize to typed blocks (headline, byline, body, cutline…)
▼
typed blocks ──► story_converter.py ──► ICML stories (Pandoc, style-mapped)
│
▼
composer.py — "donor package" composition
• a real published-issue IDML (or purpose-built template) donates
Resources/ (all styles, fonts, colors) and MasterSpreads/ (the grid)
• generates fresh Spreads/ + Stories/: standing head, headline frame,
image grid with cutline captions, threaded body legs, bottom ad well
▼
complete .idml — opens in InDesign with the paper's exact design system
template_parser.py is the intelligence layer: it reads any IDML into a
manifest — style catalog, master geometry with computed column ranges, every
frame with threading, story-role classification (headline/body/caption/jump),
and DocsFlow live-links (story → Google Doc id, decoded merge base).
Quickstart
pip install idml-engine[all] # needs Pandoc on the machine for conversion
# understand a template or issue
idml-engine-parse issue.idml --summary
# convert a story
idml-engine-convert article.docx -o article.icml
# compose an issue (donor supplies styles/masters)
idml-engine-compose --donor published-issue.idml --manifest manifest.json --out new-issue.idml
Python API:
from idml_engine import composer, ingest, story_converter, template_parser
manifest = template_parser.parse_template("issue.idml")
blocks = ingest.from_file("article.docx")
story_converter.blocks_to_icml(blocks, "article.icml")
composer.compose("donor.idml", articles, "out.idml", ads=ads)
Layout priors — "trained" on your own paper
The composer doesn't guess layout metrics; it learns them from your archive.
layout_learner.py mines a corpus of published-issue IDMLs into
layout-priors.json — measured body-text density (chars/pt², drives column
capacity), headline-frame heights, caption heights, image sizes, ad-band
heights, and stories-per-page (quartile distributions). The composer
auto-loads priors (env IDML_ENGINE_PRIORS, or the file next to the
package) and falls back to model constants without them.
python -m idml_engine.layout_learner "path\to\published issues" -o layout-priors.json
At The Wayland Post: 27 issues mined → 729 body-story density samples, 937 headline frames, 1,200 placed images. The measured density (~31 chars/line) corrected the hand-tuned model's 40 by 25%.
MCP server (AI-drivable)
Every capability is exposed as MCP tools, so Claude (or any MCP client) can parse templates and compose issues conversationally:
claude mcp add idml-engine -- python -m idml_engine.mcp_server
Tools: parse_template, list_template_styles, get_template_geometry,
validate_template, ingest_content, convert_story, compose_issue,
compose_articles.
DocsBridge panel — the DocsFlow-style UI
uxp-panel/ is an InDesign UXP panel that replicates DocsFlow's workflow on
this engine: load an issue → per-article Place (drops the styled ICML
story and live-links it via storyTitle="docx:<google-doc-id>" — DocsFlow's
own convention) → Update re-places into the linked story's first frame,
preserving the frame chain. Status badges (placed / not placed / no copy)
survive save/reopen because the link rides in the document.
Backed by idml_engine/panel_service.py (localhost:3100 — manifest
listing, on-demand blocks→ICML, Drive refetch). Load the panel once via the
Adobe UXP Developer Tool (uxp-panel/manifest.json).
Commercial REST API
commercial/api_server.py wraps the same engine with Bearer-key auth and
per-key usage metering for hosted deployment (FastAPI):
uvicorn commercial.api_server:app --port 8080
# POST /api/compose /api/parse /api/convert (Authorization: Bearer <key>)
# GET /api/usage
Keys + metering are file-backed stubs; production wires them to Stripe
metered billing (see commercial/README.md).
Findings that made this possible
- ICML style mapping: Pandoc's ICML writer (stable since 2014) plus a
post-pass that strips its
" > Paragraph"style-name suffix yields stories whose styles match the template by exact name — InDesign adopts the template's formatting on Place. Trailing-space style names ("Byline ") survive round-trip. - Donor-package composition: a finished issue's IDML already carries the paper's whole design system. Cloning its resources and generating only spreads + stories produces documents InDesign opens cleanly.
- DocsFlow link format: DocsFlow stores its Google Doc live-links in
plain sight —
StoryTitle="docx:<file-id>"plus a merge-base blob that is just base64 → raw DEFLATE → JSON. A future release can read, preserve, and write these links for drop-in compatibility.
See docs/TEMPLATE-STRUCTURE.md for the full IDML anatomy notes.
Status
Alpha. Working end-to-end at one real newspaper. Not yet implemented: multi-article pages, jump lines ("Continued on…"), text wrap around images, DocsFlow-compatible link writing, IDML→PDF export (open in InDesign, or pair with InDesign Server / the UXP MCP bridge).
License
BSD-3-Clause (this library). The commercial API layer and hosted service are separate products built on top.
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.