webhallen-mcp
# 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
Scored across 8 tools
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.
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.
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.
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.