@the-meridian/cli 1.3.0 → 1.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +17 -0
- package/README.md +13 -0
- package/dist/index.js +227 -7
- package/dist/index.js.map +1 -1
- package/dist/skill/SKILL.md +72 -0
- package/dist/skill/references/cli.md +54 -0
- package/dist/skill/references/hosting.md +54 -0
- package/dist/skill/references/sdk.md +71 -0
- package/dist/skill/references/setup.md +68 -0
- package/package.json +4 -3
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: meridian
|
|
3
|
+
description: Build, bill, run and deploy a Shopify app on Meridian. Use when the project uses or should use Meridian (the-meridian.ai), `@the-meridian/sdk`, the `meridian` CLI or the Meridian MCP server, or when the user asks to add plans, pricing, billing, entitlements, feature gating or usage tracking to a Shopify app, to run it against a Meridian developer database, or to deploy it on Meridian hosting and debug that deploy.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Meridian
|
|
7
|
+
|
|
8
|
+
Meridian is a platform for Shopify app developers: plans and billing through Shopify, feature gating and usage metering (the SDK), managed developer databases (the CLI), hosting on Cloud Run with GitHub deploys, and Grow tools (CRM, emails, automations). This skill tells you how to use each piece and what never to do.
|
|
9
|
+
|
|
10
|
+
## Before anything else
|
|
11
|
+
|
|
12
|
+
1. **Read the live facts, never guess them.** Feature keys, event keys, plan ids, environment ids and injected variables come from the Meridian MCP server. Product behaviour comes from the docs: call `docs_search`, then `docs_get` for the full page. Do not answer a Meridian question from memory, and treat this skill as a map, not the reference.
|
|
13
|
+
- MCP not connected yet: ask the user to connect it (`references/setup.md`) before writing code that needs keys or ids. For the docs alone, fetch a page as Markdown at `https://help.the-meridian.ai/<page>.md`, which is the `docs_get` path with `.md` instead of `.mdx` (`sdk-quickstart.mdx` is `https://help.the-meridian.ai/sdk-quickstart.md`; the `.mdx` URL does not exist). The page list is `https://help.the-meridian.ai/llms.txt`.
|
|
14
|
+
2. **Check what is already set up**, in this order, and fix only what is missing:
|
|
15
|
+
- `meridian --version` (the CLI is installed)
|
|
16
|
+
- the MCP server is connected (a `whoami` tool call answers)
|
|
17
|
+
- `meridian whoami --json` (signed in), and `.meridian/project.json` exists (the project is linked)
|
|
18
|
+
- `@the-meridian/sdk` is in `package.json` and `app/meridian.server.ts` exists (the SDK is wired)
|
|
19
|
+
|
|
20
|
+
## Pick the workflow
|
|
21
|
+
|
|
22
|
+
| The user wants to | Read |
|
|
23
|
+
| --- | --- |
|
|
24
|
+
| Install the CLI, connect MCP, sign in, link the project | [references/setup.md](references/setup.md) |
|
|
25
|
+
| Add plans, pricing, gating or usage tracking (the SDK) | [references/sdk.md](references/sdk.md) |
|
|
26
|
+
| Run the app locally on a Meridian database, migrate, seed | [references/cli.md](references/cli.md) |
|
|
27
|
+
| Deploy, follow a deploy, fix a failed deploy, set variables | [references/hosting.md](references/hosting.md) |
|
|
28
|
+
| Work on webhooks, Shopify API alerts, CRM, emails, automations | "Operate and grow" below |
|
|
29
|
+
|
|
30
|
+
A new app usually goes through all four references in that order: setup, SDK, local development, deploy.
|
|
31
|
+
|
|
32
|
+
## Rules that always apply
|
|
33
|
+
|
|
34
|
+
**The human does these, never you.** Ask the user, explain why, and wait:
|
|
35
|
+
|
|
36
|
+
- Signing in: `meridian login` runs a device-code flow the user approves in their browser. Ask them to run it in their own terminal, then check with `meridian whoami --json`.
|
|
37
|
+
- Approving the MCP connection (the OAuth consent screen in their browser).
|
|
38
|
+
- Creating or rotating `MERIDIAN_API_KEY` (Settings, SDK in the dashboard) and putting it in `.env` or the hosting secrets. Never ask them to paste a key, a password or a secret into the chat.
|
|
39
|
+
- Entering hosting secrets and variables, installing the Meridian GitHub app, adding a custom domain, choosing a plan.
|
|
40
|
+
|
|
41
|
+
**Confirm in chat before you do these**, naming exactly what will happen:
|
|
42
|
+
|
|
43
|
+
- Deploying to production, promoting to production, or `deployment_rollback`.
|
|
44
|
+
- `meridian db reset`, `dev_database_reset`, or anything else that drops data.
|
|
45
|
+
- `automation_update` on an automation that is already active, or `custom_field_values_set` on a real store.
|
|
46
|
+
|
|
47
|
+
**Never:**
|
|
48
|
+
|
|
49
|
+
- Put `MERIDIAN_API_KEY` in browser code, a client bundle, a theme or a commit. It is server only and imports from `@the-meridian/sdk/server` only.
|
|
50
|
+
- Invent a feature key, event key, plan id or variable name. Read it (`features_list`, `events_list`, `plans_list`, `managed_variables_list`).
|
|
51
|
+
- Copy code from an old Meridian example that imports from `meridian-sdk` (the package's former name) or sends a Shopify access token to Meridian. The current SDK never does.
|
|
52
|
+
|
|
53
|
+
## Operate and grow
|
|
54
|
+
|
|
55
|
+
Every tool below takes `app_id` (from `apps_list`). Read the tool's own description before calling it.
|
|
56
|
+
|
|
57
|
+
| Question | Tools |
|
|
58
|
+
| --- | --- |
|
|
59
|
+
| A Shopify webhook is not arriving | `webhook_routes_list` (is the topic routed and registered?), then `webhook_deliveries_list` (did it arrive, what did the handler answer?) |
|
|
60
|
+
| Shopify API deprecations affecting the app | `shopify_alerts_list`, `shopify_alert_get` |
|
|
61
|
+
| What a store is entitled to right now | `entitlements_explain` |
|
|
62
|
+
| CRM fields and segments | `custom_fields_list`, `crm_segments_list`, `crm_segment_get`, `custom_field_values_set` |
|
|
63
|
+
| Emails | `emails_list`, `email_get`, `emails_variables_list`, `email_create` and `email_update` (inactive drafts and metadata only) |
|
|
64
|
+
| Automations | `automations_catalog_get` first, then `automation_create`, `automation_update` (inactive only), `automation_test_run` (dry run, sends nothing) |
|
|
65
|
+
|
|
66
|
+
Email bodies, activating an email or automation, live sends, prices and discounts stay in the dashboard. Say so instead of looking for a workaround.
|
|
67
|
+
|
|
68
|
+
## When something is refused
|
|
69
|
+
|
|
70
|
+
- "App not found, or you do not have access to it" means a wrong `app_id` or a missing permission. The two read the same on purpose. Re-run `apps_list`, then ask the user to check their role.
|
|
71
|
+
- `402 PLAN_LIMIT_REACHED` from the SDK is the developer's own Meridian plan quota, not the merchant's. Never show it to a merchant.
|
|
72
|
+
- A CLI error names its fix in the `›` hint line. Read it before retrying.
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Local development with the CLI
|
|
2
|
+
|
|
3
|
+
`meridian dev` gives each developer a private MySQL 8.4 database on Meridian, reached through the Meridian database gateway on `127.0.0.1`. No Docker, no local MySQL, no cloud credentials. Billing works locally because Meridian can read the sessions this database holds (installs made locally are Shopify test charges).
|
|
4
|
+
|
|
5
|
+
The project must be linked first (`references/setup.md`).
|
|
6
|
+
|
|
7
|
+
## Prepare Prisma (once)
|
|
8
|
+
|
|
9
|
+
The Shopify template ships with SQLite. Every database command refuses a schema that is not:
|
|
10
|
+
|
|
11
|
+
```prisma
|
|
12
|
+
datasource db {
|
|
13
|
+
provider = "mysql"
|
|
14
|
+
url = env("DATABASE_URL")
|
|
15
|
+
}
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
After switching, delete the old SQLite migrations in `prisma/migrations` (they cannot apply to MySQL) and create a fresh one with `meridian migrate -- --name init`. Ask the user before deleting migrations that already ran against a deployed database.
|
|
19
|
+
|
|
20
|
+
`meridian migrate` also needs `shadowDatabaseUrl = env("SHADOW_DATABASE_URL")` in the datasource. It offers to add the line (`--yes` accepts). In a non-interactive shell without `--yes` it stops and prints the line to add.
|
|
21
|
+
|
|
22
|
+
## Commands
|
|
23
|
+
|
|
24
|
+
Every command accepts the global flags `--json` (one JSON result on stdout, human lines on stderr), `--yes` (approve confirmations), `--no-input` (never prompt, fail instead) and `--cwd <dir>`.
|
|
25
|
+
|
|
26
|
+
| Command | What it does | Notes for agents |
|
|
27
|
+
| --- | --- | --- |
|
|
28
|
+
| `meridian dev` | Provisions the database (up to 5 minutes the first time), opens the gateway, writes `DATABASE_URL` and `SHADOW_DATABASE_URL` into `.env`, then runs `npm run dev` | Long-running: start it in the background. Run another command with `meridian dev -- shopify app dev`. `--no-env` prints the URL instead of editing `.env` |
|
|
29
|
+
| `meridian migrate -- --name <name>` | Snapshots the database to `.meridian/snapshots/`, runs `prisma migrate dev`, restores the snapshot if it fails | Always pass `--name`, or Prisma prompts. Arguments after `--` go to Prisma |
|
|
30
|
+
| `meridian db seed` | Runs `npx prisma db seed` with the gateway open | |
|
|
31
|
+
| `meridian db shell --repl -e "<sql>" --json` | Runs one statement and prints the rows as JSON | `--repl` matters: without it an installed `mysql` client prints plain text |
|
|
32
|
+
| `meridian db reset --yes --migrate` | Drops every table, then reapplies the migrations (`--seed` to seed too) | Destructive. Confirm with the user first |
|
|
33
|
+
| `meridian db credential list --env production` | Lists external access credentials of a hosted environment's database | Creating and rotating them is dashboard-only |
|
|
34
|
+
| `meridian whoami --json` | The signed-in user, their organizations and the linked project | |
|
|
35
|
+
| `meridian link --org <slug> --app <slug>` | Links the project | See setup |
|
|
36
|
+
| `meridian skills install` | Installs or updates this skill and the MCP config in the project | `--agent all`, `--no-mcp` |
|
|
37
|
+
|
|
38
|
+
`.env` keeps every other line. The first change saves `.env.backup`.
|
|
39
|
+
|
|
40
|
+
## Errors
|
|
41
|
+
|
|
42
|
+
Exit code 1 for an expected error, 130 on Ctrl-C, otherwise the child process's code. With `--json` an error prints `{"error": {"message", "hint"}}` on stdout. Read the hint before retrying.
|
|
43
|
+
|
|
44
|
+
| Message | Fix |
|
|
45
|
+
| --- | --- |
|
|
46
|
+
| You are not logged in / token has expired / no longer valid (401) | The user runs `meridian login` |
|
|
47
|
+
| This project is not linked to a Meridian app | `meridian link --org <slug> --app <slug>` |
|
|
48
|
+
| Cannot prompt for X in a non-interactive shell | Pass the flag the hint names, or `--yes` |
|
|
49
|
+
| `schema.prisma` sets `provider = "sqlite"`, or reads another variable than `DATABASE_URL` | Switch the datasource (above) |
|
|
50
|
+
| `dev_database_limit_reached` | The organization's plan has no developer database left. Tell the user |
|
|
51
|
+
| `cli_upgrade_required` | `npm install -g @the-meridian/cli@latest` |
|
|
52
|
+
| `meridian dev` is already running in this process tree | You are inside a `meridian dev` session. Run the command directly, without nesting another one |
|
|
53
|
+
|
|
54
|
+
The MCP tools `dev_database_get` (status, storage) and `dev_database_reset` cover the same database without the CLI. `dev_database_migrate` only records a run, it does not execute one.
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Deploying on Meridian hosting
|
|
2
|
+
|
|
3
|
+
Meridian builds the app from a commit of its connected GitHub repository, runs it on Cloud Run, and puts it behind its own edge (`*.the-meridian.app` or a custom domain). Deploys come only from GitHub: a push to the auto-deploy branch, a manual deploy of a branch and commit (dashboard or MCP `deployment_create`), a promote, or a rollback. There is no CLI deploy command.
|
|
4
|
+
|
|
5
|
+
Each app has a Production environment. Development is optional on every plan, Staging is Enterprise only. Each environment has its own service, database, variables and add-ons.
|
|
6
|
+
|
|
7
|
+
## Readiness checklist
|
|
8
|
+
|
|
9
|
+
Check each item in the repository before the first deploy, and fix what fails:
|
|
10
|
+
|
|
11
|
+
1. **`Dockerfile` at the repository root.** A deploy is refused without one ("Dockerfile not found at root of repository"). The Shopify template's Dockerfile works. The build runs with `NODE_ENV=production`.
|
|
12
|
+
2. **Prisma on MySQL** with `url = env("DATABASE_URL")` (`references/cli.md`). Meridian injects `DATABASE_URL` for the environment's managed database, plus the `DB_*` variables. A `DATABASE_URL` the user sets wins.
|
|
13
|
+
3. **Migrations in the release command**, not at startup. The environment's release command should be `npx prisma migrate deploy`. It runs once per deploy in the new image, before traffic moves, with a 15 minute limit, and a non-zero exit fails the deploy while the old revision keeps serving. Then remove `prisma migrate deploy` from the `docker-start` script and run `prisma generate` at build time, which cuts the cold start from over ten seconds to a few.
|
|
14
|
+
4. **A health check route answering 200** on the environment's health check path (usually `/health`), with no redirect and no authentication. A redirect counts as a failure. A minimal React Router route: `app/routes/health.tsx` exporting `export const loader = () => new Response("ok")`.
|
|
15
|
+
5. **The container port** set on the environment matches the port the server listens on (the template serves on `3000`, or reads `PORT`).
|
|
16
|
+
6. **The host header.** The edge passes the public hostname in `X-Forwarded-Host`. Code that reads the request host reads that header. React Router form actions need no `allowedActionOrigins` for Meridian hostnames.
|
|
17
|
+
|
|
18
|
+
## What the user sets up in the dashboard
|
|
19
|
+
|
|
20
|
+
You cannot do these. List the missing ones for the user:
|
|
21
|
+
|
|
22
|
+
- Connect the repository: Settings, Integrations, GitHub card. It installs the Meridian GitHub app.
|
|
23
|
+
- Add the database: Hosting, Database (MySQL, up to five minutes to provision).
|
|
24
|
+
- Set the environment's release command, health check path and container port.
|
|
25
|
+
- Add their own variables and secrets on the Environment page (write-only secrets, scoped to all environments or one). Meridian injects `SHOPIFY_API_KEY`, `SHOPIFY_API_SECRET`, `MERIDIAN_APP_ID`, `MERIDIAN_API_URL`, `MERIDIAN_API_KEY`, `MERIDIAN_WEBHOOK_SECRET`, `DB_*` and the add-on variables itself.
|
|
26
|
+
- Choose the auto-deploy branch and target.
|
|
27
|
+
|
|
28
|
+
Variables, secrets, the release command and the health check path reach the app with the next deploy. `environments_list` shows `config_pending_deploy: true` until then.
|
|
29
|
+
|
|
30
|
+
## Deploy and follow it
|
|
31
|
+
|
|
32
|
+
1. `apps_list`, then `environments_list` for the `environment_id`.
|
|
33
|
+
2. `managed_variables_list` and `secrets_list` to check every variable the code reads exists (names only, never values).
|
|
34
|
+
3. `github_refs_list` for a pushed `git_sha`. A commit that is not pushed fails late in the build.
|
|
35
|
+
4. Confirm with the user, then `deployment_create` with the environment and the sha (or the user pushes to the auto-deploy branch). Production needs the **hosting.promote** permission.
|
|
36
|
+
5. Poll `deployment_get`. Status runs Queued, Building, Deploying (the release command, then the new revision), Verifying (the health check), then Succeeded, Failed or Cancelled. One deployment is active per environment.
|
|
37
|
+
6. After it succeeds, `logs_tail` for runtime errors (`min_severity: "WARNING"`, `contains`, `since`).
|
|
38
|
+
|
|
39
|
+
## When a deploy fails
|
|
40
|
+
|
|
41
|
+
Run the MCP prompt `debug_failed_deploy` with the deployment: it returns the real error, the recent build events and the calls to make next. Common causes:
|
|
42
|
+
|
|
43
|
+
| Failed at | Usual cause |
|
|
44
|
+
| --- | --- |
|
|
45
|
+
| Building | The Dockerfile build fails (a missing dependency, a build script that needs a variable a build cannot see) |
|
|
46
|
+
| Running release command | The migration fails. Read its output in the deploy log |
|
|
47
|
+
| Verifying | The health check path redirects, needs auth, answers non-200, or the container port is wrong |
|
|
48
|
+
| Runtime errors after success | A missing variable (`managed_variables_list`, `secrets_list`) or a schema mismatch (`database_schema_get`) |
|
|
49
|
+
|
|
50
|
+
`deployment_rollback` sends traffic back to an earlier succeeded deployment with no rebuild. Ask the user before you call it.
|
|
51
|
+
|
|
52
|
+
## Pull request previews
|
|
53
|
+
|
|
54
|
+
A pull request from a branch of the connected repository gets a preview deployment (two live at most per app, removed when the PR closes). A preview gets only the plain all-environment variables, never secrets or managed variables. `previews_list` gives its URL and status.
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# The SDK: plans, pricing, gating, usage
|
|
2
|
+
|
|
3
|
+
`@the-meridian/sdk` goes inside the Shopify app. It targets the Shopify React Router app template (Remix-shaped loaders work the same way). Two entry points:
|
|
4
|
+
|
|
5
|
+
- `@the-meridian/sdk`: browser code (`MeridianProvider`, `useMeridian`, `MeridianPricingPage`, `MeridianAccountPage`).
|
|
6
|
+
- `@the-meridian/sdk/server`: Node only (`createMeridianApp`, webhook verification). The only place the API key is used.
|
|
7
|
+
|
|
8
|
+
Before writing code, get the real keys: the MCP prompt `integrate_sdk` returns a walkthrough pre-filled with the app's features, events and plans (optional `surface`: `provider`, `pricing`, `usage` or `server`). Or call `features_list`, `events_list` and `plans_list`. For any detail, `docs_get` on `sdk-quickstart.mdx`, `sdk-app.mdx`, `sdk-use-meridian.mdx` or `sdk-errors.mdx` (without MCP, the same pages as `.md` on help.the-meridian.ai).
|
|
9
|
+
|
|
10
|
+
## Credentials
|
|
11
|
+
|
|
12
|
+
| Variable | Where it comes from |
|
|
13
|
+
| --- | --- |
|
|
14
|
+
| `MERIDIAN_APP_ID` | Dashboard, the app's Settings, SDK page. Not a secret. |
|
|
15
|
+
| `MERIDIAN_API_KEY` | Same page, **Create API key** (shown once, starts `mrd_sk_`). Server only. The user creates it and puts it in `.env` themselves. |
|
|
16
|
+
| `MERIDIAN_WEBHOOK_SECRET` | Only to verify forwarded webhooks. Pub/Sub, Webhooks page. |
|
|
17
|
+
| `MERIDIAN_API_URL` | Leave unset. |
|
|
18
|
+
|
|
19
|
+
On Meridian hosting these are injected at every deploy (check with `managed_variables_list`), so they only need to be in the local `.env`.
|
|
20
|
+
|
|
21
|
+
## Wire it in
|
|
22
|
+
|
|
23
|
+
1. `npm install @the-meridian/sdk`
|
|
24
|
+
2. `app/meridian.server.ts`:
|
|
25
|
+
|
|
26
|
+
```ts
|
|
27
|
+
import { createMeridianApp } from "@the-meridian/sdk/server"
|
|
28
|
+
|
|
29
|
+
export const meridian = createMeridianApp()
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
It never throws. Unconfigured, `meridian.configured` is `false` and every method returns its empty result.
|
|
33
|
+
3. `app/shopify.server.ts`, in `shopifyApp({ hooks })`:
|
|
34
|
+
|
|
35
|
+
```ts
|
|
36
|
+
afterAuth: async ({ session, request }) => {
|
|
37
|
+
await meridian.afterAuth(session, { request })
|
|
38
|
+
},
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
This registers the webhooks, reports the install (automations fire), syncs Shopify subscriptions and trials, and attributes a referral.
|
|
42
|
+
4. `app/routes/app.tsx` loader: `const shopToken = await meridian.mintShopToken({ shop: session.shop })`, returned to the component. `null` means "render without Meridian", not an error.
|
|
43
|
+
5. Same file, inside `<AppProvider embedded>`: `shopToken ? <MeridianProvider shopToken={shopToken}><Outlet /></MeridianProvider> : <Outlet />`.
|
|
44
|
+
6. Pricing route `app/routes/app.pricing.tsx`: build `returnUrl` in the loader as `https://<shop>/admin/apps/<client id>/app/pricing`, where `<shop>` is `session.shop` and `<client id>` is the app's Shopify client ID (public, already in `shopify.app.toml`), and render `<s-page><s-section><MeridianPricingPage returnUrl={returnUrl} /></s-section></s-page>`.
|
|
45
|
+
7. Account route: `<MeridianAccountPage onChangePlan={() => navigate("/app/pricing")} />`.
|
|
46
|
+
|
|
47
|
+
## Gate and track
|
|
48
|
+
|
|
49
|
+
```tsx
|
|
50
|
+
const { isEnabled, getLimit, loading, track } = useMeridian()
|
|
51
|
+
if (loading) return null
|
|
52
|
+
if (!isEnabled("advanced_reports")) return <UpgradePrompt />
|
|
53
|
+
await track({ eventKey: "api_calls", quantity: 1, idempotencyKey: requestId })
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Server side: `meridian.track({ shop, eventKey, quantity, idempotencyKey })`, or `meridian.trackMany({ shop, events })` for up to 50 events in one request. `meridian.gatesForShop(shop)` returns the gates for a loader or a job.
|
|
57
|
+
|
|
58
|
+
## Pitfalls
|
|
59
|
+
|
|
60
|
+
- **Billing needs Meridian hosting.** `subscribe`, `cancelSubscription` and `updateUsageCap` work only when the app runs on Meridian with a managed database, or locally under `meridian dev`. Otherwise they fail with `403 PLAN_BUILDER_UNAVAILABLE` and `err.details.plan_builder_billing_status` names the cause. Two things fail quietly instead: usage overage is never charged and prices fall back to USD. See `sdk-hosting.mdx`.
|
|
61
|
+
- **SQLite breaks billing** with `session_table_missing`. Prisma must use MySQL (`references/cli.md`).
|
|
62
|
+
- **`returnUrl`** must be the `https` shop-admin URL of the pricing route itself. One built from `request.url`, `window.location` or the app's own origin is rejected (`INVALID_RETURN_URL`).
|
|
63
|
+
- **Gates fail open.** While `loading` is true, or after an error, everything reads as enabled. Check `loading` first, or paying merchants see an upgrade prompt flash. An unknown key reads `false` with no error.
|
|
64
|
+
- **Keys, not ids.** `track` and `updateUsageCap` take the event key. A UUID is refused with 422.
|
|
65
|
+
- **Idempotency.** Pass `idempotencyKey` on every `track`: retries on 429 and 5xx only happen with one. A backdated `timestamp` requires one.
|
|
66
|
+
- **Rate limits.** Reads and tracking share 120 requests a minute per shop token, billing writes 30. Batch with `trackMany`, never `Promise.all` over `track`.
|
|
67
|
+
- **The pages need App Bridge.** The pricing and account pages render Polaris web components, so they live in the embedded admin.
|
|
68
|
+
- **Serverless hosting** starts every instance with a cold token cache. Persist the token with `mintShopTokenDetailed`.
|
|
69
|
+
- **Webhook topics** added in the dashboard reach installed stores at their next `afterAuth`. `meridian.registerWebhooks({ shop, accessToken })` applies them at once.
|
|
70
|
+
- **Forwarded webhooks**: verify with `verifyMeridianWebhookDetailed` against the raw body, and take the shop and topic from what it returns, not from a header. See `sdk-webhooks.mdx`.
|
|
71
|
+
- **`402 PLAN_LIMIT_REACHED`** is the developer's Meridian quota. Log it, never show it to a merchant.
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# Setup: CLI, MCP, sign-in, link
|
|
2
|
+
|
|
3
|
+
Do these once per machine (CLI, sign-in) and once per project (MCP config, link). Skip any step that is already done.
|
|
4
|
+
|
|
5
|
+
## 1. Install the CLI
|
|
6
|
+
|
|
7
|
+
Needs Node 20 or later.
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install -g @the-meridian/cli
|
|
11
|
+
meridian --version
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## 2. Connect the Meridian MCP server
|
|
15
|
+
|
|
16
|
+
Server URL: `https://mcp.the-meridian.ai/mcp` (Streamable HTTP, OAuth 2.1 with PKCE). There is no API key: the client registers itself and the user approves it once in the browser.
|
|
17
|
+
|
|
18
|
+
`meridian skills install` writes the project config for every agent it finds (add `--no-mcp` to skip it). To do it by hand:
|
|
19
|
+
|
|
20
|
+
| Client | Config | Then |
|
|
21
|
+
| --- | --- | --- |
|
|
22
|
+
| Claude Code | `claude mcp add --transport http meridian https://mcp.the-meridian.ai/mcp`, or `.mcp.json`: `{"mcpServers": {"meridian": {"type": "http", "url": "https://mcp.the-meridian.ai/mcp"}}}` | The user runs `/mcp` and approves |
|
|
23
|
+
| Cursor | `.cursor/mcp.json`: `{"mcpServers": {"meridian": {"url": "https://mcp.the-meridian.ai/mcp"}}}` | The user opens **Customize** in Cursor's sidebar (Settings, Tools & MCP before Cursor 3) and connects Meridian |
|
|
24
|
+
| Codex | `.codex/config.toml` (trusted projects) or `~/.codex/config.toml`: `[mcp_servers.meridian]` with `url = "https://mcp.the-meridian.ai/mcp"` | The user runs `codex mcp login meridian` |
|
|
25
|
+
|
|
26
|
+
The Claude Code plugin (`/plugin marketplace add the-meridian-ai/skill`) already declares the server.
|
|
27
|
+
|
|
28
|
+
Check the connection with the `whoami` tool. It returns the user and every organization they belong to.
|
|
29
|
+
|
|
30
|
+
The MCP server only reaches the production Meridian platform (and the staging and development environments of apps there).
|
|
31
|
+
|
|
32
|
+
## 3. Sign in the CLI (the user does it)
|
|
33
|
+
|
|
34
|
+
Ask the user to run this in their own terminal, because it waits for them to approve a code in the browser:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
meridian login
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Then check it yourself:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
meridian whoami --json
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
`whoami --json` prints `user`, `orgs` (each with `id`, `name`, `slug`) and the linked project. A token lasts 90 days. "You are not logged in" or "token has expired" means the user signs in again.
|
|
47
|
+
|
|
48
|
+
## 4. Link the project
|
|
49
|
+
|
|
50
|
+
Run from the app's root (the directory with `package.json`). Find the organization slug in `whoami` and the app slug in `apps_list` (both MCP tools), then:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
meridian link --org <org-slug> --app <app-slug>
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
This writes `.meridian/project.json` (commit it, it holds no secret) and `.meridian/.gitignore`. With one organization or one app the CLI picks it. Add `--force` to relink a linked project.
|
|
57
|
+
|
|
58
|
+
No app yet: the user creates it in the dashboard (Create app). It needs the Shopify app's client ID and secret.
|
|
59
|
+
|
|
60
|
+
## 5. Install this skill in the project
|
|
61
|
+
|
|
62
|
+
So every teammate's agent gets it:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
meridian skills install
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
It writes the skill to `.claude/skills/meridian`, `.agents/skills/meridian` (Codex) and `.cursor/skills/meridian`, for the agents it detects (`--agent claude,codex,cursor` or `--agent all` to choose), plus the MCP config above. Commit those folders. Run it again after a CLI upgrade to update the skill.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@the-meridian/cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.1",
|
|
4
4
|
"description": "Meridian CLI: managed remote development databases for Shopify apps built on Meridian.",
|
|
5
5
|
"author": "The Meridian <matthias@the-meridian.ai>",
|
|
6
6
|
"license": "MIT",
|
|
@@ -49,7 +49,8 @@
|
|
|
49
49
|
"overrides": {
|
|
50
50
|
"mysqldump": {
|
|
51
51
|
"mysql2": "^3.23.2"
|
|
52
|
-
}
|
|
52
|
+
},
|
|
53
|
+
"tinypool": "2.1.2"
|
|
53
54
|
},
|
|
54
55
|
"dependencies": {
|
|
55
56
|
"@inquirer/prompts": "^8.5.2",
|
|
@@ -59,7 +60,7 @@
|
|
|
59
60
|
"mysqldump": "^3.2.0",
|
|
60
61
|
"open": "^11.0.0",
|
|
61
62
|
"picocolors": "^1.1.1",
|
|
62
|
-
"zod": "^4.
|
|
63
|
+
"zod": "^4.6.6"
|
|
63
64
|
},
|
|
64
65
|
"devDependencies": {
|
|
65
66
|
"@changesets/cli": "^2.31.1",
|