Skip to main content
Glama
AbdulRehman0004

Shopify Content Engine MCP Server

Shopify Product Content Engine

CI n8n OpenAI MCP Python License

An n8n pipeline that turns a bare product (product_name, product_description) into a complete, review-ready marketing kit — SEO research, product-page copy, a blog post, Google + Meta ads, social posts, an email and a hero image — and writes one row per product to a review sheet. Nothing publishes automatically; a human approves.

Alongside the workflow this repo ships the two things that make it operable rather than a demo: an eval harness that scores every generated kit against the engine's own rules (length caps, banned words, invented facts) and an MCP server so any agent — Claude Desktop, Claude Code, Cursor, your own — can validate drafts and trigger runs.

product_name + product_description
        │
        ▼
 ┌────────────── n8n ──────────────┐
 │ idempotency gate → 3 LLM calls  │──▶ Review sheet (status=done | failed)
 │ strict JSON → validate → map    │──▶ hero image → Drive
 │ dry-run · retry · dead-letter   │──▶ batch summary email
 └─────────────────────────────────┘
        ▲                       │
   MCP server               eval harness
 (validate / run)      (rules + LLM judge, gates CI)

Why it's built this way

Concern

What the engine does

Hallucinated specs

Every prompt is facts-only; the eval flags any number/unit or claim word (clinically, certified, vegan, …) not present in the product input.

Fragile parsing

All three model calls use OpenAI Structured Outputs (strict: true) — schema-valid JSON, no regex.

Re-runs / cost

An idempotency gate skips anything already status=done; forceRegenerate overrides. Bulk model is gpt-4o-mini.

One bad product

Per-call retry + continue-on-error. Failures are written as status=failed rows with a failure_reason (dead-letter) — the batch never stops.

Uncaught failures

Routed to a separate Error Handler workflow → alert email.

Testing without side effects

dryRun=true generates and validates but writes nothing.

Publishing

Never automatic. Drafts land in the Review tab and a human approves.

Platform limits

Hard caps (SEO title ≤ 60, meta ≤ 155, Google headline ≤ 30, X ≤ 280, …) live in config/, are enforced in the Parse node, and are re-checked by the evals.

Flow

Manual / Schedule / Webhook ─▶ ⚙️ Config ─▶ 📥 Read Products [swap point → Shopify]
  ─▶ 📖 Read Done ─▶ 🚦 Idempotency Gate ─▶ 🔢 Limit ─▶ 🔁 Loop (1 product at a time)
        ─▶ 🤖 A: SEO + Product Page ─▶ 🤖 B: Blog ─▶ 🤖 C: Ads / Social / Email / Image prompt
        ─▶ 🧩 Parse, Validate & Map ─▶ 🧪 Dry run?
              ├─ yes ─▶ 📝 Dry-run log (no write) ─▶ loop
              └─ no  ─▶ 🖼️ Images? ─▶ 🎨 gpt-image-1 ─▶ ☁️ Drive ─▶ 📤 Upsert Review row ─▶ loop
  🔁 done ─▶ 📊 Batch summary ─▶ ✉️ Email (optional)
  (uncaught) ─▶ ⚠️ Error Handler workflow ─▶ alert email

Full Mermaid diagram: docs/architecture.mmd. Product source is a Google Sheet today; 📥 Read Products is a marked swap point for Shopify → Get Products (title → product_name, body_html → product_description).

Evals

python -m evals scores kits (Review-tab rows) against the rules the engine promises to keep. Rules come straight from config/generation.config.yaml and config/brand-voice.yaml, so changing a cap in config changes the eval.

Check family

Examples

Completeness

status=done, all 19 content fields present

Hard caps

8 character caps, 3 word ranges, ≤15 Google headlines each ≤30 chars, 5–10 hashtags

Structure

4–6 bullets, H2/H3 in the blog, exactly one {PRODUCT_URL} CTA, slug format

SEO placement

primary keyword in title / meta / first sentence (warnings)

Brand voice

banned words from brand-voice.yaml

Facts-only

numbers+units and claim words in the output must exist in the product input

LLM judge (--judge)

1–5 on facts-only, brand voice, SEO quality + quoted unsupported claims (Structured Outputs, opt-in, needs OPENAI_API_KEY)

Current golden set (real kit from a live run, evals/golden/kits.json):

Product

Score

What it caught

Gentle Hydrating Gel Cleanser

88%

description 66 words (want 150–250), blog 507 words (want 900–1200), email 28 words (want 60–120) — the model under-delivers on length; the Parse node truncates over-length text but has no minimum-length retry yet

That finding is exactly why the harness exists — it's now an open item (see roadmap). Run it against your own export with python -m evals --input review-export.csv --min-score 0.9; the non-zero exit code gates CI.

MCP server

mcp_server/ exposes the engine over the Model Context Protocol (stdio):

Tool

Purpose

get_brand_voice

voice, audience, banned words, facts-only rule

get_generation_limits

the hard caps + run flags

list_sample_products

the five fixture products

validate_content_kit(row, product)

score a draft with the same rules as the evals

run_content_engine(dry_run=True, …)

POST the workflow webhook with per-run flags — dry-run by default

Resources: content-engine://columns (Review sheet column map), content-engine://prompts/{A|B|C}.

Claude Desktop / Claude Code config:

{
  "mcpServers": {
    "shopify-content-engine": {
      "command": "content-engine-mcp",
      "env": { "N8N_WEBHOOK_URL": "https://<your-instance>/webhook/shopify-content-engine-run" }
    }
  }
}

Repo layout

workflows/     shopify-content-engine.workflow.json · error-handler.workflow.json   (import these)
prompts/       system prompts A / B / C + prompt library (version-controlled mirror of ⚙️ Config)
config/        brand-voice.yaml · generation.config.yaml                            (limits, flags)
docs/          runbook.md · architecture.mmd · output-sheet-columns.md
test/          product-fixtures.json (5 products) · dry-run checklist · a real generated kit
evals/         checks.py (rules) · judge.py (LLM judge) · golden/ · tests/
mcp_server/    server.py · tests/
scripts/       check_workflows.py — static checks on the exported JSON (runs in CI)

Quick start

Workflow

  1. Import workflows/error-handler.workflow.json, then workflows/shopify-content-engine.workflow.json.

  2. Re-select credentials on the OpenAI / Google Sheets / Drive / Gmail nodes (never stored in the JSON).

  3. Point 📥 Read Products, 📖 Read Done, 📤 Write at a sheet with tabs Products and Review.

  4. Set Settings → Error Workflow to the imported error handler.

  5. Dry-run the five fixtures (test/README.md), then run for real. Run flags can be posted in the webhook body: {"dryRun": true, "enableImages": false}.

Evals + MCP

pip install -e ".[mcp,dev]"
python -m evals                     # score the golden set
python -m evals --input export.csv  # score your own Review-tab export
pytest                              # 27 tests: rules, negative cases, MCP tools in-process
content-engine-mcp                  # start the MCP server (stdio)

Roadmap

  • Minimum-length guard + one self-correcting retry in the Parse step (the eval currently flags short copy after the fact).

  • Header-auth on the webhook trigger (n8n credential) — today it relies on the unguessable path.

  • Shopify Admin API as the product source and a Draft product write-back behind the same approval gate.

  • Golden set: more real kits, one per fixture, and a nightly --judge run.

License

MIT

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/AbdulRehman0004/shopify-ai-content-engine'

If you have feedback or need assistance with the MCP directory API, please join our Discord server