nemlig-mcp
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@nemlig-mcpfind oat milk"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
nemlig-mcp
Unofficial local MCP for nemlig.com, danish delivery service
Built as a thin layer over nemlig_cli,
which already solves the hard parts: the three-step XSRF/bearer/login flow, the
cookie-backed session, the two different API hosts, and the GetAsJson
endpoints. This package adds a token-refresh loop, a privacy filter, and a
curated tool surface.
Tools
Tool | Writes? | Description |
| no | Search the catalogue |
| no | Nutrition, allergens, attributes |
| no | Current basket contents |
| yes | Set units of a product in the basket (0 removes it) |
| yes | Same, for a list of products, applied one by one with retries |
| no | Previous orders |
| no | Line items of one past order |
Related MCP server: MCP Picnic
What this server deliberately cannot do
It cannot place an order or read your payment cards. Nemlig's API exposes
POST /webapi/Order/PlaceOrderLoggedIn (which charges a saved card) and
GET /webapi/Checkout/GetCreditCards. nemlig_cli implements neither, and this
server does not add them.
The tool surface is an allowlist, not a filtered view of the whole API, so an
endpoint cannot become reachable by accident. A test asserts this
(tests/test_server.py). The two set_basket_quantit*
tools are the only ones that change state, and every change they make is
reversible on the website.
Both are annotated destructive_hint=True, because their quantity is absolute
rather than a delta: lowering it discards units already in the basket, and 0
removes the line. Clients use that hint to decide whether to confirm with the
user, so understating it would be the dangerous direction to be wrong in.
Batching
set_basket_quantities takes a list of {product_id, quantity} and applies it
sequentially, so filling a basket from a recipe or a past order is one tool call
rather than fifteen. A failing item is retried up to three times with a growing
backoff, but only for failures another attempt could actually fix — a timeout, a
429 or a 5xx. A request nemlig rejected outright is not retried, because it
would be rejected again and only delay the rest of the batch.
A failing item is recorded and skipped rather than aborting the run: the basket
has already been half-changed by that point, so the useful thing to return is
what happened to every item plus the resulting basket. The tool reports both,
and reports the basket as null with a basket_error if even the final read
fails, rather than throwing away the per-item results.
Because quantities are absolute, a product may appear only once in the list; two lines for one product would silently mean "last one wins" rather than the sum a caller likely intended, so that is rejected up front.
Privacy
Basket and order responses embed the account holder's name, street address and
phone number. Everything a tool returns lands in the model's context and in the
conversation transcript, so those fields are replaced with a marker before they
leave the server. See privacy.py.
Setup
1. Install
git clone https://github.com/kraenhansen/nemlig-mcp.git
cd nemlig-mcp
uv syncRequires uv and Python 3.11+. nemlig_cli is
pulled from git automatically — no separate checkout needed.
2. Provide credentials
Two options. Prefer the config file — an MCP config with a password in it is easy to commit by accident.
mkdir -p ~/.config/nemlig
cat > ~/.config/nemlig/login.json <<'EOF'
{"username": "you@example.com", "password": "your-password"}
EOF
chmod 600 ~/.config/nemlig/login.jsonThis is the same file the CLI uses, so both share one login. Alternatively set
NEMLIG_USER / NEMLIG_PASS in the environment, which takes precedence.
3. Register the server
claude mcp add nemlig -- uv --directory ~/code/nemlig-mcp run nemlig-mcpOr add it to .mcp.json (project-local) or ~/.claude.json (global). Use an
absolute path — ~ is not expanded inside args:
{
"mcpServers": {
"nemlig": {
"command": "uv",
"args": ["--directory", "/Users/you/code/nemlig-mcp", "run", "nemlig-mcp"]
}
}
}If you would rather not use the config file, add credentials here instead — and make sure the file is gitignored:
"env": { "NEMLIG_USER": "you@example.com", "NEMLIG_PASS": "..." }4. Verify
uv run pytest # 20 tests, no network, no credentials
uv run python tests/smoke_stdio.py # spawns the server, lists its toolsThen ask Claude something like "search nemlig for kaffebønner". The first call logs in, which takes a second or two; tokens are cached for 240s after that.
Troubleshooting:
Symptom | Cause |
| Step 2 not done, or the config file is not valid JSON |
|
|
Tool calls fail with | Wrong username/password — nemlig returns 401 from the login endpoint |
Relationship to the upstream CLI
Building this surfaced two problems in nemlig_cli, both fixed upstream in
eisbaw/nemlig_cli#3:
login()could hang forever. The progress spinner was started before the request sequence but only stopped on the success path, on a non-daemon thread — so a wrong password left the process spinning instead of raising.Progress was written to stdout, which on a stdio MCP server is the JSON-RPC transport. It now renders to stderr, and only when stderr is a tty.
Because of that fix, nemlig-cli is pinned to a commit that includes it. The
quiet() wrapper in _compat.py is kept anyway:
a single stray print() anywhere in a dependency would corrupt the protocol
stream, and that is cheap insurance against a failure mode this severe.
Development
uv run pytest # 20 tests, no network, no credentials
uv run python tests/smoke_stdio.py # end-to-end over stdioTo work against a local checkout of the CLI, uncomment the [tool.uv.sources]
block in pyproject.toml and clone nemlig_cli as a sibling directory.
Disclaimer
Not affiliated with nemlig.com. Uses a private API that may change or break, and automated access may conflict with their terms of service.
License
MIT
Available Tools
6 toolsget_basketARead-only
Show the current shopping basket with line items and prices.
Delivery and invoice addresses are redacted.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the readOnlyHint annotation, the description adds a valuable behavioral detail: delivery and invoice addresses are redacted. This is additional context not present in annotations or schema, and it does not contradict any annotation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two concise sentences: the first clearly states the tool's purpose, the second adds a key behavioral caveat. Every word earns its place, and the most important information is front-loaded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
This is a simple, no-parameter, read-only tool with an output schema. The description covers the essential purpose and discloses the redaction behavior, which is sufficient for an agent to invoke it correctly without further elaboration.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool has zero parameters, so the schema provides complete coverage (100% by vacuity). The description has no need to explain parameter semantics, and the baseline of 4 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb 'Show' on a specific resource 'current shopping basket' and details the included content (line items and prices). It clearly distinguishes this from sibling tools such as get_order_details (orders vs. basket) and set_basket_quantity (mutation).
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies usage for viewing the user's current basket but does not explicitly state when to use this tool over alternatives or note exclusions. No external comparison is provided, leaving the agent to infer the tool's role purely from its name and context.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_order_detailsARead-only
Fetch the line items of one past order.
Args: order_id: Numeric order Id from get_order_history (not OrderNumber).
| Name | Required | Description | Default |
|---|---|---|---|
| order_id | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, and the description adds the 'past order' scope, clarifying this is not a current-basket operation. The note about using the numeric ID from get_order_history (not OrderNumber) provides practical behavioral context beyond the schema.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences plus a single-argument doc; every sentence earns its place. No redundancy or filler, with the key purpose stated first.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a one-parameter read-only tool with an output schema, the description covers everything needed: purpose, input source, and the ID type. Return values are covered by the output schema, so no additional explanation is required.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
With 0% schema description coverage, the description fully compensates: it explains that order_id is the numeric internal ID (not OrderNumber) from get_order_history. This is crucial for correct invocation and adds meaning the schema alone lacks.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Description opens with 'Fetch the line items of one past order' – a specific verb ('fetch'), specific resource ('line items of one past order'), and clearly differentiates from siblings like get_order_history (which lists orders) and get_basket (current cart).
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
States that order_id must be the numeric ID from get_order_history, explicitly excluding OrderNumber. This implies the workflow: call get_order_history first, then use the returned ID here. It doesn't name alternatives explicitly but provides clear contextual guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_order_historyARead-only
List previous orders, most recent first.
Args: skip: Number of orders to skip, for pagination. take: Number of orders to return (1-50).
Returns: Orders with Id, OrderNumber, Total and delivery window. Use Id with get_order_details. Addresses are redacted.
| Name | Required | Description | Default |
|---|---|---|---|
| skip | No | ||
| take | No |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint and openWorldHint, so the safe-read nature is covered. The description adds meaningful behavioral context: addresses are redacted, returns include delivery window, and pagination semantics are explained, which goes beyond the structured annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is compact and well-structured with labeled Args and Returns sections. No redundant content; every sentence adds practical information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a list endpoint with a simple schema and an output schema, the description covers ordering, pagination, redaction, and returned key fields. It also provides guidance for the natural next step (get_order_details), making it contextually complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Despite 0% schema description coverage, the description fully explains both parameters: skip as number to skip and take as count with a range constraint (1-50). This is essential semantic detail that the schema's type/default fields do not convey.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Clearly identifies the tool as listing previous orders in reverse chronological order. The verb 'List' and resource 'orders' are specific, and the description distinguishes it from get_order_details by implying this is the overview tool.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly directs users to use the returned Id with get_order_details, indicating when to chain to the detail tool. However, it does not enumerate situations where this tool should be avoided or alternatives for filtering/searching, though sibling tools are mostly product-focused.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_product_detailsARead-only
Fetch full details for one product, including nutrition and allergens.
Args: product_id: Product Id from search_products, e.g. "5070417".
| Name | Required | Description | Default |
|---|---|---|---|
| product_id | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, so the safe-read behavior is covered. The description adds that it returns nutrition and allergens, which is a minor behavioral detail, but it does not disclose error handling, rate limits, or other operational behavior. No contradiction with annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is short and front-loaded with the main purpose, followed by a clearly formatted args section. Every sentence serves a purpose, with no redundant content.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
This is a simple one-parameter read tool with an output schema, so return values are already covered by the schema. The description, annotations, and sibling list provide complete context for selecting and invoking the tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate. It does so effectively by explaining that product_id is 'Product Id from search_products' and providing an example ('5070417'), which adds meaningful guidance beyond the bare schema type declaration.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses the specific verb 'Fetch' with a clear resource ('full details for one product'), and explicitly mentions nutrition and allergens. It distinguishes itself from siblings like search_products (which searches) and order tools by focusing on a single product's details.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies usage after search_products by stating product_id comes from search_products, providing clear context. It does not explicitly mention when not to use or alternatives, but the sibling names and the phrase 'one product' offer sufficient guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_productsARead-only
Search the nemlig.com catalogue.
Args: query: Search term. Danish terms match best, e.g. "kaffebønner", "mælk". limit: Maximum number of products to return (1-50).
Returns: Matching products with Id, Name, Brand, Price and availability. Use the Id with get_product_details or set_basket_quantity.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | ||
| query | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare readOnlyHint=true and openWorldHint=true, so the safe-read behavior is already known. The description adds value by specifying the return fields (Id, Name, Brand, Price, availability) and the limit constraint (1-50). This is useful behavioral context beyond the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured with Args and Returns sections. Every sentence adds value: search query hints, parameter explanation, and return usage. No fluff or repetition.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's simple nature (2 params, output schema exists, no nested objects), the description is complete. It covers the search behavior, parameter semantics, return format, and downstream usage (get_product_details/set_basket_quantity). Users know exactly what to expect and how to proceed.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, but the description provides detailed semantics for both parameters: query is the search term (with language hint), and limit is the maximum number of results (with range 1-50). This fully compensates for the minimal schema and adds meaning beyond the type declarations.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's purpose: 'Search the nemlig.com catalogue.' This is a specific verb (search) with a resource (catalogue) and differentiates from siblings like get_product_details or set_basket_quantity, which are for retrieval or mutation.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides useful guidance on when to use this tool: as the entry point for searching, with a note that Danish terms work best. It also directs the user to use the returned Id with get_product_details or set_basket_quantity, implying the search is a precursor to those tools. No explicit exclusions, but clear context.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
set_basket_quantityADestructive
Set how many units of a product the basket should contain.
The quantity is absolute, not a delta. It is the number of units to end up with, so setting 2 on a line that currently holds 5 removes 3 of them, and setting 0 removes the product entirely. To add to a line that may already exist, read its current Quantity with get_basket and pass the new total.
This changes the user's real basket on nemlig.com. It does not place an order or charge anything -- the user completes checkout themselves.
Args: product_id: Product Id from search_products, e.g. "5070417". quantity: Units the basket should end up with. 0 removes the product.
Returns: The updated basket, with addresses redacted.
| Name | Required | Description | Default |
|---|---|---|---|
| quantity | No | ||
| product_id | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description adds significant behavioral context beyond the annotations: the quantity is absolute rather than a delta, setting 0 removes the product, it changes the user's real basket, and the returned basket has addresses redacted. These details are not present in the structured annotations and are crucial for safe invocation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with the core purpose, then provides essential semantics and side effects in a clear paragraph style, followed by an Args/Returns section. Every sentence serves a purpose, with no repetition of schema defaults or redundant fluff.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a two-parameter tool with output schema, the description covers all necessary context: absolute quantity semantics, how to calculate a delta, the real-world side effect, what it does not do, and what the return value contains. No significant information gap remains.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
With 0% schema description coverage, the description fully compensates by explaining each parameter: product_id is 'Product Id from search_products' with an example, and quantity is 'Units the basket should end up with. 0 removes the product.' This adds meaning beyond the raw schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states exactly what the tool does: 'Set how many units of a product the basket should contain.' It uses a specific verb and resource, and clearly distinguishes itself from siblings like get_basket and search_products by describing a mutation operation.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explicitly explains when to use this tool versus alternatives: 'To add to a line that may already exist, read its current Quantity with get_basket and pass the new total.' It also clarifies what it does not do ('does not place an order or charge anything'), providing clear usage context.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
TDQS
Each tool targets a distinct resource and action: search vs. details, basket vs. order, and list vs. detail vs. modify. No two tools overlap in purpose.
All tools follow the consistent verb_noun pattern in snake_case: search_products, get_product_details, get_basket, get_order_details, set_basket_quantity, get_order_history.
Six tools is well-scoped for a grocery shopping assistant, covering product discovery, basket management, and order history without unnecessary bloat.
The domain is fully covered: product search/detail, basket read/update (including removal via quantity 0), and order list/detail. Checkout is intentionally omitted as the user completes it manually.
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
Turn any shopping list into a ready-to-checkout grocery cart across 26 European supermarkets.
Live prices, deals & optimal multi-stop shopping routes for German grocery & drug stores.
Household-aware cooking brain: pantry, meal suggestions, dietary safety, recipes, shopping lists.
Routes natural-language shopping queries to merchant storefronts, returns normalized results.
Related MCP Servers
- FlicenseBqualityCmaintenanceEnables AI assistants to interact with Mathem.se, a Swedish online grocery store, allowing users to search for ingredients, add items to their shopping basket, and manage recipes through natural language.42
- AlicenseNot gradedqualityAmaintenanceEnables AI assistants to interact with Picnic online supermarket for grocery shopping, meal planning, cart management, delivery tracking, and budget-conscious shopping in Netherlands and Germany.24895MIT
- FlicenseNot gradedqualityDmaintenanceEnables searching for groceries and automatically adding items to cart through various grocery vendor APIs like Rami Levy and Keshet.3
- AlicenseNot gradedqualityNot gradedmaintenanceEnables agentic grocery shopping on Oda (Norway) and Mathem (Sweden) platforms through an MCP-compatible interface. Users can search for products, manage their shopping cart, and access order history using natural language commands.1
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/kraenhansen/nemlig-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server