aleccritser

StoreLink MCP Server

Community aleccritser
Updated

StoreLink MCP server for Korral category buyers (Duvo)

StoreLink MCP Server

Python MCP server that exposes the hypothetical StoreLink grocery stocking API as agent tools over stdio.

StoreLink is used by a European grocer with locations across Europe, primarily in Czechia (also Slovakia and Austria in the mock data).

Tools

Built for a category buyer workflow: check on-hand vs last-24h POS, apply the delta rule, then replenish.

Tool Description
list_stores List stores
get_store Store details
get_on_hand_vs_pos Primary check: on-hand + POS + delta + product/case_pack
create_replenishment Raise a replenishment order
get_replenishment Order status

get_on_hand_vs_pos defaults the POS window to the last 24 hours when since is omitted. It returns delta = units_sold − available and a product block (case_pack, lead_time_days, etc.).

Buyer rule: if delta >= 6, call create_replenishment (prefer multiples of product.case_pack).

Butter test scenario

Field Value
SKU 8847291 — Madeta butter 250g
Store 47 Praha Budějovická — available 4, ~12 sold / 24h → delta 8 → replenish
Store 102 Brno Vaňkovka — available 18, ~5 sold / 24h → delta −13 → do not replenish

Setup

Requires Python 3.10+.

# From the project root
uv sync

Or with pip:

pip install -e .

Configuration

Variable Default Description
STORELINK_MODE mock mock = in-process fixtures; http = call the real API
STORELINK_BASE_URL https://storelink.com Base URL used in http mode
STORELINK_API_KEY (unset) Optional Bearer for non-store endpoints
KORRAL_GCP_PROJECT (required in http) GCP project where Korral stores weekly-rotated store keys
KORRAL_SECRET_PREFIX korral-store- Secret id = {prefix}{store_id} (e.g. korral-store-47)
STORELINK_AUDIT_LOG logs/storelink-audit.ndjson NDJSON audit log file path
STORELINK_THREAD_ID (session id) Optional agent/thread id for correlating a chat
STORELINK_BUYER_LOG logs/buyer-activity.ndjson Category-buyer activity (JSON lines)
STORELINK_BUYER_MD logs/buyer-activity.md Category-buyer activity (readable markdown)

Every tool requires a reason string (why the agent is calling it). That value is written into the audit trail as ground-truth rationale.

Korral per-store API keys

Korral IT rotates a per-store API key weekly in GCP Secret Manager. Store-scoped StoreLink calls send:

X-Korral-Store-Key: <key>

Secret naming: projects/{KORRAL_GCP_PROJECT}/secrets/{KORRAL_SECRET_PREFIX}{store_id}/versions/latest Example for store 47: korral-store-47.

Auth behavior:

  1. Before any store-scoped request, the key is loaded (cached in memory).
  2. If the secret does not exist, the tool fails immediately with a clear message for the agent (no HTTP call): No Korral API key configured for store … Ask Korral IT to provision the weekly-rotated key.
  3. If StoreLink returns 401 (key rotated in flight), the cache is invalidated, the latest secret is fetched, and the request is retried once.

Store-scoped tools/endpoints: get_store, inventory/POS inside get_on_hand_vs_pos, create_replenishment, get_replenishment. list_stores / SKU-supplier lookups do not require a store key.

Use Application Default Credentials (GOOGLE_APPLICATION_CREDENTIALS or workload identity) so the MCP process can read Secret Manager.

Audit logging

All audit events are standardized JSON (one object per line / NDJSON), written to stderr and appended to STORELINK_AUDIT_LOG.

Common envelope:

{
  "schema_version": "1.0",
  "event_type": "tool_call_started",
  "timestamp": "2026-08-01T17:00:00.123Z",
  "session_id": "…",
  "interaction_id": "…",
  "thread_id": "…",
  "service": "storelink-mcp",
  "level": "info",
  "payload": {
    "tool": "get_on_hand_vs_pos",
    "arguments": { "store_id": "47", "sku": "8847291", "reason": "…" },
    "reason": "Check store 47 butter sell-through before replenish decision"
  }
}
event_type When
session_started / session_ended Process lifetime
tool_call_started Tool invoked
tool_call_succeeded Tool returned (includes duration_ms, result_summary)
tool_call_failed Tool error (includes error, and traceback for unexpected failures)

interaction_id is unique per tool invocation and shared across that call’s started/succeeded/failed events.

Category buyer activity feed

Alongside the engineer audit log, every agent action is also written in plain language for category buyers:

  • Why the agent acted (from the required reason argument)
  • What happened (stock checked, order placed, etc.)
  • Outcome (e.g. replenishment recommended when delta ≥ 6)

Files:

  • logs/buyer-activity.md — human-readable timeline
  • logs/buyer-activity.ndjson — same entries as structured JSON

MCP resource (not a tool — does not clutter the buyer agent loop):

  • buyer://activity — current-session feed in markdown

Example markdown entry:

### 2026-08-01T17:22:49Z — Checked on-hand vs recent sales for Madeta butter 250g at store 47

**Status:** Needs attention
**Why the agent did this:** Check butter delta at store 47 before replenish decision
**What happened:** In the last 24 hours, about 12 units sold; 4 units are still available on the shelf (gap/delta: 8).
**Outcome:** Sales are outpacing stock (delta 8 ≥ 6). A replenishment order is recommended.

Mock mode includes Czech/EU stores (plus scenario stores 47 and 102), metric SKUs including 8847291, inventory, POS history (CZK/EUR), and Central European suppliers.

Run

uv run storelink-mcp
# or
uv run python -m storelink_mcp.server

Cursor / Claude Desktop config

Add to your MCP settings (e.g. Cursor mcp.json):

{
  "mcpServers": {
    "storelink": {
      "command": "/Users/aleccritser/.local/bin/storelink-mcp-cursor",
      "env": {
        "STORELINK_MODE": "mock"
      }
    }
  }
}

Important: the project path contains a space (Duvo Task). Cursor splits the command field on spaces, so pointing command at .venv/bin/storelink-mcp under that folder fails with spawn /Users/aleccritser/Duvo ENOENT. Use the no-space launcher at ~/.local/bin/storelink-mcp-cursor (created by the project setup), or uv with the directory passed as a separate arg:

{
  "mcpServers": {
    "storelink": {
      "command": "/Users/aleccritser/.local/bin/uv",
      "args": ["run", "--directory", "/Users/aleccritser/Duvo Task", "storelink-mcp"],
      "env": {
        "STORELINK_MODE": "mock"
      }
    }
  }
}

For live HTTP against a StoreLink deployment:

{
  "mcpServers": {
    "storelink": {
      "command": "uv",
      "args": ["run", "--directory", "/absolute/path/to/Duvo Task", "storelink-mcp"],
      "env": {
        "STORELINK_MODE": "http",
        "STORELINK_BASE_URL": "https://storelink.com",
        "STORELINK_API_KEY": "your-api-key"
      }
    }
  }
}

Example agent flow

  1. get_on_hand_vs_pos("47", "8847291", reason="…") → read delta and product.case_pack
  2. If delta >= 6create_replenishment(..., reason="delta>=6 …")
  3. Optionally check store 102 (delta should stay below 6 — no order)
  4. get_replenishment(..., reason="…") → poll status

MCP Server · Populars

MCP Server · New

    gura105

    Operational Ontology

    A minimal, readable reference implementation of the Operational Ontology pattern. Palantir Foundry is one implementation; this is the concept, minimized.

    Community gura105
    EllisMorrow

    Caelune

    Caelune (星野) — Local-first retrieval for private Markdown, PDF, and Tika documents, with a Windows desktop app and read-only MCP server.|本地优先的私人知识检索工具。

    Community EllisMorrow
    vmware-skills

    VMware AIops

    VMware vCenter/ESXi AI-powered monitoring and operations. Two skills: vmware-monitor (read-only, safe) and vmware-aiops (full operations) | Claude Code Skill

    Community vmware-skills
    asdecided

    AsDecided

    Native deterministic requirements-as-code engine and read-only MCP server.

    Community asdecided
    Mapika

    portview

    See what's on your ports, then act on it. Diagnostic-first port viewer for Linux, MacOS and Windows.

    Community Mapika