Content
# MCP Server Сільпо (silpo-mcp)
MCP (Model Context Protocol) server for interaction with the internet supermarket **Сільпо** through AI assistants (Claude Desktop, Claude Code, etc.).
Built on real storefront-API requests of Сільпо (`sf-ecom-api.silpo.ua`), updated from network traffic. There is no official SDK - the API may change without notice.
## Capabilities
- 🔍 **Product Search** — by name or keywords
- 📁 **Categories** — view and filter product categories
- 🏷️ **Promotions** — products with discounts
- 📦 **Products by Category** — filtering and sorting
- 🛒 **Cart** — real cart of Сільпо; created automatically when adding a product for the first time
- 🧾 **Shopping List** — separate from cart, with "purchased" marks
- 🚚 **Delivery** — zone check, delivery types, time slots
- 💬 **Comments** — notes to products ("cut", "ripe")
- 🔐 **Authorization** — cabinet token for order history and bonus balance
## Installation
```bash
# Global installation
npm install -g silpo-mcp
# or without installation
npx silpo-mcp
```
From source code:
```bash
git clone https://github.com/MIt9/silpo-mcp.git
cd silpo-mcp
npm install
npm run build
npm start
```
## Configuration
### Claude Desktop / Claude Code
`claude_desktop_config.json` or `.mcp.json`:
```json
{
"mcpServers": {
"silpo": {
"command": "npx",
"args": ["-y", "silpo-mcp"]
}
}
}
```
Or from source code:
```json
{
"mcpServers": {
"silpo": {
"command": "node",
"args": ["/absolute/path/to/silpo-mcp/dist/index.js"]
}
}
}
```
> The store ID (`branch`) is determined automatically after setting the delivery address.
## Remote Hosting (Claude web / custom connector)
In addition to the local stdio mode, the server has a **remote HTTP mode** (`dist/http.js`),
protected by OAuth 2.1 - this is what Claude connects through the "custom connector".
The `OAuth Client ID` / `OAuth Client Secret` fields in Claude are **not** protection against
IP guessing, but standard OAuth: Claude acts as an OAuth client, and the server -
as an authorization server. Access is limited by **password** on the login page
(`SILPO_MCP_PASSWORD`), so outsiders, even knowing the URL, will not be able to use it.
### Launch
```bash
npm run build
SILPO_MCP_BASE_URL="https://silpo.example.com" \
SILPO_MCP_PASSWORD="your-reliable-password" \
SILPO_MCP_PORT=3000 \
npm run start:http
```
Environment variables:
| Variable | Mandatory | Description |
| --- | --- | --- |
| `SILPO_MCP_BASE_URL` | yes | Public **https** URL of the server (issuer for OAuth) |
| `SILPO_MCP_PASSWORD` | yes | Password for login (access gate) |
| `SILPO_MCP_PORT` | no | Port (typically 3000) |
| `SILPO_MCP_TOKEN_TTL` | no | Access token lifetime, sec (typically **2592000** = 30 days) |
| `SILPO_MCP_STATE_FILE` | no | OAuth persistence file (clients + tokens). Typically `.oauth-state.json` in the working directory |
| `SILPO_MCP_SESSION_FILE` | no | Session persistence file (address, `basketId`, token, and cabinet cookie). Typically `session.json` next to `SILPO_MCP_STATE_FILE` |
| `SILPO_OAUTH_CLIENT_ID` / `SILPO_OAUTH_CLIENT_SECRET` | no | Pre-registered client (for fields in Claude) |
| `SILPO_OAUTH_REDIRECT_URIS` | no | Allowed redirect_uri of the static client (comma-separated) |
> **Persistence.** In remote mode, both OAuth tokens and session state
> are stored on disk (files with `0600` permissions), so restart/deployment/reboot
> **do not** require re-authorization in Claude and do not lose address/cart.
> The cabinet token **and cookie** of Сільпо also fall into `SILPO_MCP_SESSION_FILE`
> - keep the file private (the cookie allows updating the token on behalf of the account).
### HTTPS is mandatory
Claude requires **https** with a valid certificate and domain name - a "bare" IP will not work.
Run the server behind a reverse proxy, e.g., Caddy (automatic Let's Encrypt):
```
silpo.example.com {
reverse_proxy localhost:3000
}
```
### Connection in Claude
1. Deploy the server behind an HTTPS domain.
2. In Claude → "Add custom connector" specify **Server URL**: `https://silpo.example.com/mcp`.
3. **Leave Client ID/Secret empty** - the server supports Dynamic Client
Registration, so Claude will register itself. (Or set `SILPO_OAUTH_CLIENT_*`
and enter them in these fields.)
4. During connection, Claude will open the login page - enter `SILPO_MCP_PASSWORD`.
5. Done: all tools are available. The session state (address, cart) is shared with the server.
### Endpoints
- `POST/GET/DELETE /mcp` — MCP Streamable-HTTP transport (protected by Bearer token)
- `/.well-known/oauth-protected-resource/mcp`, `/.well-known/oauth-authorization-server` — metadata
- `/authorize`, `/token`, `/register`, `/revoke` — standard OAuth endpoints
- `/login` — password login page
## Quick Start
Before searching for products, set the delivery address - it determines the nearest store:
```
"Set delivery address: Lviv, Striyiska street, 45A"
"Do you deliver to coordinates 49.8030, 24.0196?"
"Find milk"
"Show promotions"
"When can I order delivery?"
```
For personal functions (order history, bonuses), authorization is required. There are two ways:
- **Cookie (recommended)** — `set_auth_cookie` saves the session cookie
`.AspNetCore.Identity.Application` (auth.silpo.ua), and the server **itself updates**
the cabinet token when it expires (every ~24 hours), without manual intervention.
- **Token** — `set_auth_token` accepts a one-time Bearer token (lives ~24 hours, then
you need to insert a new one manually).
```
"My cart: fadff098-d1ed-47dd-a312-5cdd11a54a67"
"Silpo authorization cookie: CfDJ8PokYHNhxS1Nmvi…"
"Token from Silpo cabinet: eyJhbGciOiJSUzI1NiIs…"
```
**Where to get the cookie:** DevTools → Application → Cookies → `https://auth.silpo.ua`
→ value `.AspNetCore.Identity.Application`. **Token:** network request to
`sf-ecom-api.silpo.ua` with the header `authorization: Bearer …`.
## Available Tools
### Session Settings
| Tool | Description |
| --- | --- |
| `set_delivery_address` | Set delivery address (text or coordinates) |
| `get_current_address` | Current address and store |
| `set_auth_cookie` | Session cookie for auto-renewal of cabinet token (recommended) |
| `set_auth_token` | One-time cabinet authorization token (without auto-renewal) |
| `set_basket_id` | Connect existing Silpo cart |
| `get_session_info` | State of the current session |
### Products and Search
| Tool | Description |
| --- | --- |
| `search_products` | Product search by query |
| `get_categories` | List of categories |
| `get_category_products` | Products in a category (sorting, pagination) |
| `get_promotions` | Products with discounts |
| `get_product` | Product details by slug |
| `get_product_images` | Product images by slug - returns images themselves (not links) |
### Delivery
| Tool | Description |
| --- | --- |
| `check_delivery_zone` | Is the coordinate in the delivery zone? |
| `get_delivery_modes` | All delivery types by coordinates |
| `get_time_slots` | Available delivery slots |
| `set_delivery_slot` / `get_delivery_slot` | Selected delivery time |
### Cart (real Silpo cart)
`add_to_cart`, `get_cart`, `update_cart_item`, `remove_from_cart`, `clear_cart`, `create_cart`, `add_item_comment`
The cart lives on the Silpo server - this is the same cart as seen on the website/application.
It is created **automatically** when `add_to_cart` for the first time (you need to have a set delivery address);
`create_cart` exists for explicit creation of a new cart. Products are identified by **productId**
(uuid of the product - take it from `search_products`/`get_product`). `update_cart_item` with `quantity: 0`
(or `remove_from_cart`) removes the product. Authorization is not required - the cart is determined only by `basketId`;
the token can be passed optionally.
### Shopping List
`add_to_shopping_list`, `get_shopping_list`, `remove_from_shopping_list`, `clear_shopping_list`, `set_shopping_list_item_checked`, `shopping_list_to_cart`
The shopping list is a lightweight draft list (name + quantity) that lives in the server session and does not touch the Silpo API.
`shopping_list_to_cart` finds each item in the catalog (by slug or name) and adds it to the Silpo cart.
### Cabinet (requires authorization)
`get_orders_history`, `get_order_products`, `get_loyalty_balance`, `silpo_suggest_from_history`
`get_orders_history` returns a list of orders (number, status, amount, date, address).
`get_order_products` returns **items** of a specific order (by number or from the last one):
name, quantity, amount, `productId` (to add back to cart), replacement/deletion marks.
A token is required (`set_auth_token`) or, better, a cookie (`set_auth_cookie`) - with the cookie, the token is updated automatically when it expires.
If 401, the server makes one attempt to update the token and repeat the request.
## Limitations
- In stdio mode, the session (address, `basketId`, shopping list) lives only in memory (not saved between runs). In remote mode, the state is persisted in `SILPO_MCP_SESSION_FILE` and survives restarts.
- The cart is synchronized with Silpo, but order checkout requires authorization on the website.
- **Carts are ephemeral** — Silpo removes them after some inactivity; then `get_cart` returns 404, and the next `add_to_cart` creates a new one.
- Creating a cart requires a chosen delivery slot (chosen automatically if not set) and **is rate-limited** (HTTP 429). If you already have a `basketId` — use `set_basket_id`.
- Cart changes are applied asynchronously (server responds 202), so the server does a repeated `GET` to show the current state.
- `set_delivery_address` accepts coordinates (recommended) or text. Text is geocoded through OpenStreetMap Nominatim, since Silpo's own autocomplete is not yet restored.
- **The cabinet token lives ~24 hours.** With `set_auth_cookie` it is updated automatically (silent OIDC flow through session cookie); without cookie after expiration, you need to insert a new token manually. If the cookie stops working — insert a new one.
- **Temporarily disabled** (commented out in `src/index.ts` until restoration of real endpoints): `search_address` (separate address search) and recipes `search_recipes` / `get_recipe_filters`.
- The API has been updated using reverse engineering and may change; individual operations may be blocked by Cloudflare.
## Development
```bash
npm run dev # watch build
npm run build # build
npm start # start the built server
```
## Structure
```
silpo-mcp/
├── src/
│ ├── index.ts # buildServer() + all MCP tools, stdio mode
│ ├── http.ts # Remote HTTP mode (Streamable HTTP + OAuth)
│ ├── oauth.ts # OAuth 2.1 authorization server (password gate, DCR)
│ ├── silpo-api.ts # HTTP client for Silpo API
│ ├── silpo-auth.ts # Automatic cabinet token renewal (PKCE prompt=none via cookie)
│ └── session.ts # Session state, shopping list
├── .env.example # Variables for remote mode
├── dist/
├── package.json
└── tsconfig.json
```
MCP Config
Below is the configuration for this MCP Server. You can copy it directly to Cursor or other MCP clients.
mcp.json
Connection Info
You Might Also Like
No recommendations available