npm package: @iflow-mcp/markusl-alko-mcp
Description: MCP server for querying Alko.fi alcohol product catalog
Latest version: 1.0.0

# Alko MCP Server

A production-grade [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) server that provides AI assistants with access to the [Alko.fi](https://www.alko.fi/) alcohol product catalog.

## Features

- **Product Search**: Search 11,900+ products by name, type, country, price range, alcohol %, and more
- **Product Details**: Get detailed information including enriched data (taste profile, food pairings, certificates, serving suggestions)
- **Vivino Ratings**: Get wine ratings from Vivino.com by name or URL
- **Store Hours**: Check store opening hours with "open now" filtering
- **Store Availability**: Check real-time stock availability at Alko stores (via web scraping)
- **Recommendations**: Get product recommendations based on food pairings, occasions, and preferences
- **Store Listing**: Browse 360+ Alko stores by city

All tools return **compact JSON** for efficient LLM token usage.

## Demo

<video src="https://github.com/user-attachments/assets/ca9535c2-b3e4-44da-b509-5f55793b9d4a" controls width="100%"></video>

*Claude Desktop using Alko MCP to search products, check availability, and get recommendations.*

## MCP Tools

| Tool | Description |
|------|-------------|
| `search_products` | Search products by name, type, country, price range, alcohol % |
| `get_product` | Get product details. Set `includeEnrichedData=true` for taste, food pairings, serving tips |
| `get_store_hours` | Get store opening hours. Filter by city, name, or `openNow=true`. Auto-refreshes if stale |
| `get_availability` | Check store stock for a product (scrapes alko.fi) |
| `list_stores` | List Alko stores by city |
| `get_recommendations` | Get personalized product recommendations |
| `get_vivino_rating` | Get Vivino wine rating by name or URL (scrapes vivino.com) |
| `sync_products` | Sync database with latest Alko price list |
| `get_sync_status` | Check sync status and product count |

## Quick Start

### Prerequisites

- Node.js 24+
- Google Cloud Firestore (or emulator for local dev)
- Playwright (auto-installed for web scraping)

### Installation

```bash
# Clone the repository
git clone https://github.com/yourusername/alko-mcp.git
cd alko-mcp

# Install dependencies
npm install

# Install Playwright browsers
npx playwright install chromium

# Build
npm run build
```

### Local Development with Firestore Emulator

**Step 1: Start Firestore Emulator** (keep running in background)
```bash
gcloud emulators firestore start --host-port=localhost:8081
```

**Step 2: Start Claude Desktop** (or other AI assistant)

The MCP server will automatically load bundled seed data (~12,000 products, ~360 stores) on first query if the emulator is empty. No manual sync required!

> **Note**: The emulator doesn't persist data. After restarting the emulator, seed data will be auto-loaded again on first use.

#### Optional: Fresh Data Sync

If you need the latest product data from Alko.fi:

```bash
export FIRESTORE_EMULATOR_HOST=localhost:8081

# Sync fresh products from Excel (~30 seconds)
npm run sync-data

# Sync fresh stores from website (~2 minutes)
npm run sync-stores

# Export to seed file (for sharing with team)
npm run export-seed
```

## AI Assistant Configuration

### Claude Desktop

Config file: `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS)

**Local development:**
```json
{
  "mcpServers": {
    "alko": {
      "command": "node",
      "args": ["/absolute/path/to/alko-mcp/dist/server.js"],
      "env": {
        "FIRESTORE_EMULATOR_HOST": "localhost:8081"
      }
    }
  }
}
```

**Production (Cloud Run):**
```json
{
  "mcpServers": {
    "alko": {
      "url": "https://YOUR-CLOUD-RUN-URL.run.app/mcp",
      "transport": "streamable-http"
    }
  }
}
```

### ChatGPT Desktop

Config file: `~/.config/chatgpt/mcp.json` (macOS/Linux) or `%APPDATA%\chatgpt\mcp.json` (Windows)

**Local development:**
```json
{
  "servers": {
    "alko": {
      "command": "node",
      "args": ["/absolute/path/to/alko-mcp/dist/server.js"],
      "env": {
        "FIRESTORE_EMULATOR_HOST": "localhost:8081"
      }
    }
  }
}
```

**Production (Cloud Run):**
```json
{
  "servers": {
    "alko": {
      "url": "https://YOUR-CLOUD-RUN-URL.run.app/mcp",
      "transport": "streamable-http"
    }
  }
}
```

### Google Gemini (AI Studio)

For Gemini, use HTTP transport. Start the server with:

```bash
MCP_TRANSPORT=http PORT=3000 node dist/server.js
```

Then configure in AI Studio with the MCP endpoint URL:
```
http://localhost:3000/mcp
```

For production, deploy to Cloud Run with API token authentication (see below).

### Claude Code CLI

Add to your project's `.mcp.json`:

```json
{
  "mcpServers": {
    "alko": {
      "command": "node",
      "args": ["./dist/server.js"],
      "env": {
        "FIRESTORE_EMULATOR_HOST": "localhost:8081"
      }
    }
  }
}
```

## Example Prompts

### 🔍 Basic Search
> **Etsi minulle hyviä italialaisia punaviinejä alle 20 euroa**
>
> *Searches for Italian red wines under €20*

### 🍷 Wine Recommendations
> **Suosittele viiniä grillatulle lohelle. Budjetti noin 15-25 euroa.**
>
> *Recommends wine for grilled salmon within budget*

### 🥂 Champagne & Sparkling
> **Mitä samppanjoita Alkossa on saatavilla? Näytä 5 parasta vaihtoehtoa.**
>
> *Lists champagne options*

### 🍺 Craft Beer Search
> **Etsi IPA-oluita Suomesta tai muista Pohjoismaista**
>
> *Searches for Nordic IPA beers*

### 📊 Product Details
> **Kerro lisää tuotteesta numero 906458**
>
> *Gets detailed product information with taste profile*

### 🏪 Store Hours
> **Mitkä Alkon myymälät ovat auki nyt Helsingissä?**
>
> *Lists Helsinki stores that are open now*

### 📍 Store Availability
> **Onko Barolo-viiniä saatavilla Helsingin myymälöissä?**
>
> *Checks product availability in Helsinki stores*

### 🎁 Gift Recommendations
> **Etsi lahjaideoita viininystävälle. Budjetti 50-100 euroa.**
>
> *Premium gift ideas for wine lovers*

### 🧀 Food Pairing (uses Alko's official pairing data)
> **Suosittele viiniä äyriäisille** / **Recommend wine for seafood**
>
> *Uses Alko's food symbol search to find products officially tagged for seafood pairing*

> **Tarvitsen viinin juustolautaselle. Juustot: brie, manchego ja sinihomejuusto.**
>
> *Wine for cheese platter - matches "miedot juustot" and "voimakkaat juustot"*

### 🌍 Region-specific Search
> **Hae espanjalaisia punaviinejä Rioja-alueelta**
>
> *Spanish wines from Rioja region*

### 💰 Budget Shopping
> **Parhaat viinit alle 10 eurolla arki-iltoihin**
>
> *Best budget wines for weeknight dinners*

### 🍾 Special Occasions
> **Suosittele kuohuviiniä uudenvuoden juhliin 20 hengelle**
>
> *Sparkling wine for New Year's party*

### ⭐ Vivino Ratings
> **Etsi punaviinejä 15-25€ ja tarkista niiden Vivino-arvostelut**
>
> *Searches for red wines and checks their Vivino ratings*

### 🏆 Best Rated Wines
> **Mikä on Alkon parhaiten arvioitu Barolo Vivinossa?**
>
> *Finds Barolo wines and compares their Vivino ratings*

### 📈 Wine Comparison
> **Vertaile näiden viinien Vivino-arvosanoja: Amarone, Brunello di Montalcino**
>
> *Compares Vivino ratings for premium Italian wines*

## Data Sources

### Product Catalog
- **Source**: Alko's public Excel price list
- **URL**: `https://www.alko.fi/INTERSHOP/static/WFS/Alko-OnlineShop-Site/-/Alko-OnlineShop/fi_FI/Alkon%20Hinnasto%20Tekstitiedostona/alkon-hinnasto-tekstitiedostona.xlsx`
- **Products**: ~11,900
- **Update**: Run `npm run sync-data`

### Store Data
- **Source**: Scraped from alko.fi store finder
- **Stores**: ~360
- **Includes**: Name, address, opening hours (today/tomorrow)
- **Update**: Run `npm run sync-stores`

### Enriched Product Data
- **Source**: Scraped from individual product pages
- **Includes**: Taste profile, usage tips, serving suggestions, food pairings, certificates, ingredients
- **Cached**: Persisted to Firestore after first scrape

## Product Fields

| Field | Description |
|-------|-------------|
| `id` | Product ID (e.g., "004246") |
| `name` | Product name |
| `producer` | Producer/manufacturer |
| `price` | Price in EUR |
| `pricePerLiter` | Price per liter |
| `bottleSize` | Volume (e.g., "0.75 l") |
| `type` | Category (punaviinit, valkoviinit, oluet, etc.) |
| `subtype` | Flavor profile (e.g., "Mehevä & Hilloinen") |
| `country` | Country of origin |
| `region` | Wine region |
| `alcoholPercentage` | Alcohol % |
| `description` | Taste description from Excel |
| `tasteProfile` | Detailed taste (enriched, scraped) |
| `usageTips` | Usage suggestions (enriched) |
| `servingSuggestion` | Serving temperature (enriched) |
| `foodPairings` | Food pairing symbols (enriched) |
| `certificates` | Certification labels: Luomu, Vegaani, etc. (enriched) |
| `ingredients` | Producer declared ingredients (enriched) |
| `assortment` | vakiovalikoima, tilausvalikoima, etc. |

## Development

```bash
npm run build        # Compile TypeScript
npm run dev          # Run with tsx watch mode
npm run test         # Run tests in watch mode
npm run test:run     # Run tests once (232 tests)
npm run typecheck    # Type check
npm run sync-data    # Sync products from Excel
npm run sync-stores  # Scrape stores from website
npm run export-seed  # Export data to seed file (with diff)
```

### Logs

```bash
tail -f /tmp/alko-mcp.log
```

## Deployment to Google Cloud Run

The server can be deployed to Cloud Run with public access (no authentication) for compatibility with ChatGPT and other MCP clients.

```bash
# Enable APIs
gcloud services enable run.googleapis.com firestore.googleapis.com artifactregistry.googleapis.com cloudbuild.googleapis.com

# Create Firestore database
gcloud firestore databases create --location=europe-north1

# Deploy using Cloud Build
gcloud builds submit --config=cloudbuild.yaml

# Or deploy directly from source
gcloud run deploy alko-mcp \
  --source . \
  --region europe-north1 \
  --memory 2Gi \
  --cpu 2 \
  --execution-environment gen2 \
  --set-env-vars="MCP_TRANSPORT=http" \
  --allow-unauthenticated
```

**Test the endpoint:**
```bash
curl -X POST https://alko-mcp-xxx.a.run.app/mcp \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
```

See [DEPLOYMENT.md](DEPLOYMENT.md) for API token authentication and other options.

## Legal Disclaimer

- The Alko price list is publicly available data
- Web scraping respects rate limits (2s between requests)
- This is an unofficial project not affiliated with Alko Oy
- Alcohol products can only be purchased by persons 18+ in Finland

## License

MIT License