An MCP server that lets an LLM design web pages in a Framer project via the Framer Server API (currently in open beta).
Scoped to page-design and CMS operations — create pages, frames, text, components, styles, and code files; read and update CMS collections and items; screenshot the result. Publishing workflows are intentionally excluded (see "Out of scope" below).
npm install
npm run buildframer-api uses the global WebSocket constructor, which is built in on
Node.js ≥ 22. On Node 20 you must launch with --experimental-websocket.
# Node 22+
node dist/index.js
# Node 20 — flag required, else tools fail with "rr is not a constructor"
node --experimental-websocket dist/index.jsThe Claude Desktop config in the next section includes the flag for Node 20 compatibility; remove it if you're on Node 22+.
The server reads a single-project configuration from environment variables:
| Variable | Required | Description |
|---|---|---|
FRAMER_PROJECT_URL |
yes | e.g. https://framer.com/projects/Sites--aabbccddeeff |
FRAMER_API_KEY |
yes | Generate in Framer → Site Settings → General. The key is bound to this one project. |
FRAMER_LOG_LEVEL |
no | error | warn | info | debug (default warn). Logs go to stderr. |
One server instance serves one project. Run multiple instances with different env files to target multiple projects.
Add to an MCP client (e.g. Claude Desktop claude_desktop_config.json):
{
"mcpServers": {
"framer-design": {
"command": "/absolute/path/to/node",
"args": ["--experimental-websocket", "/absolute/path/to/framer-design-mcp-server/dist/index.js"],
"env": {
"FRAMER_PROJECT_URL": "https://framer.com/projects/Sites--aabbccddeeff",
"FRAMER_API_KEY": "ap_..."
}
}
}
}Or inspect interactively:
FRAMER_PROJECT_URL=... FRAMER_API_KEY=... npm run inspect44 tools prefixed framer_. All open a fresh Framer connection per call (via
withConnection), retry transient SDK errors, and return structured JSON.
| Group | Tools |
|---|---|
| Inspection (read-only) | get_project_info, get_current_user, get_canvas_root, list_pages, get_node, get_node_children, list_descendants, get_node_parent, get_node_rect, find_nodes_by_type, find_nodes_by_attribute, find_nodes_by_name |
| Pages | create_page (kind: web | design) |
| Nodes | create_frame, create_text_node, create_component_node, add_component_instance, set_node_attributes, set_text, set_parent, clone_node, remove_node, add_svg |
| Assets | upload_asset (kind: image | file), add_image |
| Styles | list_color_styles, create_color_style, list_text_styles, create_text_style, list_fonts |
| Code | list_code_files, get_code_file, create_code_file, typecheck_code |
| CMS | list_collections, get_collection, list_collection_items, get_collection_item, create_collection, update_collection_fields (mode: add | remove | setOrder), upsert_collection_items, remove_collection_items, set_collection_item_order |
| Visual | screenshot_node, export_svg |
framer_screenshot_node returns PNG/JPEG as inline MCP image content — an
agent can call it after every design edit to visually verify the result before
continuing.
These Framer Server API surfaces are not exposed by this server:
- Publishing —
publish,deploy,getChangedPaths,getChangeContributors - Redirects, localization
- ManagedCollection writes (CMS collections owned by other plugins are read-only at the SDK level)
- Per-field schema updates (
Field.setAttributes) — the CMS surface covers add/remove/reorder fields only
If you need them, a separate tools/publishing.ts module can be added; it
would share the existing withFramer wrapper.
See evals/framer-design-eval.xml for 10 Q/A pairs that validate this server against a seeded test project. The eval questions assume a fixture Framer project — read the comment at the top of the eval file for seed requirements.