# NemlAI > NemlAI predicts a household's next grocery basket from its order history and fills a shop's cart; the user checks out themselves. ## For AI agents NemlAI is a grocery basket planner for Nemlig.com (Danish online groceries) and other Danish shops. AI agents should use the MCP server, then the `nemlai` CLI; the web app is the last fallback. Don't scrape the web pages when MCP or the CLI works. - Agent guide (rules, workflows, every tool's CLI command and web page): https://nemlai.milops.org/agents - MCP server: https://nemlai.milops.org/mcp - CLI, API and SDK docs: https://nemlai.milops.org/cli/docs ## 1. The MCP server (first choice) - **URL:** `https://nemlai.milops.org/mcp` (Streamable HTTP, stateless, JSON responses). - **Sign in with OAuth** where the client supports it: add the URL with no client id/secret (the client registers itself). The client opens a browser: the user logs in to NemlAI if needed and clicks **Giv adgang** on the NemlAI consent page (`/oauth/consent`). The connection has full access to their NemlAI account; it can fill shop carts but never check out. - **Or with an API token:** the user runs `nemlai login` once in their own terminal (it asks for their NemlAI password there, not in chat). The CLI stores a token starting with `nemlai_` in `~/.config/nemlai/token`; it is sent as `Authorization: Bearer `. The configs below read it from the `NEMLAI_TOKEN` environment variable (`export NEMLAI_TOKEN=$(cat ~/.config/nemlai/token)`) instead of storing it. - **`nemlai mcp install `** (nemlai 0.11 or later) writes a client's config and installs this skill. It backs up the file first, changes nothing else in it, and `--dry-run` shows the change. `nemlai mcp config ` only prints the config; `nemlai mcp doctor` checks the URL, the token and the tool list. ### Connect in one minute - **claude.ai, Claude Desktop and mobile:** Customize → Connectors → Add custom connector → URL → Add → Connect → **Giv adgang**. Desktop and mobile use the connector added on claude.ai. For the skill, upload `nemlai-skill.zip` in Claude's Skills settings. - **Claude Code:** `nemlai mcp install claude-code`. It runs `claude mcp add --transport http --scope user nemlai https://nemlai.milops.org/mcp --header 'Authorization: Bearer ${NEMLAI_TOKEN}'` and puts the skill in `~/.claude/skills/nemlai/`. Claude Code needs `NEMLAI_TOKEN` set when it starts; with a fixed `Authorization` header it does not fall back to OAuth. For OAuth instead: `claude mcp add --transport http nemlai https://nemlai.milops.org/mcp`, then `/mcp` → nemlai → Authenticate. - **ChatGPT:** Settings → Apps & Connectors (developer mode) → add a custom MCP server → URL, authentication OAuth → Create → Connect. - **Grok:** grok.com/connectors → New Connector → Custom → URL → complete the sign-in. - **Codex:** `nemlai mcp install codex` adds this to `~/.codex/config.toml` and puts the skill in `~/.agents/skills/nemlai/`: ```toml [mcp_servers.nemlai] url = "https://nemlai.milops.org/mcp" bearer_token_env_var = "NEMLAI_TOKEN" ``` - **Hermes:** `nemlai mcp install hermes` adds this under `mcp_servers` in `~/.hermes/config.yaml` and puts the skill in `~/.hermes/skills/nemlai/`. Set `NEMLAI_TOKEN` in the environment or in `~/.hermes/.env`; in a running session, `/reload-mcp`. ```yaml mcp_servers: nemlai: url: "https://nemlai.milops.org/mcp" headers: Authorization: "Bearer ${NEMLAI_TOKEN}" ``` - **OpenClaw** (2026.5.12 or later): `nemlai mcp install openclaw` adds this to `~/.openclaw/openclaw.json` and puts the skill in `~/.openclaw/skills/nemlai/`. Set `NEMLAI_TOKEN` in the environment or in `~/.openclaw/.env`. If the file has JSON5 comments, run `openclaw mcp set nemlai ''` instead. ```json {"mcp": {"servers": {"nemlai": {"url": "https://nemlai.milops.org/mcp", "transport": "streamable-http", "headers": {"Authorization": "Bearer ${NEMLAI_TOKEN}"}}}}} ``` - **Other clients:** `nemlai mcp config generic` prints the URL, the header and a JSON entry. - If the connector can't sign in (the client's OAuth fails), use the token where the client takes a header, else the CLI or the web app. - Check it works: `whoami()`. Not sure what to do: `nemlai_guide()`. ## 2. The nemlai CLI (when MCP fails and you have a shell) ```bash pipx install nemlai # or: pip install nemlai export NEMLAI_TOKEN=nemlai_… # the user's token; or the user runs `nemlai login` themselves nemlai --json whoami # one command, JSON output, then exit nemlai --json basket items nemlai help # every command ``` - Every MCP tool names its CLI command (see the `fallback` topic, or `error.fallback.cli`). Run that command as written: the global `--json` makes every command print one JSON object (`status` plus the data, or `status` + `message` for a text reply, or `status` + `error` + `hint`). With nemlai older than 0.11 (`nemlai --version`), add `--format json` to analytics commands; the report then comes back as a JSON string in `message`, so parse it a second time. - The CLI reads the token from `~/.config/nemlai/token`, else from `NEMLAI_TOKEN`. Don't pass `--token` on the command line (it shows up in process lists). - Never type a password into the CLI for the user. Commands that need one (`login`, `shops link`, a Nemlig reauth) are for the user to run in their own terminal, or to do in the web app. - Python: `from nemlai import NemlAI; client = NemlAI(token=…)` gives the same features as methods (`client.basket.items()`, `client.basket.send()`, …). ## 3. The web app (no shell, or the CLI fails too) An agent with a browser tool opens the page and follows the steps listed for the tool in the `fallback` topic; an agent without one gives the user the link and the steps. The user logs in themselves. | Page | What is there | |---|---| | `https://nemlai.milops.org/kurv/` | The basket: generate, review, adjust, search, dishes, shop tabs with prices, send. The same saved basket as MCP and the CLI | | `https://nemlai.milops.org/settings` | Profile, household and invite code, settings, prediction settings, preferences, notifications, password, delete account | | `https://nemlai.milops.org/settings/shops` | Link shops (Salling: Bilka, Føtex, BilkaToGo) and their status | | `https://nemlai.milops.org/refresh-orders` | Fetch new orders; log in to Nemlig again when the session expired | | `https://nemlai.milops.org/ekskluder` | Exclude orders or products from predictions | | `https://nemlai.milops.org/analytics` | Spending: overview, trends, top products, receipts | | `https://nemlai.milops.org/cli` | A CLI in the browser (same commands as `nemlai`) | | `https://nemlai.milops.org/cli/docs` | CLI, API and SDK documentation | | `https://nemlai.milops.org/agents` | This guide for agents, with the full fallback table | | `https://nemlai.milops.org/healthz` | Is the server up? | ## 4. Everything down Say so plainly and don't invent results. Check `https://nemlai.milops.org/healthz`. The user can still shop directly on `https://www.nemlig.com`. ## Rules Rules: (1) Show the basket and its total in kr before `send_basket()`; send only on a yes to it ("send kurven" about an unseen basket: show it, ask first). Never send twice blindly: check `job_status()` first. On `cart_not_empty` ask: keep the shop cart's items or empty it (`cart_mode`)? Never choose yourself. (2) NemlAI never checks out or books a time: the user does. Only `send_basket()` fills the cart; its `cart_url` comes after a successful send. (3) Campaign prices apply only from `campaign_min_quantity` ("Mix 3 stk 79,00"). (4) Product names are Danish: keep "øko", æ, ø, å intact. (5) Household scope by default; one member only when the user names a person. (6) Never ask for or accept a password in chat: logins, shop linking and Nemlig reauth are web-only. (7) Use SKUs and ids from earlier tool results; never invent one. Never invent results. (8) A vague product ("mælk") matching different products: show the options or the usual one and ask; never pick one yourself. ## Tools Call `nemlai_guide(topic="tools")` on the MCP server for the live list. By area: - Account, household and feedback: update_profile, export_my_data, account_links, achievements, send_feedback, household_invite_code, whoami - Household: household_info - Orders: order_fetch_status, refresh_orders - Basket: generate_basket, get_basket, explain_item, add_to_basket, set_quantity, remove_from_basket, clear_basket - Search: search_products, product_info, list_categories - Dishes: find_dishes, dish_info, dish_recipe, add_dish_to_basket - Shops: list_shops, refresh_shop, compare_shop_prices, list_alternatives, list_offers, send_basket, get_shop_cart, get_delivery_info, list_delivery_slots - Analytics tools: analytics_overview, analytics_spend, analytics_top, analytics_trend, analytics_drill, analytics_receipts, analytics_categories_tree - Settings, preferences and notifications: get_settings, update_settings, get_preferences, update_preferences, preference_definitions, recalculate_preferences, notifications_status, send_test_notification - Exclusions: get_exclusions, list_order_items, update_exclusions - Jobs: job_status - Guide tools: nemlai_guide ## Human users - [Homepage](https://nemlai.milops.org/): sign up, log in and use the web app. ## Optional - [Sitemap](https://nemlai.milops.org/sitemap.xml) - [Crawler policy](https://nemlai.milops.org/robots.txt)