Skip to main content
Glama
craveup-oss

CraveUp MCP Server

Official
by craveup-oss
README.md
# Crave Up MCP Server

<div align="center">

**A Model Context Protocol (MCP) server that lets AI agents onboard restaurant brands and manage [Crave](https://craveup.com) menus, storefronts, and mobile releases — entirely from natural language in chat**

[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](#license)
[![npm](https://img.shields.io/npm/v/@craveup/mcp?label=npm)](https://www.npmjs.com/package/@craveup/mcp)
[![Tests](https://img.shields.io/badge/tests-passing-brightgreen.svg)](#testing)

[Quick Start](#quick-start) | [Available Tools](#available-tools) | [Authentication](#authentication) | [Documentation](#documentation)

</div>

---

## Overview

This MCP server provides Crave platform integration for Claude Code, Cursor, and other MCP-compatible clients. It covers the full merchant lifecycle: creating an organization, wiring a repo, importing menus, configuring locations, going live with subscriptions and payments, managing discounts, and dispatching guarded Expo/EAS mobile releases.

### Key Features

- **Lifecycle Tooling** — browser auth, onboarding, go-live, location settings, menus, discounts, readiness checks, mobile releases, and sandbox data
- **Natural-Language Onboarding** — _"hook up this repo for Demo Bistro"_ → login → create org → wire `.env` → import menu → run iOS
- **Idempotent Writes** — menu imports, discount creation, and sandbox seeding are safe to re-run
- **Guarded Mobile Releases** — internal TestFlight only; paid EAS work requires a scoped Expo token plus explicit confirmation, and public App Store release remains human-controlled
- **TypeScript** — full type safety with Zod validation
- **Tested** — Vitest coverage for tools, clients, config, auth, and readiness logic

> Note: this is a local MCP server. It runs as a stdio subprocess on the developer's machine. An agent can start secure Crave Up browser sign-in/sign-up through `start_crave_auth`; the resulting session is shared with the CLI.

> **After rebuilding** `packages/mcp/dist`, **restart the MCP server in your client** (or reload the window) so new tools appear.

---

## Quick Start

### Installation

```bash
# From npm (published package)
CRAVEUP_ENVIRONMENT=sandbox npx -y @craveup/mcp

# Inspect the executable without configuring credentials
npx -y @craveup/mcp --help

# Or from the monorepo
pnpm --filter @craveup/mcp build   # compiles to dist/
```

### Configuration

**Claude Code.** Register separate sandbox and production processes at user
scope so the environment boundary remains visible in every tool call. This is
a local stdio server, so there is no hosted MCP URL:

```bash
claude mcp add -s user craveup-sandbox \
  -e CRAVEUP_ENVIRONMENT=sandbox \
  -- npx -y @craveup/mcp

claude mcp add -s user craveup-production \
  -e CRAVEUP_ENVIRONMENT=production \
  -- npx -y @craveup/mcp
```

Run `/mcp` in Claude Code to inspect the registration. Start a new Claude Code
session if the current session does not refresh its tool inventory.

Do not switch an already-running server between environments. Use the
`craveup-sandbox` tools while building and testing, then explicitly select the
`craveup-production` tools when preparing to launch. Each process has its own
dashboard host, API-key prefix, Clerk configuration, and stored browser session.

**Option A — Full NL development bootstrap (recommended for new brands).** Register the MCP server **without** an API key. No repo checkout is needed:

```json
{
  "mcpServers": {
    "craveup": {
      "command": "npx",
      "args": ["-y", "@craveup/mcp"],
      "env": {
        "CRAVEUP_ENVIRONMENT": "sandbox"
      }
    }
  }
}
```

The agent calls `start_crave_auth`, opens the returned Crave Up URL, and then calls
`complete_crave_auth`. The user can sign in or create a free account in that browser flow. The
server stores the resulting shared CLI/MCP session in the macOS keychain (or
`~/.config/craveup/credentials.json`). Alternatively set `CRAVEUP_ACCESS_TOKEN` in the MCP env.

To exercise tools that are on `main` but not yet published, swap the command for the local build:
`"command": "node", "args": ["/path/to/craveup-turborepo/packages/mcp/dist/cli.js"]`.

**Option B — Menu-only (existing location + API key).** Create a merchant API key in Crave Business Manager → Settings → Developer → API Keys:

```json
{
  "mcpServers": {
    "craveup": {
      "command": "npx",
      "args": ["-y", "@craveup/mcp"],
      "env": {
        "CRAVEUP_ENVIRONMENT": "sandbox",
        "CRAVEUP_API_KEY": "crv_test_…",
        "CRAVEUP_LOCATION_ID": "<default location id>"
      }
    }
  }
}
```

`CRAVEUP_ENVIRONMENT` is required. The environment selects all dashboard, API, and Clerk hosts
together. `CRAVEUP_LOCATION_ID` is optional; every menu tool also accepts an explicit `locationId`.

**Mobile releases.** To dispatch mobile release workflows, also set a scoped Expo robot-user token in the MCP env:

```json
{
  "env": {
    "EXPO_TOKEN": "<scoped Expo robot-user token>"
  }
}
```

### Example chat flow

> "This demo-bistro repo — hook it up to Crave for Demo Bistro. Login if you need to, create the org, import the menu, and run it on the iOS simulator."

Agent sequence:

1. `whoami` — confirm the shared session
2. If needed: `start_crave_auth` → open its URL → `complete_crave_auth`
3. Create the organization in Business Manager while MCP organization creation is idempotency-blocked; create any scoped private key there, never through chat
4. `connect_project({ projectPath: "…/demo-bistro", locationId })`
5. `import_menu(…)` from the restaurant source
6. Run the storefront or iOS app locally
7. Exercise menu, fulfillment, and cart flows in sandbox; ordinary Stripe payment admission remains cutover locked
8. Only after direct-charge activation and an explicit production decision: switch environments and complete subscription and payment onboarding

---

## Available Tools

### Entities

CRUD-style operations are available for the following entity types:

| Entity | Create | Get | Update | Delete | List |
|--------|:------:|:---:|:------:|:------:|:----:|
| **Organization** | ✅ | - | - | - | - |
| **Location** | ✅ | - | ✅ | ✅ | ✅ |
| **Store Settings** | - | ✅ | ✅ | - | - |
| **Menu** | ✅ | - | ✅ | - | ✅ |
| **Product** | ✅¹ | ✅ | ✅ | ✅ | - |
| **Discount** | ✅ | - | - | - | ✅ |
| **Order** | - | - | - | - | ✅ |
| **Customer** | - | - | - | - | ✅ |
| **Subscription** | ✅² | - | - | - | ✅ |
| **Mobile Release** | ✅³ | ✅ | - | - | - |

¹ Products are created in bulk via `import_menu`. ² `start_subscription_checkout` opens a Stripe Checkout session; plans themselves are read-only. ³ `start_mobile_release` dispatches an EAS workflow run; deletion/cancellation stays in EAS.

### Checks & Guides

| Check | Tool Name | Description |
|-------|-----------|-------------|
| **Go-live Status** | `get_onboarding_status` | The dashboard's 6 go-live steps with completion state + next actions |
| **Storefront Readiness** | `check_storefront_readiness` | Reads `ordering-readiness` without creating a cart; reports payment configuration without proving admission |
| **Mobile Release Readiness** | `check_mobile_release_readiness` | Read-only Expo/EAS preflight for internal releases |
| **Onboarding Flow** | `get_onboarding_flow` | NL checklist: login → create org → connect repo → import menu → run |
| **Session** | `whoami` | Verify the `craveup login` session is readable |
| **MCP Compatibility** | `get_mcp_capabilities` | Runtime versions, policy digest, and fail-closed compatibility blockers |
| **Integration Guide** | `get_integration_guide` | Crave.js implementation guidance: storefront, menu display, checkout |

---

## Tool Reference

<details>
<summary><strong>Browser Auth Tools</strong></summary>

| Tool | Description |
|------|-------------|
| `start_crave_auth` | Return a hosted Crave Up sign-in/sign-up URL for the agent to open |
| `complete_crave_auth` | Finish the loopback callback and persist the shared CLI/MCP session |
| `cancel_crave_auth` | Abandon a pending sign-in and release its loopback listener |

</details>

<details>
<summary><strong>Onboarding Tools</strong></summary>

| Tool | Description |
|------|-------------|
| `get_onboarding_flow` | NL checklist: login → create org → connect repo → import menu → run |
| `whoami` | Verify the `craveup login` session is readable |
| `create_organization` | Create merchant + location without minting or returning a plaintext API key |
| `connect_project` | Write the public API origin and location ID into an Expo app's `.env`; remove legacy browser keys |

</details>

<details>
<summary><strong>Runtime and Policy Tools</strong></summary>

| Tool | Description |
|------|-------------|
| `get_mcp_capabilities` | Return the MCP version, tool-policy digest, and unavailable compatibility evidence without credentials |

</details>

<details>
<summary><strong>Go-live Tools</strong></summary>

| Tool | Description |
|------|-------------|
| `get_onboarding_status` | The dashboard's 6 go-live steps with completion state + next actions |
| `create_location` | Create a location (`restaurantDisplayName` + optional address PATCH) |
| `delete_location` | Soft-archive a location (frees slug; hides from dashboard) |
| `list_locations` | Dashboard locations-stats for the merchant |
| `get_location_orders` | Active orders for a location |
| `list_customers` | Customers page for a location |
| `set_location_address` | Set the street address; the server geocodes (no lat/lng needed) |
| `set_fulfillment_methods` | Enable pickup / table service / delivery / room service |
| `list_subscription_plans` | Production-only plans with price, interval, and trial info |
| `start_subscription_checkout` | Production-only Stripe Checkout URL for the user to pay in the browser |

</details>

<details>
<summary><strong>Location Settings Tools</strong></summary>

| Tool | Description |
|------|-------------|
| `get_location_settings` | Read store hours, scheduled-order flag, tax, takeout |
| `update_store_hours` | Set hours (`always_open`, `business_9am_10pm`, or custom 7-day schedule) |
| `set_scheduled_orders_enabled` | Toggle order-ahead when closed |
| `set_takeout_enabled` | Enable/disable takeout pickup |
| `open_location_for_orders` | One-shot fix for "Restaurant is closed. Scheduled orders are not allowed." |

</details>

<details>
<summary><strong>Menu & Storefront Tools</strong></summary>

| Tool | Description |
|------|-------------|
| `import_menu` | Idempotent full menu import; forces `menu.isActive=true` by default |
| `set_menu_active` | Explicitly activate/deactivate a menu (use when `list_menus` shows inactive) |
| `list_menus` | Read back menus exactly as the storefront API serves them |
| `get_product` | Fetch one product with its modifier group ids |
| `update_product` | Partial edits: name, description, price, availability |
| `set_product_availability` | Sold-out toggles |
| `delete_product` | Remove a product (category references cleaned up) |
| `get_integration_guide` | Implementation guidance: storefront setup, menu display, checkout, import format |

</details>

<details>
<summary><strong>Discount Tools</strong></summary>

| Tool | Description |
|------|-------------|
| `list_discounts` | List location promo codes and their current configuration |
| `create_order_discount` | Idempotently create an order-level fixed or percentage promo code (percentage capped at 100) |

</details>

<details>
<summary><strong>Readiness Tools</strong></summary>

| Tool | Description |
|------|-------------|
| `check_storefront_readiness` | Side-effect-free `ordering-readiness` GET without creating a cart; reports payment configuration without proving admission |

</details>

The readiness tool reads the published menu and ordering availability, then reads
private integration status for payment configuration. It does not create a cart
or a PaymentIntent. During the current direct-charge cutover, a configured Stripe
integration still reports `ready: false`: ordinary Stripe checkout in sandbox and
production fails closed with `STRIPE_DIRECT_CHARGE_CUTOVER_INCOMPLETE`. Surface
checkout as temporarily unavailable and do not retry or bypass that response.

<details>
<summary><strong>Mobile Release Tools</strong></summary>

Run `craveup apps configure` in the Expo/React Native project and commit the generated workflows before using these tools. EAS builds consume plan minutes.

| Tool | Description |
|------|-------------|
| `check_mobile_release_readiness` | Read-only local preflight for EAS project identity, workflow, credentials, and internal target |
| `start_mobile_release` | Dispatch the fixed internal TestFlight workflow after exact confirmation |
| `get_mobile_release_status` | Read the EAS workflow run, build jobs, and submission jobs |

`start_mobile_release` cannot publish publicly. iOS always goes to internal TestFlight first; public App Store review remains an explicit App Store Connect action. Use `craveup apps publish play-internal` for Android; the CLI blocks submission unless the local EAS submit profile targets Google Play's `internal` track.

</details>

<details>
<summary><strong>Sandbox Tools</strong></summary>

| Tool | Description |
|------|-------------|
| `seed_sandbox_analytics` | Idempotently create customers, orders, ratings, and funnel events for the dev test organization. Requires `CRAVEUP_ENVIRONMENT=sandbox` and a sandbox Clerk session. |

</details>

---

## Authentication

This server authenticates to Crave with a **merchant API key** (menu, discount, and readiness tools), a shared **CLI/MCP browser session** (organization, onboarding, go-live, and location-settings tools), and optionally an **Expo token** (mobile release tools). The agent starts browser authentication with `start_crave_auth`; the user can sign in or create an account on the Crave Up-hosted page.

### Important: Sandbox vs production

| Environment | Dashboard | API | Clerk issuer | API key |
|---|---|---|---|:---:|
| `sandbox` | `sandbox.dashboard.craveup.com` | `dev-api-43233223.craveup.com` | `refined-mosquito-31.clerk.accounts.dev` | `crv_test_…` |
| `production` | `dashboard.craveup.com` | `api.craveup.com` | `clerk.craveup.com` | `crv_live_…` |

Set `CRAVEUP_ENVIRONMENT` explicitly in the MCP server configuration. The server derives the whole
profile from that value and rejects a test/live key or endpoint mismatch before sending a request.
Sandbox and production sessions are stored separately.

For daily development, register two named MCP servers instead of mutating one
server's environment in-process:

- `craveup-sandbox`: build the storefront, configure menus and locations, and
  exercise catalog and cart flows without crossing into live data. Stripe payment
  admission remains hard locked during the direct-charge cutover.
- `craveup-production`: use the live dashboard and live API-key namespace.
  Dashboard and setup tools remain usable before onboarding is complete. Checkout
  remains gated on subscription, Stripe Connect KYC/banking, and cutover activation.

Browser authentication is explicit: call `start_crave_auth`, open the returned Clerk authorization
URL, then call `complete_crave_auth`. Normal MCP calls reuse that persisted session and do not open a
browser again.

### Test Setup (recommended for management tools)

1. Sign in to **Crave Business Manager** → **Settings** → **Developer** → **API Keys**
2. Create a key for the location you want to work with — copy the `crv_test_…` value
3. Set `CRAVEUP_ENVIRONMENT=sandbox`, the server-only `CRAVEUP_API_KEY`, and optionally
   `CRAVEUP_LOCATION_ID` in the MCP server env. Public guides, project wiring, and published menu
   reads do not send this key.
4. For session-authenticated tools, use `start_crave_auth` and `complete_crave_auth`, or run `craveup login`; both paths use the same secure local session

### Live Setup

1. Start a separate MCP process with `CRAVEUP_ENVIRONMENT=production`; do not reuse sandbox credentials
2. Open the production dashboard and continue configuring the organization even if the commercial checklist is incomplete
3. When the business is ready to accept real payments, complete the go-live checklist — `get_onboarding_status` shows the six steps and what's missing
4. Verify payments with `check_storefront_readiness` — production requires merchant Stripe `chargesEnabled`
5. Mint a `crv_live_…` key in Business Manager

### Once you have credentials

```env
CRAVEUP_ENVIRONMENT=sandbox           # required: sandbox or production
CRAVEUP_API_KEY=crv_test_…            # prefix must match the environment
CRAVEUP_LOCATION_ID=<location id>     # optional default; every tool also accepts locationId

CRAVEUP_ACCESS_TOKEN=<session token>  # optional alternative to the keychain session
EXPO_TOKEN=<scoped robot-user token>  # only for mobile release tools
```

Endpoint overrides are normally unnecessary. Sandbox loopback URLs are allowed for local
development. Other custom deployments require `CRAVEUP_ALLOW_CUSTOM_ENDPOINTS=true`, and the
environment remains visible in `whoami` and mutating responses.

The private API transport rejects redirects rather than following them, so API-key and session
authorization headers are never replayed to a redirect target.

### Credential safety

Do not paste Apple passwords, 2FA codes, App Store Connect keys, or Google service-account JSON into chat. Bootstrap interactive credentials in a visible terminal; EAS stores the reusable submission credentials. `EXPO_TOKEN` must be a **scoped Expo robot-user token**, never a personal account token.

### Common pitfalls

- **New tools not appearing.** After rebuilding `packages/mcp/dist`, restart the MCP server in your client (or reload the window) — clients cache the tool list per process.
- **Keys are location-scoped.** The API rejects requests for locations the key cannot access; use the key minted for the location you're targeting, or pass an explicit `locationId`.
- **Session tools failing while key tools work.** The two auth modes are independent — a valid `CRAVEUP_API_KEY` does not log you in. Call `start_crave_auth`, open the returned URL, then call `complete_crave_auth`.
- **"Restaurant is closed. Scheduled orders are not allowed."** Not an auth problem: run `open_location_for_orders({ locationId })` for the one-shot fix, then retry.
- **Sandbox seeding refuses to run.** `seed_sandbox_analytics` is guarded by design: it requires `CRAVEUP_ENVIRONMENT=sandbox`; there is no production override.

---

## Development

### Building

```bash
pnpm --filter @craveup/mcp build   # compile to dist/
```

### Testing

```bash
pnpm --filter @craveup/mcp test    # Vitest unit and MCP round-trip suites
```

### Project Structure

```
src/
├── clients/         # Crave + Expo/EAS API clients
├── tools/           # MCP tool definitions (9 categories)
├── handlers/        # Business logic (readiness, onboarding, guides)
├── helpers/         # Zod schemas, session, env config
├── cli.ts           # stdio entry point (craveup-mcp bin)
└── index.ts         # Server assembly + tool registration

tests/
└── unit/            # Vitest suites

docs/
├── ARCHITECTURE.md  # Layers, auth modes & design decisions
└── TESTING.md       # Testing patterns & conventions
```

---

## Documentation

| Document | Description |
|----------|-------------|
| [CHANGELOG.md](CHANGELOG.md) | Version history and all changes |
| [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) | Layers, authentication modes, and design decisions |
| [docs/TESTING.md](docs/TESTING.md) | Testing strategy, in-memory MCP transport pattern, conventions |
| [docs.craveup.com](https://docs.craveup.com/guides/ai/craveup-mcp-server) | Hosted Crave Up MCP server guide + Crave.js integration docs (also served at runtime via `get_integration_guide`) |
| [modelcontextprotocol.io](https://modelcontextprotocol.io) | MCP specification |

---

## Error Handling

Every tool returns the same versioned `MerchantOperationResult` in both text and
`structuredContent`. Review-required writes default to a side-effect-free dry run; apply requires the
exact intent digest, and destructive/paid/release operations also require an explicit confirmation
phrase. The generated [mutation inventory](docs/mutation-inventory.json) is the source of truth for
credentials, scopes, risks, preview requirements, and current idempotency strategy.

Policies marked `unverified` fail closed even after preview. At present this applies to
`create_organization`, `create_location`, `start_subscription_checkout`, and
`start_mobile_release`; use Business Manager or the provider workflow until the authoritative
service supplies a durable operation identity and response-loss reconciliation.

Tools return structured MCP error results (`isError: true`) rather than throwing: missing or invalid auth reports which credential is needed (session vs API key vs `EXPO_TOKEN`), and the API rejects keys that cannot access the requested location. Paid EAS dispatch requires an exact confirmation phrase, location deletion is a recoverable soft-archive, and sandbox seeding refuses to run unless all dev-environment guards are set. The current digest binds environment, policy, and requested arguments; it does not yet bind authoritative target pre-state. `get_mcp_capabilities` reports that limitation, and also reports project generation, API-range compatibility, cursor pagination, and durable jobs as unavailable until their reviewed release evidence exists.

---

## Contributing

> **Note:** development happens in the private Crave Up monorepo; the public
> [craveup/craveup-mcp](https://github.com/craveup/craveup-mcp) repo is a read-only mirror synced
> automatically from `packages/mcp`. Bug reports and feature requests are welcome as issues on the
> mirror; direct pushes and PRs there will be overwritten by the next sync.

### Tool naming convention

- `get_*` / `list_*` / `check_*` — read-only
- `create_*` / `update_*` / `set_*` / `delete_*` — writes, idempotent where possible
- `start_*` — kicks off an external process (checkout, EAS workflow) and returns a handle

Add tests in `tests/unit/` for every new tool; `pnpm --filter @craveup/mcp test` must pass before publishing (`prepublishOnly` runs build + tests).

---

## License

MIT — see [LICENSE](LICENSE).

TDQS

A3.6/5.0

Scored across 38 tools

Disambiguation4/5

Most tools cleanly separate by resource and action (auth, locations, menu, orders, billing, mobile). A few naming pairs and composite helpers overlap conceptually, such as get_onboarding_flow vs get_onboarding_status and open_location_for_orders vs the individual settings toggles, but descriptions are generally sufficient to disambiguate.

Naming Consistency5/5

Tool names consistently follow a snake_case verb-first pattern (get_, create_, set_, list_, update_, delete_, start_, complete_, cancel_). 'whoami' is the only stylistic outlier, but it is a recognizable standard command and does not create confusion.

Tool Count2/5

38 tools is well above the 25-tool threshold for feeling appropriately scoped. The server covers a broad restaurant-platform domain, but the set feels heavy and includes composite helpers and meta guides that could be consolidated.

Completeness3/5

Core lifecycles are covered for auth, locations, menu products, and mobile releases. However, order handling ends at fetching active orders, discounts have no update/delete, and subscription management lacks cancellation/update paths, leaving some workflows with dead ends.

Maintenance

ActivityMaintained
ResponsivenessNo issues