Skip to content

feat(mcp): switch to the dev environment with X-Crystallize-Environment - #30

Merged
Plopix merged 2 commits into
mainfrom
feat/mcp-dev-environment
Oct 30, 2026
Merged

Plopix merged 2 commits into
mainfrom
feat/mcp-dev-environment

Conversation

@Plopix

@Plopix Plopix commented Oct 30, 2026

Copy link
Copy Markdown
Member
Q A
Branch? main
Bug fix? no
New feature? yes
BC breaks? no
Fixed tickets -

What

The MCP server hardcoded api.crystallize.com / shop-api.crystallize.com in eight tool files, never passed origin to the js-api-client, and verified bearer tokens against a fixed production JWKS.

A request can now switch to the dev environment the way the js-api-client's shopApiStaging switch works: the caller flips a switch, never types a hostname.

  • Header: X-Crystallize-Environment: dev. Absent, blank or production → production (unchanged behaviour). Any other value → 400.
  • Secret: CRYSTALLIZE_DEV_API_ORIGIN holds the dev js-api-client origin suffix. It is a Wrangler secret (or a .env line locally), so the dev hostname never appears in the repo. Tests and docs use the fake -dev.example.test. dev with the secret unset → 400; a secret that is not a valid suffix → 500.

How

  • src/core/api-origin.ts resolves the header into an origin suffix and builds API hosts from it (apiBaseUrl).
  • authMiddleware resolves it first, stores it on the auth context as origin, uses it for the me call and keeps one remote JWKS per environment (cached per isolate). The secret is only read when a request asks for dev, so a bad secret can never affect production traffic.
  • Every tool passes origin: authContext.origin to createClient; every hand-built URL (schema introspection, the Shop API /auth/token exchange) comes from apiBaseUrl. grep crystallize.com src now only hits the resolver, the landing page and the product panel's static CSP.
  • The product-overview panel's CSP gains the dev parent-domain wildcard when the resource is read on dev, so images still render.
  • bin/dev-bridge.ts forwards the header from CRYSTALLIZE_ENVIRONMENT.
  • AGENTS.md (renamed from CLAUDE.md in the first commit) documents the header, the secret and the rule for new tools.

Tests

bun test: 211 pass (was 184). New coverage: the resolver, the middleware (header resolution, production default, 400 / 500 paths, per-environment JWKS and its caching), the query-core and query-shop-cart tools, the Core schema tool's introspection URL, and the CSP helper. bun type-check, bun lint and bun run build are clean.

Rollout

  1. wrangler secret put CRYSTALLIZE_DEV_API_ORIGIN with the dev suffix (must start with . or -, lowercase host fragment).
  2. Locally, add CRYSTALLIZE_DEV_API_ORIGIN=<suffix> to .env; optionally CRYSTALLIZE_ENVIRONMENT=dev for the dev bridge.
  3. In an MCP client, add --header "X-Crystallize-Environment: dev" next to the token headers.

The server used to hardcode api.crystallize.com / shop-api.crystallize.com in
eight tool files, never passed `origin` to the js-api-client, and verified
bearer tokens against a fixed production JWKS.

A request can now flip to dev the way the js-api-client's `shopApiStaging`
switch works: the caller sends `X-Crystallize-Environment: dev`, never a
hostname. The dev origin suffix lives only in the `CRYSTALLIZE_DEV_API_ORIGIN`
secret, so it never appears in the repo (tests and docs use `-dev.example.test`).

- `src/core/api-origin.ts`: resolve the header into a js-api-client origin
  suffix. No header / `production` -> `.crystallize.com`; `dev` -> the secret
  (400 when unset, 500 when not a valid suffix); anything else -> 400.
- `authMiddleware` resolves it first, stores it on the auth context as
  `origin`, uses it for the `me` call and keeps one remote JWKS per environment.
- Every tool passes `origin: authContext.origin` to `createClient`, and every
  hand-built URL (schema introspection, Shop API token exchange) comes from
  `apiBaseUrl(prefix, origin)`.
- The product-overview panel's CSP gains the dev parent-domain wildcard on read.
- The dev bridge forwards the header from `CRYSTALLIZE_ENVIRONMENT`.
- AGENTS.md documents the header, the secret and the rule for new tools.
@Plopix
Plopix merged commit 8eb9594 into main Oct 30, 2026
1 check passed
@Plopix
Plopix deleted the feat/mcp-dev-environment branch October 30, 2026 18:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant