Skip to main content
Glama
petrycz

ecommerce-mcp-automation

by petrycz

Ecommerce MCP Automation

A sample Claude Code + MCP integration: Shopify and Meta Ads exposed as MCP tools, plus a reporting agent that pulls both into one formatted daily P&L + ad-performance spreadsheet — no manual copy-paste between platforms.

This is a demonstration built against the public Shopify Admin API and Meta Marketing API docs — not something that has run a real business. It's a clean-room sample: real endpoints, real auth, real pagination, real error handling, written fresh to show exactly how this kind of automation gets built. It runs end-to-end in mock mode with zero credentials (realistic fixture data standing in for live responses), and switches to live mode per-integration the moment real credentials are set — see How to run.

The Shopify client has been run live against a real Shopify Partners development store (a sandbox store, not a production business) — real auth, a real order, real API responses. That process surfaced and fixed two real nullability edge cases (see Known simplifications) that the mock fixtures alone hadn't covered. Meta Ads runs against the mock transport by default in this repo; the client code is written the same way and switches to live the moment META_ACCESS_TOKEN/META_AD_ACCOUNT_ID are set.

What it does

  • Exposes Shopify orders, revenue, and COGS as MCP tools (get_orders, get_daily_pnl)

  • Exposes Meta Ads spend, impressions, purchases, and ROAS as MCP tools (get_insights, get_daily_ad_performance)

  • Runs a reporting agent (daily_report.py) that pulls both concurrently and writes a formatted .xlsx — Summary, Orders, and Ad Performance sheets

  • Ships a Claude Code Skill that wraps the whole workflow behind a natural-language trigger ("run the daily report")

  • Includes a committed sample output so the result is visible without running anything

Related MCP server: Presso MCP Server

Sample output

Rendered preview of the Summary tab — open the actual generated workbook for the live file (with the Orders and Ad Performance sheets, currency/ROAS formatting, and frozen header rows).

Architecture

flowchart LR
    subgraph Shopify["Shopify Admin API"]
        SO[orders.json]
        SI[inventory_items.json]
    end
    subgraph Meta["Meta Marketing API"]
        MI[act_id/insights]
    end

    SO --> SC[shopify_client.py]
    SI --> SC
    MI --> MC[meta_ads_client.py]

    SC --> SS[shopify_server.py<br/>MCP tools]
    MC --> MS[meta_ads_server.py<br/>MCP tools]

    SC --> DR[daily_report.py]
    MC --> DR
    DR --> SPX[spreadsheet.py]
    SPX --> XLSX[(sample_daily_report.xlsx)]

    Mock[["mock_api.py<br/>(ASGITransport, in-process)"]] -.mock mode.-> SC
    Mock -.mock mode.-> MC

The two API clients (clients/shopify_client.py, clients/meta_ads_client.py) are genuine integration code — real endpoint URLs, real auth headers, real pagination loops, real 429 backoff. The only thing that changes between mock and live mode is the HTTP transport (clients/http.py):

  • Live: httpx.AsyncClient opens a real connection to Shopify / Meta.

  • Mock: httpx.AsyncClient is given an httpx.ASGITransport pointed at an in-process FastAPI app (fixtures/mock_api.py) serving realistic fixture payloads. No port is bound, no subprocess runs — but requests still travel through genuine HTTP/ASGI routing, headers, and JSON encoding.

That means the client code a reviewer reads is the same code that would run against a live store — not a mock dressed up to look like one. See CLAUDE.md for the full conventions.

How to run

Mock mode (default — zero credentials)

git clone <this-repo> && cd ecommerce-mcp-automation
python -m venv .venv && source .venv/bin/activate   # or: uv sync && source .venv/bin/activate
pip install -e ".[dev]"

python -m ecommerce_mcp.reporting.daily_report
# -> Wrote examples/sample_daily_report.xlsx

Run the test suite the same way, no setup needed:

pytest

Live mode

Copy .env.example to .env and fill in what you have — each integration switches to live independently the moment its own credentials are present, so you can run Shopify live with Meta still mocked (or vice versa):

cp .env.example .env
# SHOPIFY_STORE_DOMAIN=your-dev-store.myshopify.com
# SHOPIFY_ACCESS_TOKEN=shpat_...          (Partners dev store -> custom app -> Admin API token)
# META_ACCESS_TOKEN=EAA...                (System User token, ads_read scope)
# META_AD_ACCOUNT_ID=act_1234567890

As MCP servers (Claude Code / Claude Desktop)

Add to your MCP config (.mcp.json for Claude Code, or Claude Desktop's config file). Point command at the project's venv interpreter directly — MCP clients don't source your shell profile, so a bare python won't see an activated venv:

{
  "mcpServers": {
    "shopify": {
      "command": "/path/to/ecommerce-mcp-automation/.venv/bin/python",
      "args": ["-m", "ecommerce_mcp.mcp_servers.shopify_server"],
      "cwd": "/path/to/ecommerce-mcp-automation"
    },
    "meta-ads": {
      "command": "/path/to/ecommerce-mcp-automation/.venv/bin/python",
      "args": ["-m", "ecommerce_mcp.mcp_servers.meta_ads_server"],
      "cwd": "/path/to/ecommerce-mcp-automation"
    }
  }
}

Then ask Claude things like "what's today's Shopify P&L?" or "get me yesterday's Meta ad performance" — it'll call the tools directly, in mock mode by default.

As a Skill

skills/daily-report/SKILL.md wraps the report-generation workflow so Claude Code runs it on a natural-language trigger ("run the daily report") rather than needing the exact CLI command. The full-report path doesn't need the MCP config above at all — it runs daily_report.py directly, which calls the clients as plain Python, no MCP involved. MCP config is only needed for the Skill's other path: answering a one-off single-metric question ("what's today's ROAS?") by calling get_daily_pnl / get_daily_ad_performance as MCP tools instead of running the whole report.

Project layout

src/ecommerce_mcp/
  clients/         Typed, async API clients (Shopify + Meta), transport-swappable
  mcp_servers/      MCP tool servers wrapping the clients
  reporting/        daily_report.py (orchestration) + spreadsheet.py (openpyxl)
  fixtures/         Realistic mock payloads + the in-process mock API app
skills/daily-report/ Claude Code Skill for the reporting workflow
tests/              pytest suite (all run against mock mode)
examples/           Committed sample .xlsx + README preview image

Known simplifications

Documented here rather than hidden, since precision matters more than polish for a sample like this:

  • COGS uses Shopify's InventoryItem.cost field via the real two-hop lookup (variant → inventory_item_id → batched inventory_items fetch) — Shopify doesn't expose cost on the order line item directly. Both cost and line-item sku are nullable on a live store (a merchant may never have set them) — found via live testing against a real dev store, not from the docs alone. Both are handled as zero-cost / missing-SKU rather than erroring.

  • Refunded orders are excluded entirely from revenue/COGS/order count in daily_pnl(). Partial refunds/returns accounting would need the Refund resource — out of scope here.

  • Meta purchase attribution uses the purchase action type from the actions/action_values arrays at whatever attribution window the ad account is configured with — this client doesn't override it.

  • The reporting agent currently pulls all available orders/insights rather than filtering by date range; a production daily cron would pass created_at_min/time_range for the target day.

License

MIT — see LICENSE.

Available Tools

2 tools
get_daily_pnlA

Revenue, COGS, and gross profit across the current order set.

COGS is resolved per line item via the Shopify inventory item cost field. Refunded orders are excluded.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A4/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden of behavioral disclosure. It usefully explains that COGS is resolved per line item and that refunded orders are excluded. However, it does not define what 'current order set' means or how the 'daily' period is determined, leaving ambiguity in the tool's scope.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is compact and front-loaded, with the core metrics stated in the first sentence. Every subsequent line adds distinct value: cost-resolution method and refund exclusion. There is no redundancy or filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

There is no output schema or annotations, so the description must communicate both the result metric and behavioral caveats, which it does adequately for a zero-parameter tool. The main gap is that the exact time period of 'current order set' is left undefined.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool has zero parameters and the schema covers everything about parameters, so the description does not need to explain parameter semantics. It still adds meaning by describing what the computed values represent, which is sufficient given no parameters exist.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with the specific metrics 'Revenue, COGS, and gross profit' and names the resource 'current order set.' This clearly distinguishes the tool from its sibling get_orders, which would return orders rather than a financial summary.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives helpful context such as 'across the current order set' and 'Refunded orders are excluded,' but it does not explicitly state when to use this tool versus get_orders or when not to use it. Usage guidance is implied rather than clearly articulated.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_ordersA

Fetch Shopify orders (paginated automatically).

Args: status: Order status filter — "any", "open", "closed", or "cancelled".

ParametersJSON Schema
NameRequiredDescriptionDefault
statusNoany

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the behavioral burden. It usefully discloses that pagination is handled automatically, which is a non-obvious behavior an agent needs to know. It does not mention auth or rate limits, but for a simple fetch operation the pagination disclosure is meaningful.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two concise sentences cover purpose, pagination behavior, and the parameter's allowed values. Every sentence earns its place, and the most important information is front-loaded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a one-parameter fetch tool with an output schema, this description is complete. It covers what the tool does, the parameter semantics, and a key behavioral detail (automatic pagination). The sibling tool is clearly distinct, so no additional routing context is necessary.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate. It fully defines the only parameter, status, and lists all allowed values: 'any', 'open', 'closed', or 'cancelled'. This adds clear meaning beyond the schema, which only shows type and default.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Description states a specific action and resource: 'Fetch Shopify orders'. The automatic pagination note adds scope, and the sibling get_daily_pnl is clearly a different resource, so an agent can distinguish them without opening schemas.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies usage when order data is needed and offers a status filter, but it does not explicitly say when to use this tool versus get_daily_pnl or any other alternative. There are no exclusions or conditional routing cues.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 2 tool updatesv0.1.0
    • First observedget_daily_pnl
    • First observedget_orders

TDQS

A3.9/5.0

Scored across 2 tools

Disambiguation5/5

get_orders returns raw order data, while get_daily_pnl computes financial metrics. Their purposes are entirely distinct with no overlap, making tool selection unambiguous.

Naming Consistency5/5

Both tools follow the consistent get_<noun> pattern, which is clear and predictable. There is no mixing of styles or ambiguous verbs.

Tool Count3/5

With only two tools, the set feels thin for a server labeled 'ecommerce automation'. However, it is not a single trivial tool, so borderline is appropriate.

Completeness1/5

The server provides only read-only order access and a PnL report. There are no create/update/delete operations, product or customer tools, refund handling, or broader automation workflows, making the surface severely incomplete for ecommerce automation.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    F
    maintenance
    Free, open-source MCP server that connects Claude to the Shopify Partner API. 25 tools for revenue analytics, churn analysis, retention cohorts, merchant health scoring, conversion funnels, revenue forecasting, and growth velocity.
    25
    13
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    Connects e-commerce and marketing data sources like Shopify, GA4, Google Ads, and Meta Ads to AI assistants, enabling natural language queries about store performance, ad campaigns, and customer behavior.
    7 npm
    2
    MIT
  • F
    license
    Not graded
    quality
    C
    maintenance
    Hosted MCP server connecting Shopify, Klaviyo, GA4, Meta Ads, Google Ads, Xero, Gorgias and 20+ e-commerce data sources so AI assistants can answer merchant questions that span every source at once.
    -
  • A
    license
    Not graded
    quality
    C
    maintenance
    Connects Claude to Meta Ads, enabling full management of ad accounts including campaigns, creatives, budgets, and reporting. Handles authentication, token minting, and MCP server registration automatically.
    MIT