shopico
Provides demand forecasting, reorder recommendations, and impact reports based on Shopify store data, including sales history, inventory levels, and order information.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@shopicoForecast demand for my top 10 products and show dollar impact."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Shopify Demand & Inventory Copilot
A production-grade demand forecasting and inventory-risk system for Shopify merchants: a live GraphQL Admin API integration (OAuth install, webhooks, bulk operations), per-SKU forecasting with an eval-gated promotion process, and every forecast translated into an estimated dollar impact versus a naive baseline -- not just an accuracy score.
This is built as an installable, multi-tenant Shopify app (any merchant can install it via OAuth), not a tool wired to one personal store.
Status: Phase 4 of 4 (complete)
Phase | Scope | Status |
0 | Repo scaffold, schema, local Postgres | Done |
1 | Seasonality-aware data generation, Shopify OAuth install flow, webhook ingestion (HMAC-verified), bulk-operation reconciliation | Done |
2 | dbt aggregation ( | Done |
3 | Per-SKU LightGBM model, MLflow tracking, promotion gate | Done -- see REPORTS.md |
4 | FastAPI serving ( | Done (this pass) |
Headline result (see REPORTS.md for the full, real MLflow-logged history): the promoted forecasting model has worse raw accuracy than the naive baseline (6.69 vs. 5.39 units MAE) but delivers +$11,593.21 over the baseline across a 12-week/24-SKU backtest, because it was trained toward the newsvendor-optimal quantile instead of the conditional mean. Three earlier, accuracy-competitive candidates were correctly rejected by the promotion gate before this fix, along with a deliberately weak model on every run -- real evidence the gate evaluates dollars, not accuracy.
Related MCP server: shopops-mcp
What's real vs. what needs live Shopify credentials
There's no Shopify Partner account or dev store yet, so everything is built in two tracks:
Runs today, no Shopify credentials needed: local Postgres, the seasonality/promo/catalog generators,
data_generator/seed_local.py(writes synthetic order history directly into Postgres), the webhook listener + HMAC verification (tested with locally-crafted signed payloads).Implemented against the real Shopify API contract, but requires a live Partner dev store (or a real merchant install) to actually run:
shopify_client/oauth.py(app install flow),data_generator/shopify_seed.py(seeds history via realorderCreatemutations),ingestion/bulk_backfill.py(weekly reconciliation viabulkOperationRunQuery).
Creating a Shopify Partner account and a free development store (no credit card, ~10 minutes) is what unlocks live end-to-end testing of the second track. Until then, the first track proves the ingestion/storage contract works correctly on its own.
Repo layout
data_generator/ seasonality + promo + catalog models, local and live seeding
shopify_client/ Admin GraphQL client, OAuth install flow, bulk operations
ingestion/ FastAPI app: webhook listener (HMAC-verified) + OAuth routes, bulk reconciliation job
dbt/ staging models + daily_sku_sales mart
forecasting/ naive baseline, $-value dollarization, backtest harness, LightGBM training, MLflow promotion gate
serving/ GET /forecast, /reorder, /impact-report business logic, mounted into ingestion's FastAPI app
mcp_server/ MCP tool wrappers over serving/, for use from Claude Desktop/Code or any MCP client
dashboard/ Streamlit dashboard leading with the live $-impact headline number
monitoring/ Evidently feature-drift report + a custom $-impact-degradation trend check
db/ schema.sql, tiny psycopg2 connection helper
tests/ pytest suite
.github/workflows/ CI (tests on push/PR) + scheduled weekly retrain (+ drift check)
Dockerfile image shared by the api/dashboard/mlflow-ui docker-compose services
docker-compose.yml postgres + api + dashboard + mlflow-ui for local dev
REPORTS.md Phase 3 baseline-vs-model comparison, accuracy and dollar termsRunning Phase 1 locally
Start Postgres
docker compose up -d postgresThis applies
db/schema.sqlautomatically on first start.Set up a virtualenv and install deps
python -m venv .venv .venv/Scripts/activate # or source .venv/bin/activate on macOS/Linux pip install -r requirements.txt cp .env.example .envGenerate a
TOKEN_ENCRYPTION_KEY:python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"Seed 18-24 months of synthetic order history
python -m data_generator.seed_local --months 20Re-run with
--resetto regenerate. This writes a dev shop, a 24-SKU catalog with Pareto-ish popularity, and daily orders driven by a trend + weekday seasonality + quarterly/BFCM promo-spike curve.Run the ingestion API
uvicorn ingestion.main:app --reloadGET /health,GET /auth?shop=...(install flow),POST /webhooks(HMAC-verifiedorders/create/orders/updated/inventory_levels/update).Run the tests
pytest tests/Covers: HMAC accepts a correctly-signed payload and rejects a forged or missing signature (both as pure-function checks and as full webhook-endpoint integration checks that assert nothing is written to the DB on rejection).
Build the
daily_sku_salesmart with dbtdbt run --project-dir dbt --profiles-dir dbtAggregates
orders+order_line_itemsinto daily per-SKU unit sales. The dbt profile defaults to the docker-compose Postgres credentials, so no extra config is needed for local dev.Run the backtest harness
python -m forecasting.backtestReplays the last 12 weeks for every product, using a trailing 4-week moving average as the naive baseline (
forecasting/baseline.py), and writes each SKU-week's actual/predicted/baseline/dollar-impact intobacktest_results. Phase 2 has no trained model yet, sopredicted_unitsis deliberately set equal to the baseline -- the headline dollar impact should print as$0.00, which is the expected, correct result: it proves the harness and the dollarization math (forecasting/backtest.py::dollarize_forecast_error) are wired correctly without a real model muddying the signal. Phase 3's trained model plugs into this same harness as a genuinely differentpredicted_unitsand is expected to produce a non-zero (ideally positive) number.Train the model, run the promotion gate, and see the real comparison
python -m forecasting.trainTrains a global LightGBM model (product_id as a categorical feature) plus a deliberately weak
DummyRegressor"control" candidate, backtests both through the exact same harness as the baseline, logs everything to MLflow (MLFLOW_TRACKING_URI, defaults to a localsqlite:///mlflow.dbso Model Registry stage transitions work without a real server), and only promotes a candidate to theProductionstage if it beats both the baseline and whatever's currently deployed, in dollars (forecasting/registry.py). Prints a comparison table at the end; see REPORTS.md for the full real run history from this project's own development, including multiple rejections.mlflow ui --backend-store-uri sqlite:///mlflow.dbto browse runs/versions/stage transitions in the MLflow UI.
Running Phase 4 locally
Serve live forecasts (after step 8 has promoted a model -- otherwise these fall back to the naive baseline)
uvicorn ingestion.main:app --reloadGET /forecast?shop_domain=...&sku=...,GET /reorder?shop_domain=...&sku=...,GET /impact-report?shop_domain=....Run the dashboard
streamlit run dashboard/app.pyLeads with the live $-impact-vs-baseline headline number (
serving/impact_report_service.py), then a per-SKU breakdown and the reorder-recommendations table.Register the MCP server (wraps the same
serving/logic as three MCP tools:get_forecast_tool,get_reorder_recommendation_tool,get_impact_report_tool)claude mcp add shopico -- python -m mcp_server.serverOr run directly with
python -m mcp_server.server(stdio transport) to register with any other MCP client.Check for degrading $-impact or feature drift
python -m monitoring.drift_monitorPrints an early-half-vs-recent-half $-impact trend for the active model and writes an Evidently feature-drift HTML report to
monitoring/reports/. Wired into the weekly retrain workflow as a post-training step.Or run the whole stack in Docker
docker compose up -d --buildapi(port 8000, ingestion + serving),dashboard(port 8501),mlflow-ui(port 5000) all bind-mount the host's./mlflow.db, so they see whatever step 8 already promoted rather than starting from an empty registry.
Once a Partner dev store exists
python -m data_generator.shopify_seed --months 20 # seeds via real orderCreate mutations
python -m ingestion.bulk_backfill --shop-domain your-store.myshopify.com --access-token <token> --since-days 7And point the app's /auth?shop=your-store.myshopify.com at a running
ingestion.main:app (with SHOPIFY_APP_URL set to a publicly reachable URL,
e.g. via ngrok for local dev) to exercise the full install flow.
Design notes worth knowing
products.shopify_inventory_item_idis an addition beyond the original spec's schema:inventory_levels/updatewebhooks key offinventory_item_id, not SKU, so there's no way to route that event to a product row without it.Webhook ingestion and bulk-operation reconciliation intentionally write through the same
handle_order_webhookfunction (ingestion/webhook_listener.py), so both paths agree by construction on overlapping records.Everything uses a single
psycopg2(sync) driver, no ORM -- matches the spec's "right-sized, not cloud-scale" philosophy (see original spec §7).dollarize_forecast_error's sign convention was corrected vs. the original spec pseudocode. The pseudocode'scost_of_errorreturns a positive cost for the stockout branch but a negative value for the overstock branch. Walk through a case where the model forecasts perfectly and the baseline over-forecasts:baseline_cost - model_costshould be positive (model saved money by avoiding the baseline's excess inventory), but the pseudocode's sign makes it negative -- and more negative the worse the baseline overstocks, inverting the stated "positive = value created" meaning. Fixed by havingcost_of_erroralways return a positive cost magnitude in both branches. Seeforecasting/backtest.py's module docstring andtests/test_dollar_impact_calc.py::test_overstock_scenario_*for the hand-verified case that pins this down.The naive baseline (
forecasting/baseline.py) is a trailing 4-week moving average of weekly units sold, computed strictly from weeks before the target week (no leakage) -- the standard, easy-to-hand-verify "seasonal naive" baseline for weekly-bucketed retail demand.A single global LightGBM model, not per-SKU models. The spec allows "per-SKU (or per-SKU-cluster, for low-volume SKUs)"; with ~600-900 days of history per SKU, one shared model with
product_idas a categorical feature borrows statistical strength across SKUs far better than fitting 24 independent models in isolation, especially for the long-tail ones.Trained toward a cost-optimal quantile, not the conditional mean.
dollarize_forecast_error's cost is asymmetric (stockouts cost a full unit's margin, overstock only a small holding fee), so a plain L2 regression model has no way to know that slight over-forecasting is usually cheaper than under-forecasting. This is the classic newsvendor problem;forecasting/train.py::newsvendor_critical_fractilederives the optimal LightGBM quantile objectivealphafrom each product's real unit economics rather than guessing. See REPORTS.md for what this fix actually changed (rejected → promoted, despite worse MAE).forecasting/backtest.py::write_backtest_resultsdeletes existing rows for amodel_versionbefore inserting -- discovered this needed to be idempotent while iterating during Phase 3 development, when re-running training for the same day's model label was silently accumulating duplicate rows and corruptingtotal_dollar_impact's aggregation.The promotion gate uses MLflow's Model Registry
Productionstage (viaMlflowClient.transition_model_version_stage) as the single source of truth for "what's currently deployed," rather than a custom state table. That API is deprecated as of MLflow 2.9 in favor of model aliases, but still functional as of 2.19 (used here) -- worth revisiting if this project upgrades MLflow significantly later.serving/model_loader.pyreusesforecasting/train.py::make_predict_fndirectly (loading the model viamlflow.lightgbm.load_model, notmlflow.pyfunc) so live inference goes through the exact same feature-building code path already validated in backtest -- no separate, potentially-drifted serving-time implementation. It caches the loaded model by MLflow registry version number (immutable once registered, unlike "Production" which changes meaning on every promotion), since callers that loop over many SKUs for one shop (dashboard/app.py,monitoring/drift_monitor.py) would otherwise reload the same model from disk once per SKU.forecasting/train.pynever persisted the naive baseline's ownbacktest_resultsrows (only trained candidates go throughwrite_backtest_results) -- a real gap this pass'sserving/impact_report_service.pyhad to work around: if the baseline has no rows for a shop, it's recomputed live viaforecasting.backtest.run_backtestinstead of silently reporting a zero MAE.The reorder policy (
serving/reorder_service.py) is a documented assumption, not real Shopify data:LEAD_TIME_WEEKS/SAFETY_STOCK_WEEKS/OVERSTOCK_WEEKS_OF_COVERare a standard weeks-of-cover policy, overridable via env vars, until a live merchant's actual lead times exist.fastapi was bumped from 0.115.6 to 0.139.0 (and pydantic 2.10.5 to 2.11.0) in this pass: fastapi 0.115.6 pinned
starlette<0.42, which can't coexist in one virtualenv with the starlette version streamlit 1.59.2 requires, and mcp 1.28.1 requirespydantic>=2.11. Existing tests (tests/test_webhook_hmac.py, the OAuth routes) still pass unchanged.The Docker image needs
libgomp1(apt-get install) --python:3.11-slimdoesn't include it, and LightGBM's native library won't load without it (OSError: libgomp.so.1: cannot open shared object file).Evidently alone only compares feature distributions, which wouldn't catch a model that's still "in-distribution" but has quietly stopped beating the baseline in dollars -- the metric this whole project is built around. So
monitoring/drift_monitor.pyruns a custom early-half-vs-recent-half $-impact trend check (flags >30% relative degradation, or a positive→negative flip) alongside Evidently's feature-drift report, rather than relying on feature drift as a proxy for the thing that actually matters.
All four planned phases are now complete. Natural next steps beyond the original scope: replacing MLflow's deprecated stage-based registry with aliases, real Shopify Partner dev-store credentials to exercise the OAuth/bulk paths end-to-end, and per-SKU (rather than catalog-average) lead times once real merchant inventory data exists.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- AlicenseAqualityAmaintenanceMulti-channel inventory intelligence for Shopify and Amazon sellers. 28 tools for stockout risk, demand forecasts, purchase order management, and sales analytics — with human-in-the-loop safeguards.Last updated50962MIT
- AlicenseAqualityBmaintenanceAI e-commerce operations manager for MCP. Inventory forecasting, pricing optimization, RFM customer segmentation, order anomaly detection, and automated reports for Shopify and WooCommerce.Last updated1243MIT
- AlicenseAqualityCmaintenanceEnables AI assistants to forecast revenue and demand for Shopify stores using Google's TimesFM model. Provides tools for revenue forecasting, demand analysis, promotion analysis, and anomaly detection.Last updated71MIT
- Alicense-qualityDmaintenanceEnables Shopify store owners to get actionable business insights such as sales comparisons, inventory alerts, and recommendations, transforming raw data into meaningful decisions.Last updated15MIT
Related MCP Connectors
Shopify MCP Pack — wraps the Shopify Admin REST API (2024-01)
Connect e-commerce and marketing data to AI assistants via MCP.
Remote MCP connector for eBay, Shopify, Best Buy & Etsy marketplace data via the Commerce API
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
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/HamzaOuadid/shopico'
If you have feedback or need assistance with the MCP directory API, please join our Discord server