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

# MCP Server

> Operate your Merchkit catalog from Claude, ChatGPT, VS Code, and other agents over the remote MCP server. Connect in one click with OAuth and no API key, or authenticate with a workspace API key for programmatic use.

Merchkit exposes a remote MCP server so you can operate your catalog directly from Claude,
ChatGPT, VS Code (GitHub Copilot), Cursor, and any other MCP-capable agent. MCP is a superset of
the REST API with identical shapes. Every tool emits the same
[one-map resource](/developers/conventions#resource-anatomy), event, and job shapes as REST, takes
snake\_case arguments, and runs the same validation. What you learn from these docs applies to both.

<Note>
  Examples use `https://www.merchkit.com` as the base URL.
</Note>

<ParamField path="MCP endpoint" type="string">
  `https://www.merchkit.com/api/mcp` — a remote MCP server over **Streamable HTTP**.
</ParamField>

## Connect in one click

The MCP endpoint speaks OAuth 2.1, so most agents connect with a button. Click, sign in to
Merchkit, choose the workspace and the permissions to grant, and approve. There is no API
key to create, copy, or paste, and you can revoke the connection at any time from **Settings → API
keys → Connected apps**.

<CardGroup cols={2}>
  <Card title="Add to Claude" icon="robot" href="https://claude.ai/customize/connectors?modal=add-custom-connector&connectorName=Merchkit&connectorUrl=https%3A%2F%2Fwww.merchkit.com%2Fapi%2Fmcp">
    Opens claude.ai with the Merchkit connector pre-filled. Works on Claude web and Claude Desktop.
  </Card>

  <Card title="Install in VS Code" icon="code" href="https://insiders.vscode.dev/redirect/mcp/install?name=merchkit&config=%7B%22type%22%3A%22http%22%2C%22url%22%3A%22https%3A%2F%2Fwww.merchkit.com%2Fapi%2Fmcp%22%7D">
    Adds the Merchkit MCP server to VS Code for GitHub Copilot agent mode.
  </Card>
</CardGroup>

<Callout type="info">
  Whichever client you use, the URL to add is always **`https://www.merchkit.com/api/mcp`**. On the
  consent screen the default permissions are everything except the delete scopes. Tighten them
  to a read-only set for an agent that should only inspect your catalog.
</Callout>

### Claude (web & Desktop)

Click **Add to Claude** above, or add it manually: **Settings → Connectors → Add custom connector**,
paste `https://www.merchkit.com/api/mcp`, and click **Add**. Claude opens the Merchkit consent
screen where you pick a workspace, choose scopes, and approve. Then the tools appear. No `claude_desktop_config.json`
editing and no `mcp-remote` bridge required.

### Claude Code

```bash theme={null}
claude mcp add --transport http merchkit https://www.merchkit.com/api/mcp
```

Then run `/mcp` and select **merchkit** to complete the browser sign-in. No key or header needed.

### ChatGPT

ChatGPT supports custom remote MCP connectors through **developer mode**, on the web app and a paid
plan (Plus, Pro, Business, Enterprise, or Edu). There is no one-click link, so add it manually:

<Steps>
  <Step title="Enable developer mode">
    In ChatGPT on the web, open **Settings → Apps & Connectors → Advanced settings** and turn on
    **developer mode**. On Business/Enterprise/Edu a workspace admin must enable it first.
  </Step>

  <Step title="Create the connector">
    On **Apps & Connectors**, click **Create**, give it a name, and paste the server URL
    `https://www.merchkit.com/api/mcp`. For authentication choose **OAuth** and leave the client-id
    and client-secret fields blank. ChatGPT registers itself.
  </Step>

  <Step title="Sign in and use it">
    Click **Create** and complete the Merchkit sign-in. The tools then appear from the **+** menu in
    a chat.
  </Step>
</Steps>

### VS Code / GitHub Copilot & Cursor

Click **Install in VS Code** above, or add it from the command line:

```bash theme={null}
code --add-mcp '{"name":"merchkit","type":"http","url":"https://www.merchkit.com/api/mcp"}'
```

For **Cursor**, open **Settings → MCP → Add** and paste `https://www.merchkit.com/api/mcp`. VS Code
and Cursor both run the OAuth sign-in on first connect. No key required.

## Authenticate with an API key (programmatic)

For servers, scripts, CI, or any client without a browser to sign in, authenticate with a
**workspace API key** instead. It is the same `mk_live_` bearer token the REST API uses:

```http theme={null}
Authorization: Bearer mk_live_...
```

The key's scopes apply identically here: a read-only key can call the read tools but not the write
tools. See [Authentication](/developers/authentication) for the full key + scope model.

<Callout type="warning">
  An API key is a secret with workspace access. Store it in a secret manager or environment
  variable, never in a shared config file. For interactive agents, prefer the one-click OAuth
  connect above: it keeps no key on disk and is revocable per connection.
</Callout>

<Callout type="info">
  For a local, stdio-only MCP client that cannot reach a remote HTTP server, bridge to it with
  [`mcp-remote`](https://www.npmjs.com/package/mcp-remote):
  `npx -y mcp-remote https://www.merchkit.com/api/mcp`. Add `--header "Authorization: Bearer mk_live_..."`
  if the client cannot complete the OAuth sign-in itself.
</Callout>

## Write tools require confirmation

Every write tool takes a `confirm` flag so the agent can preview a change before applying it.

<Steps>
  <Step title="Preview">
    Call the tool with `confirm` omitted or `false`. The tool returns a **diff** describing exactly
    what would change, and makes no change.
  </Step>

  <Step title="Apply">
    Call the same tool again with `confirm: true` to apply the change.
  </Step>
</Steps>

<Callout type="info">
  This two-step flow lets an agent show you the intended change and get your sign-off before anything
  is written.
</Callout>

## Tools

The tools are generic over entity type. One `list_entities` replaces a tool per resource,
with `type` as a parameter exactly like the REST path segment:
`product | image | vendor | category | source`. Read tools require the resource's `read:*` scope;
write tools require the matching `write:*` scope. See
[scopes](/developers/authentication#scopes).

### Read tools

| Tool                                                                  | What it does                                                                                                                                                                                                                                                                                                                                                       |
| --------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `list_entities(type, filters?, filter_join?, sort?, limit?, offset?)` | List and search any entity type. Filters are structured objects — `{attribute_key, operator, value}` — with the same semantics **and the same short operator spellings** as the REST [filter grammar](/developers/conventions#filtering-and-sorting): `eq`, `ne`, `contains`, `not_contains`, `starts_with`, `ends_with`, `gt`, `gte`, `lt`, `lte`, `exists`, `in` |
| `get_entity(id, type)`                                                | Fetch one entity's full detail (the one-map shape, references complete)                                                                                                                                                                                                                                                                                            |
| `list_variants(id, limit?, offset?)`                                  | List a product's variants (children)                                                                                                                                                                                                                                                                                                                               |
| `get_references(id, type, attribute?)`                                | The key-scoped reference view with explicit positions — and **the** way to walk [inverse references](/developers/conventions#inverse-references-are-queries-not-data), which never appear in `attributes`                                                                                                                                                          |
| `get_completeness(product_id, channel)`                               | Per-channel completeness with actionable issues                                                                                                                                                                                                                                                                                                                    |
| `list_events(since?, entity_id?, limit?)`                             | The [change feed](/developers/conventions#events-the-change-feed) — workspace-wide, or scoped to one entity                                                                                                                                                                                                                                                        |
| `list_attributes(type, channel?)`                                     | Attribute definitions — schema discovery                                                                                                                                                                                                                                                                                                                           |
| `get_attribute(key, type?)`                                           | One attribute definition                                                                                                                                                                                                                                                                                                                                           |
| `list_channels()`                                                     | The enabled channel catalog                                                                                                                                                                                                                                                                                                                                        |
| `list_jobs()` / `get_job(id)`                                         | List / poll async [jobs](/developers/conventions#async-jobs)                                                                                                                                                                                                                                                                                                       |

### Write tools

Every write tool follows the preview-then-`confirm` flow above.

| Tool                                                     | What it does                                                                                                                                                                                                                        |
| -------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `create_entity(type, parent_id?, attributes)`            | Create any entity — references inline, exactly like `POST /v1/{resource}`. `type: "source"` fires the same async processing pipeline as `POST /v1/sources`                                                                          |
| `update_entity(id, type, parent_id?, attributes?)`       | The one write path — set values, references, or the variant parent                                                                                                                                                                  |
| `upsert_entity(type, merge_key, parent_id?, attributes)` | Create-or-update by your own key (usually `sku`) — mirrors `POST /v1/{resource}/upsert`                                                                                                                                             |
| `upsert_entities(type, merge_key, items ≤100)`           | Bulk create-or-update — mirrors `POST /v1/{resource}/batch` exactly, returning the same `{summary, data}` per-item results. The preview (`confirm: false`) is deliberately compact: item count + sample merge values, not 100 diffs |
| `create_attribute` / `update_attribute`                  | Manage attribute definitions, including AI-generation config                                                                                                                                                                        |

### MCP-only tools

MCP is a superset. Grid views and attribute classes left the public REST surface and live only
here.

| Tool                                                                          | Scope                        | What it does                                                                                                                                                                                                                                                                            |
| ----------------------------------------------------------------------------- | ---------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `list_grid_views` / `get_grid_view` / `create_grid_view` / `update_grid_view` | `read:views` / `write:views` | Saved grid (table) views                                                                                                                                                                                                                                                                |
| `set_grid_view_column_visibility(grid_view_id, col_ids, hidden?)`             | `write:views`                | Show/hide specific columns **in place** — column order, widths, pinning, sorting, and filters are preserved exactly (`update_grid_view` rebuilds the layout; use this for visibility-only changes). Preview reports exactly what would flip; unmatched keys are reported, never guessed |
| `reorder_grid_views(type, grid_view_ids)`                                     | `write:views`                | Reorder an entity type's view tabs. Takes **every** view id of that type in the desired order; partial lists are rejected with what's missing                                                                                                                                           |
| `list_attribute_classes` / `get_attribute_class`                              | `read:attributes`            | Attribute classes (cell-disabling rule sets)                                                                                                                                                                                                                                            |
| `create_attribute_class` / `update_attribute_class`                           | `write:attributes`           | Create / update attribute classes                                                                                                                                                                                                                                                       |

<Callout type="warning">
  **Deletes are disabled during the beta.** Destructive operations are turned off across both REST
  and MCP: no delete tool is exposed and `DELETE` endpoints return `403`, even for a key or
  connection that holds a `delete:*` scope. Deletes will be enabled in a later release. See
  [Authentication](/developers/authentication#beta-limitation-deletes-are-disabled).
</Callout>

## Working with vendors, categories, and images

Products point at other entities (a vendor, a category, their images) through
**[reference attributes](/developers/conventions#reference-stubs-and-symmetric-writes)**.
A reference always holds the other entity's `id`, so the entity has to exist before a product can
point at it. `list_entities` and `create_entity` cover that: look up what already exists, create
what doesn't, then set the reference.

For example, to file a product under a "Trail Running" category:

<Steps>
  <Step title="Look for the category first">
    ```json theme={null}
    {
      "tool": "list_entities",
      "arguments": {
        "type": "category",
        "filters": [{ "attribute_key": "name", "operator": "contains", "value": "Trail Running" }]
      }
    }
    ```

    If it exists, use its `id` and skip to step 3. Search with `contains` rather than an exact
    match. It also surfaces near-duplicates, which keeps your catalog clean: one "Trail Running",
    not five spellings of it.
  </Step>

  <Step title="Create it if it's missing">
    ```json theme={null}
    {
      "tool": "create_entity",
      "arguments": {
        "type": "category",
        "attributes": { "name": "Trail Running" },
        "confirm": true
      }
    }
    ```

    `create_entity` is a write tool, so the same preview-then-confirm flow applies. The response is
    the full new resource, including its `id`.
  </Step>

  <Step title="Point the product at it">
    ```json theme={null}
    {
      "tool": "update_entity",
      "arguments": {
        "id": "9b2f6c1e-8a04-4c6e-b0d3-5f2f6f7a9e21",
        "type": "product",
        "attributes": { "category": "<category-id>" },
        "confirm": true
      }
    }
    ```

    Single references take one entity ID (or an `{id}` stub; read stubs re-sent verbatim are valid
    writes); list references (like `gallery_images`) take an array, replace semantics.
  </Step>
</Steps>

The same pattern works for vendors and images. Creating an image entity records a hosted image
URL, its `url` attribute. To upload files or pull images down from the web, use the image library
in the app or a [CSV import](/product/sources-and-importing/importing-first-catalog-csv).

<Callout type="info">
  A reference can only point at an entity that already exists,
  so a typo in a reference value fails loudly instead of silently minting a new vendor. When you
  check for near-duplicates before creating, search with `contains`. Matching is case-insensitive,
  and a wider net catches alternate spellings an exact match would miss.
</Callout>
