Skip to main content
Glama
yusi20006-max

DigiSnap-MCP

README.md
# DigiSnap-MCP

MCP server for comparing products, prices, sellers, availability and specifications across **Digikala** and **SnappShop**.

## Status

**Phase 7 — Remote Streamable HTTP transport for Grok implemented.**

## Registered tools

- `list_stores` — registered adapters
- `search_digikala` — search normalized Digikala products
- `get_digikala_product` — fetch normalized Digikala details
- `search_snappshop` — search normalized SnappShop products
- `get_snappshop_product` — fetch normalized SnappShop details, variants and offers
- `compare_products` — identity, variant, specification and offer comparison
- `compare_offers` — normalized offer and price comparison
- `compare_prices` — backward-compatible price comparison
- `find_best_price` — lowest observed comparable offer with explicit filters
- `find_best_value` — policy-driven offer selection with explainable reasons
- `analyze_offers` — expose observed price, discount, seller, warranty and availability signals

## Remote MCP / Grok

For local development the server keeps **stdio** as the default transport.

For a remote deployment, set:

```text
MCP_TRANSPORT=http
```

The Streamable HTTP MCP endpoint is exposed at:

```text
https://<public-host>/mcp
```

A lightweight `GET /health` endpoint is provided for deployment health checks.

xAI Grok supports external MCP servers over Streaming HTTP and SSE. A public HTTPS MCP URL can be registered as a Custom MCP connector.

## Cross-store comparison

Phase 4 keeps provider-specific fields inside adapters and compares only canonical models.

The comparison layer provides:

- product identity matching with an explainable similarity score
- explicit variant mismatch detection
- brand/model/title signals
- shared specification comparison
- explicit specification differences
- seller, warranty, condition and availability fields on offers
- lowest available offer
- absolute and percentage price delta
- purchase URLs
- currency-safe price deltas: a monetary delta is omitted when the comparable offers use different currencies
- missing values remain unknown rather than being inferred

A match is a comparison signal, not an assertion of identity. Consumers can inspect `matched`, `score` and `reasons` before using a cross-store result.

## Shopping intelligence

Phase 5 adds provider-neutral intelligence on canonical offers. It does not invent prices, availability or specifications.

- `find_best_price` filters normalized offers and compares only offers with the same currency.
- Seller IDs, minimum seller rating, warranty and availability can be explicit filters.
- `find_best_value` uses an ordered policy such as `price`, `availability`, `warranty`, `seller_rating` or `discount`; there is no hidden composite score.
- Discount percentages are calculated only when both current and observed regular prices are present.
- `PriceObservation` / `PriceHistoryProvider` define an optional historical-price contract without requiring a storage backend.
- `StockMonitorHook` defines an optional application hook for stock monitoring.

## Provider adapters

### SnappShop

The adapter targets the public JSON API surface observed at `apix.snappshop.ir`:

- `POST /search/v1` for product search
- `GET /products/v2/{product_id}` for product details

The upstream API is undocumented and may change. Provider-specific HTTP and payload parsing are isolated in `snappshop.py`.

### Digikala

The Digikala web API is also undocumented and may change. Provider-specific HTTP, endpoint paths and payload parsing are isolated in `digikala.py`.

Prices are preserved as returned by the upstream payload and currently represented as `IRR` in the canonical model. No implicit 10x Toman/Rial conversion is performed.

## Production hardening

Phase 6 adds bounded retries for transient upstream failures, structured adapter error logging, reproducible CI checks, dependency auditing, compile/import smoke checks, contribution and security documentation, and an MCP client configuration example.

- Retries are limited and use exponential backoff; non-transient errors are not retried.
- Upstream response bodies, headers, cookies and credentials are not logged.
- `429` remains a rate-limit signal; `404` remains a not-found signal for SnappShop.
- CI runs Python 3.11–3.13 tests, Ruff linting, coverage reporting, compilation and smoke import checks, plus `pip-audit`.
- The package is released under the MIT License.

## Upstream resilience

Phase 8.4 adds provider-specific pacing, bounded retry/backoff, upstream response classification, short-lived successful GET caching, and cookie persistence for bounded Digikala challenge retries. See `docs/upstream-resilience.md`.

## Development

Requires Python 3.11+.

```bash
python -m pip install -e ".[dev]"
pytest
```

Run:

```bash
digisnap-mcp
```

## Roadmap

1. Core MCP Server & Architecture — complete
2. Digikala Adapter — complete
3. SnappShop Adapter — complete
4. Cross-Store Product & Offer Comparison — complete
5. Shopping Intelligence — complete
6. Production Hardening, CI & Release — complete
7. Remote Streamable HTTP transport for Grok — complete

## Design principles

- Store-specific code stays inside adapters.
- Comparison operates only on normalized domain models.
- Missing upstream data is represented as unknown, never invented.
- Product variants remain explicit.
- External-store behavior is isolated behind adapter boundaries.

## MCP client configuration

See `examples/mcp-client.json` for a minimal stdio configuration.

## Release

Releases use semantic version tags such as `v0.6.0`. The release candidate must pass the complete CI matrix and dependency audit before tagging.

TDQS

C2.8/5.0

Scored across 11 tools

Disambiguation3/5

The two store-specific search/get tools are clearly distinct, but the comparison cluster (compare_products, compare_offers, compare_prices) and ranking/value tools (find_best_price, find_best_value) have subtle boundaries. Descriptions help distinguish them, but an agent could still hesitate between compare_prices and compare_offers or between the two find_best tools.

Naming Consistency5/5

All tool names use snake_case with a predictable verb_noun structure, such as search_digikala, get_digikala_product, compare_offers, and find_best_price. Minor variations like search_digikala omitting 'product' are natural and do not break the pattern.

Tool Count5/5

With 11 tools, the set is well-scoped for a multi-store product search and comparison server. Each tool appears to earn its place, covering store listing, per-store search/get, cross-store comparison, and offer analysis without excessive bloat.

Completeness4/5

The surface covers the read-only shopping comparison lifecycle well: list stores, search and get products per store, compare products/offers/prices, and analyze or select best offers. Minor gaps exist, such as no generic cross-store search tool or store-adapter management, but core workflows are covered.

Maintenance

ActivityMaintained
ResponsivenessUnresponsive