Skip to main content
Glama
irony

webhallen-mcp

by irony
README.md
# webhallen-mcp

MCP server for interacting with Webhallen. Search products and manage shared wishlists (önskelistor) — designed for a shared office shopping list.

Uses pure HTTP calls (no browser dependency), so it works from background agents.

## Tools

| Tool | Auth required | Description |
|------|:---:|-------------|
| `login` | - | Log in with username/password |
| `search_products` | - | Search products by keyword (returns IDs, names, prices, stock) |
| `get_product` | - | Get details for a specific product by ID |
| `list_wishlists` | ✓ | List all your wishlists and their contents |
| `get_wishlist` | ✓ | Get contents of a specific wishlist |
| `create_wishlist` | ✓ | Create a new wishlist (e.g. "Kontoret Inköpslista") |
| `add_to_wishlist` | ✓ | Add a product to a wishlist |
| `delete_wishlist` | ✓ | Delete a wishlist |

## Authentication

Two options:

### Option A: Environment variables (recommended for background agents)

Set `WEBHALLEN_USERNAME` and `WEBHALLEN_PASSWORD`. The server logs in automatically on first authenticated request.

### Option B: Login tool

Call the `login` tool with username and password. The session is kept in memory for the server's lifetime.

### Option C: Existing session cookie

Set `WEBHALLEN_COOKIES` with a `webhallen_session=...` cookie value extracted from a browser session. Use this if you already have a valid session and want to avoid sending credentials.

Search works without authentication. Wishlist operations require it.

## Installation

### Build

```bash
cd webhallen-mcp
npm install
npm run build
```

### Configure in opencode

Add to your `opencode.json`:

```json
{
  "mcp": {
    "webhallen": {
      "command": "node",
      "args": ["/path/to/webhallen-mcp/dist/index.js"],
      "env": {
        "WEBHALLEN_USERNAME": "your_username",
        "WEBHALLEN_PASSWORD": "your_password"
      }
    }
  }
}
```

## API endpoints used

| Endpoint | Method | Auth | Purpose |
|----------|--------|:---:|---------|
| `/api/login` | POST | - | Authenticate with username/password |
| `/api/me` | GET | ✓ | Current user info |
| `/api/productdiscovery/autocomplete/{query}` | GET | - | Product search |
| `/api/productdiscovery/category/{id}` | GET | - | Browse by category |
| `/api/wishlist` | GET | ✓ | List all wishlists |
| `/api/wishlist` | POST | ✓ | Create wishlist |
| `/api/wishlist/{id}` | PUT | ✓ | Add product to wishlist |
| `/api/wishlist/{id}` | DELETE | ✓ | Delete wishlist |

## Usage examples

Ask the agent:
- "Sök efter Nintendo Switch 2 på Webhallen"
- "Skapa en önskelista som heter Kontoret Inköpslista"
- "Lägg till produkt 378404 i önskelistan"
- "Visa alla önskelistor"

TDQS

A3.8/5.0

Scored across 8 tools

Disambiguation4/5

Most tools are clearly separated by resource and action: product search/detail, wishlist lifecycle, and auth. The only real ambiguity is list_wishlists versus get_wishlist, since both return wishlist contents, though one is all lists and the other is a specific list; the descriptions mostly clarify this.

Naming Consistency4/5

All tool names use lowercase snake_case with a verb-first style. Product and wishlist CRUD tools follow a verb_noun pattern, while login and add_to_wishlist are minor deviations but still clear and predictable.

Tool Count5/5

8 tools is well-scoped for a Webhallen wishlist integration: auth, product lookup, and wishlist CRUD each have a clear place. There is no unnecessary duplication or bloat.

Completeness3/5

The surface covers login, product search/detail, and create/get/list/delete wishlists, with add_to_wishlist for populating a list. However, there is no remove_from_wishlist or update wishlist metadata, so agents cannot correct mistakes or rename lists—a notable lifecycle gap.

Maintenance

ActivityMaintained
ResponsivenessNo issues