> ## Documentation Index
> Fetch the complete documentation index at: https://docs.subframe.com/llms.txt
> Use this file to discover all available pages before exploring further.

# MCP server

> Let AI coding assistants directly access and edit your Subframe designs and documentation.

The Subframe MCP server gives AI coding assistants like Claude Code, Cursor, and Codex direct access to your Subframe projects. AI can read, design, and delete pages, components, and snippets, read prototypes, write design documents, and edit the theme.

A separate Subframe Docs MCP server gives AI access to Subframe documentation (this site).

## Installation

<Tabs>
  <Tab title="Claude Code" icon="https://mintlify.s3.us-west-1.amazonaws.com/subframe-59800133/images/logos/claude.png">
    <Steps>
      <Step title="Install the Subframe plugin">
        ```bash theme={null} theme={null} theme={null} theme={null}
        claude plugin marketplace add https://github.com/SubframeApp/subframe && claude plugin install subframe@subframe
        ```

        The Subframe plugin for Claude Code sets up the MCP server and agent skills in one install.
      </Step>

      <Step title="Enable auto-update (recommended)">
        Keep the Subframe plugin up to date automatically:

        1. Run `/plugin` to open the plugin manager
        2. Select the **Marketplaces** tab
        3. Choose the **subframe** marketplace
        4. Select **Enable auto-update**
      </Step>

      <Step title="Verify installation">
        Run `/mcp` to check that the Subframe MCP server is connected, then try asking Claude Code to use Subframe.
      </Step>

      <Step title="Create your first design">
        Follow the [Working with AI agents](/learn/guides/working-with-ai-agents) guide to design and implement your first page.
      </Step>
    </Steps>
  </Tab>

  <Tab title="Claude Desktop" icon="https://mintlify.s3.us-west-1.amazonaws.com/subframe-59800133/images/logos/claude.png">
    <Steps>
      <Step title="Add the Subframe connector">
        1. Go to [**Customize > Connectors**](https://claude.ai/customize/connectors)
        2. Click <Icon icon="plus" size={16} /> and select **Add custom connector**
        3. Set the name to **Subframe**
        4. For **Remote MCP Server URL**, paste the following URL:
           ```
           https://mcp.subframe.com/mcp
           ```
        5. Click **Add**
      </Step>

      <Step title="Authenticate">
        Find the Subframe connector in your connectors list and click **Connect**. Follow the instructions on the Subframe website to complete authentication.
      </Step>

      <Step title="Create your first design">
        Follow the [Working with AI agents](/learn/guides/working-with-ai-agents) guide to design and implement your first page.
      </Step>
    </Steps>
  </Tab>

  <Tab title="Cursor" icon="https://mintlify.s3.us-west-1.amazonaws.com/subframe-59800133/images/logos/cursor.webp">
    <Steps>
      <Step title="Install MCP servers">
        Add the Subframe MCP servers to Cursor. You'll be prompted to authenticate via OAuth.

        * [Add Subframe MCP server to Cursor ↗](https://cursor.com/en-US/install-mcp?name=subframe\&config=eyJ1cmwiOiJodHRwczovL21jcC5zdWJmcmFtZS5jb20vbWNwIn0%3D)
        * (Optional) [Add Subframe Docs MCP server to Cursor ↗](https://cursor.com/en-US/install-mcp?name=subframe-docs\&config=eyJ1cmwiOiJodHRwczovL2RvY3Muc3ViZnJhbWUuY29tL21jcCJ9)

        <Accordion title="Troubleshooting: Manual installation">
          If the install links don't work, make the following changes to `~/.cursor/mcp.json`.

          ```json ~/.cursor/mcp.json theme={null} theme={null} theme={null} theme={null}
          {
            "mcpServers": {
              "subframe": {
                "url": "https://mcp.subframe.com/mcp"
              },
              "subframe-docs": {
                "url": "https://docs.subframe.com/mcp"
              }
            }
          }
          ```

          Cursor will handle OAuth authentication automatically when you first connect.
        </Accordion>
      </Step>

      <Step title="Install agent skills">
        Agent skills are guided workflows that teach Cursor how to best use Subframe. Install them with:

        ```bash theme={null} theme={null} theme={null} theme={null}
        npx skills add https://github.com/SubframeApp/subframe --skill '*' -g --agent cursor --yes
        ```
      </Step>

      <Step title="Verify installation">
        Check that the Subframe MCP server has successfully connected in **Cursor Settings** > **MCP**, then try asking Cursor to use Subframe.
      </Step>

      <Step title="Create your first design">
        Follow the [Working with AI agents](/learn/guides/working-with-ai-agents) guide to design and implement your first page.
      </Step>
    </Steps>
  </Tab>

  <Tab title="Codex" icon="https://mintlify.s3.us-west-1.amazonaws.com/subframe-59800133/images/logos/openai.png">
    <Steps>
      <Step title="Install MCP servers">
        Run the following commands to add the Subframe MCP servers and authenticate:

        ```bash theme={null} theme={null} theme={null} theme={null}
        codex mcp add subframe --url https://mcp.subframe.com/mcp && codex mcp add subframe-docs --url https://docs.subframe.com/mcp && codex mcp login subframe
        ```

        <Accordion title="Troubleshooting: Manual installation">
          If the commands above don't work, add the following to `~/.codex/config.toml`:

          ```toml ~/.codex/config.toml theme={null} theme={null} theme={null} theme={null}
          [mcp_servers.subframe]
          url = "https://mcp.subframe.com/mcp"

          [mcp_servers.subframe-docs]
          url = "https://docs.subframe.com/mcp"
          ```

          Then authenticate:

          ```bash theme={null} theme={null} theme={null} theme={null}
          codex mcp login subframe
          ```
        </Accordion>
      </Step>

      <Step title="Install agent skills">
        Agent skills are guided workflows that teach Codex how to best use Subframe. Install them with:

        ```bash theme={null} theme={null} theme={null} theme={null}
        npx skills add https://github.com/SubframeApp/subframe --skill '*' -g --agent codex --yes
        ```
      </Step>

      <Step title="Verify installation">
        Run `/mcp` in Codex to check that the Subframe MCP server is connected, then try asking Codex to use Subframe.
      </Step>

      <Step title="Create your first design">
        Follow the [Working with AI agents](/learn/guides/working-with-ai-agents) guide to design and implement your first page.
      </Step>
    </Steps>
  </Tab>

  <Tab title="Other clients">
    <Steps>
      <Step title="Configure the Subframe MCP Server">
        Configure your MCP client to connect to the Subframe MCP server:

        * **URL:** `https://mcp.subframe.com/mcp`
        * **Transport:** HTTP
        * **Authentication:** OAuth (your client will handle the authentication flow)
      </Step>

      <Step title="Configure the Subframe Docs MCP Server (optional)">
        Optionally add the Subframe Docs MCP server for documentation access:

        * **URL:** `https://docs.subframe.com/mcp`
        * **Transport:** HTTP
        * **Authentication:** None required
      </Step>

      <Step title="Install agent skills (optional)">
        If your client supports the [Agent Skills](https://agentskills.io) standard, install the Subframe skills with:

        ```bash theme={null} theme={null} theme={null} theme={null}
        npx skills add https://github.com/SubframeApp/subframe --skill '*' --agent '*' --yes
        ```
      </Step>

      <Step title="Verify installation">
        Restart your MCP client, then check that the Subframe MCP server has successfully connected and try asking your AI assistant to use Subframe.
      </Step>

      <Step title="Create your first design">
        Follow the [Working with AI agents](/learn/guides/working-with-ai-agents) guide to design and implement your first page.
      </Step>
    </Steps>
  </Tab>
</Tabs>

## Using the MCP server

Once configured, your AI assistant can access Subframe automatically when you prompt or paste an MCP link to a page from the Code panel.

You can get the MCP link for any design by either:

* Copying the link from the browser address bar
* Copying the link under **Code** > **Inspect** in Subframe

<Frame>
  <img src="https://mintlify.s3.us-west-1.amazonaws.com/subframe-59800133/images/developers/copy-mcp-link.png" alt="Copy MCP link from Subframe" />
</Frame>

## Available tools

The Subframe MCP server exposes tools across several categories. Most read tools take a `projectId`. If omitted, the first project the user has access to is used.

### Discovery

| Tool                  | Description                                              | Returns                                                   |
| --------------------- | -------------------------------------------------------- | --------------------------------------------------------- |
| `list_projects`       | Lists all projects you have access to                    | Array of `projectId`, `name`, `teamId`, `teamName`        |
| `generate_auth_token` | Generates a CLI auth token for a team                    | `authToken`                                               |
| `get_project_info`    | Project metadata plus all project-level design documents | `id`, `name`, `docs` (array of `id`, `title`, `contents`) |

### Pages

| Tool            | Description                                                                                                                                                                                                                                                               | Key inputs                                                                                    | Returns                                                              |
| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- |
| `list_pages`    | List all pages with the flow each belongs to                                                                                                                                                                                                                              | `projectId`                                                                                   | Array of `id`, `name`, `url`, `lastModifiedAt`, `flowId`, `flowName` |
| `get_page_info` | Generated React/Tailwind code for a page. Pass `includeNodeIds: true` to get a `data-node-id` on every element for use with `edit_page`                                                                                                                                   | `id`/`name`/`url`, `projectId`, `includeNodeIds?`                                             | `id`, `name`, `lastModifiedAt`, `files`                              |
| `design_page`   | Generates 1-4 page variations as an asynchronous background job. Variations land as pages in a flow as they finish                                                                                                                                                        | `description`, `variations`, `flowName`, `projectId`, `codeContext?`, `additionalReferences?` | `flowId`, `flowUrl`, `jobId`                                         |
| `edit_page`     | Apply a targeted edit to one node of an existing page — `replace` the node and its subtree, `insert-above`/`insert-below` a new sibling, or `delete` it. Call `get_page_info` with `includeNodeIds: true` first to get each element's `data-node-id`. Applied immediately | `id`/`name`/`url`, `nodeId`, `operation`, `code`, `projectId`                                 | `pageUrl`, `appliedCode?`, `warnings?`                               |
| `delete_page`   | Delete a page, removing it from its flow and stripping prototype actions referencing it. Refuses by default if referenced in other pages. Use `force: true` to delete anyway                                                                                              | `id`/`name`/`url`, `projectId`, `force?`                                                      | `deletedId`, `deletedName`, `references`                             |

### Components

| Tool                 | Description                                                                                                                                                                                                                                                                                             | Key inputs                                                             | Returns                                                    |
| -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------- | ---------------------------------------------------------- |
| `list_components`    | List all components                                                                                                                                                                                                                                                                                     | `projectId`                                                            | Array of `id`, `name`, `url`, `lastModifiedAt`             |
| `get_component_info` | Generated code plus attached design document                                                                                                                                                                                                                                                            | `id`/`name`/`url`, `projectId`                                         | `id`, `name`, `lastModifiedAt`, `files`, `designDocuments` |
| `design_component`   | Designs a new component as an asynchronous background job                                                                                                                                                                                                                                               | `description`, `name`, `projectId`, `additionalReferences?`            | `componentId`, `componentUrl`, `jobId`                     |
| `edit_component`     | Edit an existing component as an asynchronous background job. Propagates to every page using the component                                                                                                                                                                                              | `id`/`name`/`url`, `description`, `projectId`, `additionalReferences?` | `componentUrl`, `jobId`                                    |
| `delete_component`   | Delete a component or custom page layout. Detachable components detach their instances; non-detachable ones delete instances; page layouts clear assignments. Some built-in components can't be deleted (`force` does not override). Refuses by default if in use — pass `force: true` to delete anyway | `id`/`name`/`url`, `projectId`, `force?`                               | `deletedId`, `deletedName`, `references`                   |

### Snippets

Snippets are small, standalone bits of UI typically embedded inside design documents as live examples (e.g. a "Button variants" snippet showing every Button state). They live within Subframe and do not sync out.

| Tool               | Description                                                                                                                                     | Key inputs                                                                   | Returns                                        |
| ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------- | ---------------------------------------------- |
| `list_snippets`    | List all snippets                                                                                                                               | `projectId`                                                                  | Array of `id`, `name`, `url`, `lastModifiedAt` |
| `get_snippet_info` | Generated code for a snippet. Pass `includeNodeIds: true` to get a `data-node-id` on every element for use with `edit_snippet`                  | `id`/`name`/`url`, `projectId`, `includeNodeIds?`                            | `id`, `name`, `lastModifiedAt`, `files`        |
| `design_snippet`   | Design a new snippet                                                                                                                            | `description`, `name?`, `projectId`, `codeContext?`, `additionalReferences?` | `snippetId`, `snippetUrl`                      |
| `edit_snippet`     | Apply a targeted edit to one node of an existing snippet (same model as `edit_page`). Call `get_snippet_info` with `includeNodeIds: true` first | `id`/`name`/`url`, `nodeId`, `operation`, `code`, `projectId`                | `snippetUrl`, `appliedCode?`, `warnings?`      |
| `delete_snippet`   | Delete a snippet. Any design document embeds are removed automatically                                                                          | `id`/`name`/`url`, `projectId`                                               | `deletedId`, `deletedName`                     |

### Flows

A flow is a collection of related pages (e.g. "Onboarding", "Checkout").

| Tool            | Description                                                                                                            | Key inputs                                          | Returns                                      |
| --------------- | ---------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------- | -------------------------------------------- |
| `list_flows`    | List all flows                                                                                                         | `projectId`                                         | Array of `id`, `name`, `pageCount`           |
| `get_flow_info` | A flow with its name and ordered pages                                                                                 | `id`/`name`/`url`, `projectId`                      | `id`, `name`, `pages`                        |
| `delete_flow`   | Delete a flow. Refuses if it contains pages. Use `deleteChildPages: true` to delete the flow plus every page inside it | `id`/`name`/`url`, `projectId`, `deleteChildPages?` | `deletedId`, `deletedName`, `deletedPageIds` |

### Prototypes

A prototype is an interactive, AI-built running app — its own React + Vite codebase — created in the Subframe prototyping editor. The read tools below expose a prototype as a standalone, runnable Vite app: internal scaffolding is dropped and the Vite/Tailwind config plus an entrypoint are added, so the file paths and contents you get back are ready to run with `npm install && npm run dev`.

| Tool                  | Description                                                             | Key inputs                    | Returns                                 |
| --------------------- | ----------------------------------------------------------------------- | ----------------------------- | --------------------------------------- |
| `list_prototypes`     | List all prototypes in a project                                        | `projectId`                   | Array of `id`, `name`, `lastModifiedAt` |
| `get_prototype_info`  | A prototype's metadata and the list of files in its runnable Vite app   | `id`, `projectId`             | `id`, `name`, `lastBuiltAt`, `files`    |
| `read_prototype_file` | Read the contents of a single file from a prototype's runnable Vite app | `id`, `filePath`, `projectId` | `id`, `filePath`, `contents`            |

### Design documents

Design documents are markdown files that convey how to work within your design system — brand voice, design principles, component usage rules ("when to use Toggle vs. Checkbox"), accessibility requirements, do/don't examples. AI automatically reads them when designing or implementing. **Project-scoped** docs (many per project) cover broad guidance; **component-scoped** docs (one per component, attached directly to it) cover specifics for that component.

| Tool                    | Description                                                                                                                                                                                                               | Key inputs                                                                            | Returns                     |
| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------- | --------------------------- |
| `write_design_document` | Create or update a markdown design document. Project-scoped if no `componentId`; component-scoped otherwise. Snippet examples can be embedded like so `<div data-type="component-example" data-component-id="..."></div>` | `content`, `id?`, `componentId?`, `title?`, `projectId`, `mode?` (`replace`/`append`) | `documentId`, `documentUrl` |

Read existing docs first via `get_project_info` (project-level) or `get_component_info` (component-level). When updating, always pass the existing `id` — components allow at most one design document, and creating a second is rejected.

### Theme

| Tool         | Description                                                                                                                                                                                                                                                                                                                                           | Key inputs                 | Returns        |
| ------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------- | -------------- |
| `get_theme`  | Generate the Tailwind theme for the project                                                                                                                                                                                                                                                                                                           | `projectId`, `cssType?`    | `theme` config |
| `edit_theme` | Edits the project's visual theme (colors, fonts, corners, shadows, typography) from a natural-language prompt. Applies immediately to the whole project. Supports adding tokens, changing token values, renaming tokens, and **deleting tokens (destructive — references in designs are replaced with the token's concrete value at deletion time)**. | `description`, `projectId` | `themeUrl`     |

### Async jobs

| Tool            | Description                                                                                                                                               | Key inputs      | Returns                                                               |
| --------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------- | --------------------------------------------------------------------- |
| `wait_for_jobs` | Wait for background AI jobs to finish. Each result is `running`, `done` (with optional summary), or `not_found`. Call in a loop until every job is `done` | `jobIds` (1-10) | Array of `jobId`, `status` (`running`/`done`/`not_found`), `summary?` |

`design_page`, `design_component`, and `edit_component` return a `jobId` alongside their URL. The URL can be used immediately to view the real-time progress of the job in the editor. Pass the `jobId(s)` to `wait_for_jobs` before reading back the generated content with `get_page_info`, `get_component_info`, `get_snippet_info`, or `get_flow_info` — those reads return empty/stale state until the job is done.

## Prompt with MCP link

When prompting we recommend using the MCP link found in the Code Inspect panel for a page.

```text theme={null}
Implement the design at https://app.subframe.com/design/...
```

<Note>
  To get the latest version of components in your project, run `npx @subframe/cli@latest sync` to [sync
  components](/concepts/syncing-components).
</Note>

## Example prompts

<AccordionGroup>
  <Accordion title="Implement a new page from a design">
    ```text theme={null}
    Create a new page using the Subframe page at
    https://app.subframe.com/PROJECT_ID/design/DESIGN_ID/edit as reference.

    Wire up relevant app logic (API calls, hooks, routing) where applicable.
    Keep it consistent with existing project conventions.
    ```
  </Accordion>

  <Accordion title="Update an existing page with a new design">
    ```text theme={null}
    Update the existing page to match the Subframe design at
    https://app.subframe.com/PROJECT_ID/design/DESIGN_ID/edit.

    Preserve all existing functionality unless the new design requires a change.
    ```
  </Accordion>

  <Accordion title="Design a new component">
    ```text theme={null}
    Design a PrivacyToggle component in Subframe. It should have an on/off state,
    a label, and a description below the label. Use the same toggle styling as
    our existing Toggle component.
    ```
  </Accordion>

  <Accordion title="Write a design document">
    ```text theme={null}
    Write a design doc for the Toggle component covering when to use it,
    accessibility considerations, and a snippet showing all variants.
    ```
  </Accordion>

  <Accordion title="Delete unused components">
    ```text theme={null}
    List the components in my Subframe project and help me delete any that
    aren't being used in any pages.
    ```
  </Accordion>

  <Accordion title="Add accessibility tags in code">
    ```text theme={null}
    Review the Subframe design at
    https://app.subframe.com/PROJECT_ID/design/DESIGN_ID/edit and add proper
    accessibility attributes to the existing page.

    Add ARIA labels, roles, and descriptions, and proper semantic HTML throughout.
    ```
  </Accordion>

  <Accordion title="Migrate to Subframe's design system">
    ```text theme={null}
    Migrate the components on the existing page to use Subframe components instead
    of the old components.

    Get all components in my Subframe project and preserve all existing
    functionality unless the new design requires a change.
    ```
  </Accordion>

  <Accordion title="Fetch a component">
    ```text theme={null}
    Get the Button component from Subframe and use it in this file.
    ```
  </Accordion>

  <Accordion title="List available components">
    ```text theme={null}
    Show me all components in my Subframe project.
    ```
  </Accordion>

  <Accordion title="Get the theme">
    ```text theme={null}
    Get my Subframe theme configuration.
    ```
  </Accordion>
</AccordionGroup>

## Troubleshooting

<AccordionGroup>
  <Accordion title="Authentication failed">
    The Subframe MCP server uses OAuth. If you're seeing authentication errors:

    * Try re-authenticating by reconnecting to the MCP server in your client
    * Check that you have the correct permissions for the project you're trying to access
    * Make sure your browser session is active when authenticating
    * Confirm your client supports MCP OAuth — Subframe access tokens are not accepted by the MCP server
  </Accordion>

  <Accordion title="AI not calling the server">
    Make sure your AI tool:

    * Has MCP support enabled
    * Has the Subframe server in its MCP configuration
    * Has been restarted after adding the configuration

    Check your tool's logs for MCP-related errors.
  </Accordion>

  <Accordion title="Component or page not found">
    Use `list_components`, `list_pages`, `list_snippets`, or `list_flows` to see what's available.

    Verify:

    * The component/page/snippet exists in your Subframe project
    * The name or URL matches exactly
    * You have access to the project
  </Accordion>

  <Accordion title="Background job seems stuck">
    `design_page`, `design_component`, and `edit_component` run as background jobs. Check `wait_for_jobs` with the `jobId` returned by the design tool — it reports `running`, `done`, or `not_found`. The URL is live throughout, so opening it in the editor shows real-time progress.

    If a job stays `running` longer than \~10 minutes, the server treats it as stalled (worker died, request timed out) and reports it as `done` to unblock polling. Open the URL to see whether anything was actually generated; the chat panel surfaces any errors from the AI agent.
  </Accordion>

  <Accordion title="Connection errors">
    If the MCP server is unreachable:

    * Check your internet connection
    * Verify the URL is `https://mcp.subframe.com/mcp`
    * Reach out to the Subframe team for support
  </Accordion>
</AccordionGroup>
