@lit-pigeon/mcp-server
v0.2.2
Published
Model Context Protocol server exposing Lit Pigeon email authoring + rendering as MCP tools.
Maintainers
Readme
@lit-pigeon/mcp-server
Model Context Protocol server exposing Lit Pigeon email authoring + rendering as MCP tools. Plug it into any MCP-compatible client (Cursor, Windsurf, Codex, etc.) and ask the model to build emails for you.
This is the runtime implementation of the AI authoring specification.
Install
pnpm add @lit-pigeon/mcp-server
# or globally for direct `lit-pigeon-mcp` invocation
npm install -g @lit-pigeon/mcp-serverConfigure your client
Most MCP clients accept the same mcpServers block in their config file. The path varies by client — for example, Cursor reads ~/.cursor/mcp.json, Windsurf reads ~/.codeium/windsurf/mcp_config.json, and project-scoped configs typically live at .mcp.json in the workspace root.
{
"mcpServers": {
"lit-pigeon": {
"command": "npx",
"args": ["-y", "@lit-pigeon/mcp-server"]
}
}
}After restarting your client, ask: "Use lit-pigeon to build a welcome email with a hero, an intro paragraph, and a Get-Started button to https://example.com."
Tools exposed
| Tool | Purpose |
|---|---|
| create_document | Make a new, empty PigeonDocument. Returns its id. |
| list_documents | Return ids, names, and updatedAt for every document in this session. |
| get_document | Return the full document JSON by id. |
| validate_document | Run validateDocument() and return any errors. |
| set_document_metadata | Patch metadata.name and/or metadata.previewText. |
| set_body_attribute | Update one of width, backgroundColor, fontFamily, contentAlignment. |
| list_block_types | Enumerate the supported block types. |
| add_row | Append a row with columnCount (1-4) or explicit ratios summing to 12. |
| add_block | Append a typed block (text/image/button/divider/spacer/social/html/hero/navbar) to a column, with partial values overrides. |
| update_block | Patch a block's values. Reverts on validation failure. |
| delete_block | Remove a block. |
| render_to_mjml | Serialize to MJML. |
| render_to_html | Render to email-client-safe HTML (with inline CSS). Returns { html, errors }. |
| import_figma_frame | Fetch a Figma frame via the REST API, convert to a PigeonDocument, and load it into the store. Returns { documentId, warnings }. |
| list_templates | List the four starter templates (welcome / newsletter / transactional / promo) and any saved during this session. |
| load_template | Hydrate a template into the document store. Returns the new documentId. |
| save_template | Snapshot the current document as a reusable template (kebab-case templateId). |
| delete_template | Remove a template by id. |
Every tool takes a documentId after create_document. The id is opaque — keep it around for the rest of the conversation.
Workflow example
User: Build me a welcome email for "Lumen App". One hero, one paragraph, one CTA button to https://lumen.app/start.
Model: [calls create_document { name: "Welcome to Lumen" }]
[calls add_row { columnCount: 1 }]
[calls add_block { blockType: "hero", values: { content: "<h1>Welcome to Lumen</h1>", backgroundUrl: "...", height: 280, ... } }]
[calls add_row { columnCount: 1 }]
[calls add_block { blockType: "text", values: { content: "<p>Thanks for joining ...</p>" } }]
[calls add_row { columnCount: 1 }]
[calls add_block { blockType: "button", values: { content: "<p>Get started</p>", href: "https://lumen.app/start" } }]
[calls render_to_html { documentId }]
Returns the HTML to the user.Programmatic embedding
You can also embed the server in your own Node process — e.g. behind an HTTP endpoint with the SSE transport:
import { buildServer } from '@lit-pigeon/mcp-server';
import { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js';
const { server } = buildServer();
const transport = new SSEServerTransport('/mcp', responseWriter);
await server.connect(transport);The DocumentStore is also exported if you want to persist documents elsewhere — supply your own via buildServer({ store }).
Figma import (live)
User: Use lit-pigeon to import this Figma frame as an email — file key
abcd1234, frame id 12:34. Token: figd_…
Model: [calls import_figma_frame { fileKey, frameId, accessToken }]
[calls render_to_html { documentId }]
…returns the rendered HTML.The tool fetches the Figma file via the REST API, converts the frame to a
PigeonDocument, and loads it into the same store as create_document —
follow it with update_block, render_to_html, etc. See
@lit-pigeon/figma-import for the conversion heuristics.
What's coming
- File-system-backed
TemplateStorage(so saved templates survive restarts) wired in viabuildServer({ templateStorage }).
License
MIT
