picnic-mcp 0.5.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,30 +1,48 @@
1
1
  # picnic-mcp
2
2
 
3
- An [MCP](https://modelcontextprotocol.io) server for the online supermarket [Picnic](https://picnic.app). It lets a model search Picnic's products and change your shopping cart. It can't place an order.
3
+ An [MCP](https://modelcontextprotocol.io) server for the online supermarket [Picnic](https://picnic.app). It lets a model search Picnic's products, fill your shopping cart, pick a delivery slot, show promotions and the products you usually buy, and use recipes. It can't place an order.
4
4
 
5
- Unofficial: not made or supported by Picnic. Built on [picnic-api](https://github.com/MRVDH/picnic-api).
5
+ Unofficial: not made or supported by Picnic. Built on [picnic-api](https://github.com/MRVDH/picnic-api). Tested with Dutch accounts; German and French accounts should work, but haven't been tested.
6
+
7
+ ## Part of a set
8
+
9
+ picnic-api, picnic-web and picnic-mcp are developed and released together. When the Picnic app changes how it gets its data, picnic-api follows it and picnic-web and picnic-mcp are updated in the same change, so their latest versions always work together.
10
+
11
+ | Project | What it is |
12
+ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
13
+ | [picnic-api](https://github.com/MRVDH/picnic-api) [![npm](https://img.shields.io/npm/v/picnic-api.svg?style=flat-square)](https://www.npmjs.com/package/picnic-api) | Node.js library for Picnic's API: products, cart, delivery slots, deliveries and recipes. |
14
+ | [picnic-web](https://github.com/MRVDH/picnic-web) | Web interface for Picnic, to shop from your browser. Live at [picnic.maartenvandenhoven.com](http://picnic.maartenvandenhoven.com). |
15
+ | [picnic-mcp](https://github.com/MRVDH/picnic-mcp) [![npm](https://img.shields.io/npm/v/picnic-mcp.svg?style=flat-square)](https://www.npmjs.com/package/picnic-mcp) | MCP server that lets AI assistants search products, fill your cart and pick a delivery slot. |
6
16
 
7
17
  ## Tools
8
18
 
9
- The tools come in groups. `cart`, `slots` and `product` are on by default; turn groups on or off with `PICNIC_MCP_TOOLS` (see Setup).
19
+ The tools come in groups. `cart`, `slots`, `product` and `discover` are on by default; turn groups on or off with `PICNIC_MCP_TOOLS` (see Setup).
10
20
 
11
21
  | Group | Tool | What it does |
12
22
  | ------------ | ------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
13
23
  | `cart` | `search_products` | Searches products. Returns a `bestMatch` when one product fits (usually one you bought before), or 2 or 3 `choices` to ask you about. |
14
- | | `add_to_cart` | Adds a product by its id. Returns the quantity in the cart and the cart total, and replacements when the product can't be delivered. |
24
+ | | `add_to_cart` | Adds one or more products by their ids. Returns the quantity of each in the cart, the products that failed, the cart total, and replacements when a product can't be delivered. |
25
+ | | `set_cart_quantity` | Sets how many of a product are in the cart; 0 removes it. |
15
26
  | | `remove_from_cart` | Removes a product by its id. |
16
27
  | | `get_cart` | Shows the cart: products, quantities, prices, total and delivery window, and replacements for products that can't be delivered. |
17
28
  | `slots` | `get_delivery_slots` | Lists the delivery slots, two days at a time or for one date. |
18
29
  | | `select_delivery_slot` | Chooses the delivery slot of the cart. |
19
30
  | `product` | `get_product` | Shows a product's ingredients, allergens, nutrition, storage info, promotion and price. |
31
+ | `discover` | `get_promotions` | Lists this week's promotions per section (e.g. per category), all promotions of a section, or the products of one promotion. |
32
+ | | `get_favorites` | Lists the products you buy, per aisle, as the app's "Favorieten" tab does. For "add my usual groceries". |
20
33
  | `deliveries` | `get_deliveries` | Shows upcoming deliveries (window, number of products, total, and the expected arrival while the driver is on the way) or the last past ones. Optionally the products, e.g. to order the same again. |
21
34
  | `recipes` | `search_recipes` | Searches Picnic's recipes. |
35
+ | | `get_saved_recipes` | Lists the recipes you saved in the app. |
22
36
  | | `get_recipe` | Shows a recipe's ingredients, allergens and steps. The recipe tools also take a recipe link shared from the Picnic app. |
23
37
  | | `add_recipe_to_cart` | Adds a recipe's ingredients to the cart for a number of portions. |
24
38
  | | `remove_recipe_from_cart` | Removes a recipe and its ingredients from the cart. |
39
+ | | `save_recipe` | Saves a recipe in the app. |
40
+ | | `unsave_recipe` | Removes a recipe from your saved recipes. |
25
41
 
26
42
  Output is compact JSON with only what a model needs. It leaves out your name, address, payment details, order numbers and other account details. Keep in mind that whatever the tools return is sent to the model your MCP client uses.
27
43
 
44
+ When a search has no clear match and your MCP client can show a form ([elicitation](https://modelcontextprotocol.io/specification/latest/client/elicitation)), you pick the product in the client yourself, instead of the model asking you in the chat.
45
+
28
46
  ## Setup
29
47
 
30
48
  Requires Node.js 20 or later.
@@ -39,7 +57,9 @@ It asks for your country, email and password, and the code Picnic texts you when
39
57
 
40
58
  ### 2. Add the server to your MCP client
41
59
 
42
- Most clients take a configuration like this:
60
+ **Claude Desktop and other MCPB clients:** download `picnic-mcp.mcpb` from the [latest release](https://github.com/MRVDH/picnic-mcp/releases/latest), open it, and fill in the auth key.
61
+
62
+ **Other clients** take a configuration like this:
43
63
 
44
64
  ```json
45
65
  {
@@ -56,7 +76,9 @@ Most clients take a configuration like this:
56
76
  }
57
77
  ```
58
78
 
59
- `PICNIC_COUNTRY_CODE` is `NL`, `DE` or `FR` (default `NL`). To choose the tool groups, add `PICNIC_MCP_TOOLS` with a comma-separated list, e.g. `"cart,slots,product,deliveries,recipes"` (default `cart,slots,product`). The server runs over stdio; see [HTTP](#http) to reach it over the network.
79
+ `PICNIC_COUNTRY_CODE` is `NL`, `DE` or `FR` (default `NL`). To choose the tool groups, add `PICNIC_MCP_TOOLS` with a comma-separated list, e.g. `"cart,slots,product,discover,deliveries,recipes"` (default `cart,slots,product,discover`). Fewer tools help smaller models pick the right one. The server runs over stdio; see [HTTP](#http) to reach it over the network.
80
+
81
+ The server is also listed in the [MCP Registry](https://registry.modelcontextprotocol.io) as `io.github.MRVDH/picnic-mcp`.
60
82
 
61
83
  When the key expires, the tools say so; run `npx picnic-mcp login` again.
62
84
 
@@ -96,4 +118,4 @@ Pass `tools` to choose the tool groups (e.g. `tools: ["cart", "recipes"]`), `cli
96
118
 
97
119
  ### Product images
98
120
 
99
- Results that list products (search, the cart, an added product, product details) carry the image URLs of those products in `_meta["picnic-mcp/images"]`, by product id. MCP clients don't pass `_meta` to the model, so the images cost no tokens; your own code can use them, e.g. to show product photos. The images don't need the auth key. The key is exported as `IMAGES_META_KEY`.
121
+ Results that list products (search, the cart, added products, promotions, favorites, product details) carry the image URLs of those products in `_meta["picnic-mcp/images"]`, by product id. MCP clients don't pass `_meta` to the model, so the images cost no tokens; your own code can use them, e.g. to show product photos. The images don't need the auth key. The key is exported as `IMAGES_META_KEY`.
package/dist/cli.js CHANGED
@@ -23,7 +23,7 @@ const USAGE = `Usage:
23
23
  comma-separated, e.g. a reverse proxy's
24
24
  picnic-mcp login Sign in to Picnic and print an auth key for PICNIC_AUTH_KEY.`;
25
25
  function parseCountryCode(value) {
26
- const code = (value ?? "NL").trim().toUpperCase();
26
+ const code = (value?.trim() || "NL").toUpperCase();
27
27
  if (!COUNTRY_CODES.includes(code)) {
28
28
  throw new Error(`Unknown country code "${value}". Use one of ${COUNTRY_CODES.join(", ")}.`);
29
29
  }
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
package/dist/errors.d.ts CHANGED
@@ -5,6 +5,12 @@
5
5
  export declare function describeError(error: unknown): string;
6
6
  /** Added to an error of a tool that changes the cart, when the change may have happened anyway. */
7
7
  export declare const CART_MAY_HAVE_CHANGED = "The cart may have changed anyway: check get_cart before trying again.";
8
+ /**
9
+ * Whether an error is about the one product a request was for (it doesn't exist, Picnic refused
10
+ * it), so the next product can still be tried. Not for the auth key, rate limiting or an outage,
11
+ * which make every request fail.
12
+ */
13
+ export declare function isProductError(error: unknown): boolean;
8
14
  /**
9
15
  * Whether a failed cart change may still have gone through: after a timeout, a network error or a
10
16
  * server error the request may have reached Picnic. Not when Picnic rejected it (a 4xx, the auth
package/dist/errors.js CHANGED
@@ -27,6 +27,18 @@ export function describeError(error) {
27
27
  }
28
28
  /** Added to an error of a tool that changes the cart, when the change may have happened anyway. */
29
29
  export const CART_MAY_HAVE_CHANGED = "The cart may have changed anyway: check get_cart before trying again.";
30
+ /**
31
+ * Whether an error is about the one product a request was for (it doesn't exist, Picnic refused
32
+ * it), so the next product can still be tried. Not for the auth key, rate limiting or an outage,
33
+ * which make every request fail.
34
+ */
35
+ export function isProductError(error) {
36
+ if (PicnicClient.isProductNotFoundError(error))
37
+ return true;
38
+ if (!PicnicClient.isPicnicApiError(error) || /<html[\s>]/i.test(error.body))
39
+ return false;
40
+ return error.status >= 400 && error.status < 500 && ![401, 403, 429].includes(error.status);
41
+ }
30
42
  /**
31
43
  * Whether a failed cart change may still have gone through: after a timeout, a network error or a
32
44
  * server error the request may have reached Picnic. Not when Picnic rejected it (a 4xx, the auth
@@ -1 +1 @@
1
- {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,YAAY,MAAM,YAAY,CAAC;AAEtC;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,KAAc;IAC1C,IAAI,YAAY,CAAC,gBAAgB,CAAC,KAAK,CAAC,EAAE,CAAC;QACzC,sFAAsF;QACtF,IAAI,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;YACnC,OAAO,kEAAkE,CAAC;QAC5E,CAAC;QACD,IAAI,KAAK,CAAC,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;YACjD,OAAO,kHAAkH,CAAC;QAC5H,CAAC;QACD,OAAO,6BAA6B,KAAK,CAAC,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC;IAC7F,CAAC;IACD,IAAI,YAAY,CAAC,sBAAsB,CAAC,KAAK,CAAC,EAAE,CAAC;QAC/C,OAAO,WAAW,KAAK,CAAC,SAAS,oFAAoF,CAAC;IACxH,CAAC;IACD,IAAI,YAAY,CAAC,2BAA2B,CAAC,KAAK,CAAC,EAAE,CAAC;QACpD,OAAO,uHAAuH,CAAC;IACjI,CAAC;IACD,IAAI,KAAK,YAAY,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,cAAc,EAAE,CAAC;QAC5D,OAAO,2CAA2C,CAAC;IACrD,CAAC;IACD,OAAO,0CAA0C,CAAC;AACpD,CAAC;AAED,mGAAmG;AACnG,MAAM,CAAC,MAAM,qBAAqB,GAChC,uEAAuE,CAAC;AAE1E;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAAC,KAAc;IAC/C,IAAI,YAAY,CAAC,gBAAgB,CAAC,KAAK,CAAC;QACtC,OAAO,KAAK,CAAC,MAAM,IAAI,GAAG,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAChE,IACE,YAAY,CAAC,sBAAsB,CAAC,KAAK,CAAC;QAC1C,YAAY,CAAC,2BAA2B,CAAC,KAAK,CAAC,EAC/C,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,YAAY,MAAM,YAAY,CAAC;AAEtC;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,KAAc;IAC1C,IAAI,YAAY,CAAC,gBAAgB,CAAC,KAAK,CAAC,EAAE,CAAC;QACzC,sFAAsF;QACtF,IAAI,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;YACnC,OAAO,kEAAkE,CAAC;QAC5E,CAAC;QACD,IAAI,KAAK,CAAC,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;YACjD,OAAO,kHAAkH,CAAC;QAC5H,CAAC;QACD,OAAO,6BAA6B,KAAK,CAAC,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC;IAC7F,CAAC;IACD,IAAI,YAAY,CAAC,sBAAsB,CAAC,KAAK,CAAC,EAAE,CAAC;QAC/C,OAAO,WAAW,KAAK,CAAC,SAAS,oFAAoF,CAAC;IACxH,CAAC;IACD,IAAI,YAAY,CAAC,2BAA2B,CAAC,KAAK,CAAC,EAAE,CAAC;QACpD,OAAO,uHAAuH,CAAC;IACjI,CAAC;IACD,IAAI,KAAK,YAAY,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,cAAc,EAAE,CAAC;QAC5D,OAAO,2CAA2C,CAAC;IACrD,CAAC;IACD,OAAO,0CAA0C,CAAC;AACpD,CAAC;AAED,mGAAmG;AACnG,MAAM,CAAC,MAAM,qBAAqB,GAChC,uEAAuE,CAAC;AAE1E;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,KAAc;IAC3C,IAAI,YAAY,CAAC,sBAAsB,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAC5D,IAAI,CAAC,YAAY,CAAC,gBAAgB,CAAC,KAAK,CAAC,IAAI,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;QAAE,OAAO,KAAK,CAAC;IAC1F,OAAO,KAAK,CAAC,MAAM,IAAI,GAAG,IAAI,KAAK,CAAC,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;AAC9F,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAAC,KAAc;IAC/C,IAAI,YAAY,CAAC,gBAAgB,CAAC,KAAK,CAAC;QACtC,OAAO,KAAK,CAAC,MAAM,IAAI,GAAG,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAChE,IACE,YAAY,CAAC,sBAAsB,CAAC,KAAK,CAAC;QAC1C,YAAY,CAAC,2BAA2B,CAAC,KAAK,CAAC,EAC/C,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,15 @@
1
+ import type { CountryCode, ProductTile, PromotionGroup } from "../types.js";
2
+ import { type ProductOutput } from "./products.js";
3
+ /** A promotion on several products, as a tool shows it to a model. */
4
+ export type PromotionOutput = {
5
+ /** For get_promotions, to list its products. */
6
+ promotionId: string;
7
+ name: string;
8
+ /** E.g. "Bv. sojayoghurt". */
9
+ example?: string;
10
+ /** E.g. "2 voor €3.99". */
11
+ label?: string;
12
+ };
13
+ export declare function formatPromotion(group: PromotionGroup): PromotionOutput;
14
+ /** Products from a promotions or favorites page; none of them is marked as bought before. */
15
+ export declare function formatTiles(tiles: ProductTile[], countryCode: CountryCode): ProductOutput[];
@@ -0,0 +1,14 @@
1
+ import { formatProduct } from "./products.js";
2
+ export function formatPromotion(group) {
3
+ return {
4
+ promotionId: group.id,
5
+ name: group.name,
6
+ ...(group.example && { example: group.example }),
7
+ ...(group.label && { label: group.label }),
8
+ };
9
+ }
10
+ /** Products from a promotions or favorites page; none of them is marked as bought before. */
11
+ export function formatTiles(tiles, countryCode) {
12
+ return tiles.map((tile) => formatProduct({ tile, boughtBefore: false }, countryCode));
13
+ }
14
+ //# sourceMappingURL=discover.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discover.js","sourceRoot":"","sources":["../../src/format/discover.ts"],"names":[],"mappings":"AACA,OAAO,EAAsB,aAAa,EAAE,MAAM,eAAe,CAAC;AAalE,MAAM,UAAU,eAAe,CAAC,KAAqB;IACnD,OAAO;QACL,WAAW,EAAE,KAAK,CAAC,EAAE;QACrB,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,GAAG,CAAC,KAAK,CAAC,OAAO,IAAI,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC;QAChD,GAAG,CAAC,KAAK,CAAC,KAAK,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,CAAC;KAC3C,CAAC;AACJ,CAAC;AAED,6FAA6F;AAC7F,MAAM,UAAU,WAAW,CAAC,KAAoB,EAAE,WAAwB;IACxE,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,aAAa,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,KAAK,EAAE,EAAE,WAAW,CAAC,CAAC,CAAC;AACxF,CAAC"}
@@ -1,7 +1,7 @@
1
1
  import type { CountryCode, Product } from "../types.js";
2
2
  /** A product's details as a tool shows them to a model. Optional fields are left out when empty. */
3
3
  export type ProductDetailsOutput = {
4
- id: string;
4
+ productId: string;
5
5
  name: string;
6
6
  brand?: string;
7
7
  size?: string;
@@ -13,7 +13,7 @@ export function formatProductDetails(product, countryCode) {
13
13
  .filter((section) => section.content.trim() && lines(section.content.split("\n")) !== nutritionText)
14
14
  .map((section) => ({ title: section.title, content: cut(section.content) }));
15
15
  return {
16
- id: product.id,
16
+ productId: product.id,
17
17
  name: product.name,
18
18
  ...(product.brand && { brand: product.brand }),
19
19
  ...(product.unitQuantity && { size: product.unitQuantity }),
@@ -1 +1 @@
1
- {"version":3,"file":"product.js","sourceRoot":"","sources":["../../src/format/product.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"product.js","sourceRoot":"","sources":["../../src/format/product.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  import type { CountryCode, ProductTile } from "../types.js";
2
2
  /** A product as a tool shows it to a model. Optional fields are left out when empty. */
3
3
  export type ProductOutput = {
4
- id: string;
4
+ productId: string;
5
5
  name: string;
6
6
  brand?: string;
7
7
  size?: string;
@@ -7,7 +7,7 @@ export function formatProduct(candidate, countryCode) {
7
7
  const { tile } = candidate;
8
8
  const labels = tile.labels.map((label) => label.text).filter((text) => !!text);
9
9
  return {
10
- id: tile.id,
10
+ productId: tile.id,
11
11
  name: tile.namePrefix ? `${tile.namePrefix} ${tile.name}` : tile.name,
12
12
  ...(tile.brand && { brand: tile.brand }),
13
13
  ...(tile.unitQuantity && { size: tile.unitQuantity }),
@@ -1 +1 @@
1
- {"version":3,"file":"products.js","sourceRoot":"","sources":["../../src/format/products.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAyB1C;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,SAAoB,EAAE,WAAwB;IAC1E,MAAM,EAAE,IAAI,EAAE,GAAG,SAAS,CAAC;IAC3B,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAkB,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAC/F,OAAO;QACL,EAAE,EAAE,IAAI,CAAC,EAAE;QACX,IAAI,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI;QACrE,GAAG,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC;QACxC,GAAG,CAAC,IAAI,CAAC,YAAY,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,YAAY,EAAE,CAAC;QACrD,KAAK,EAAE,WAAW,CAAC,IAAI,CAAC,YAAY,EAAE,WAAW,CAAC;QAClD,GAAG,CAAC,IAAI,CAAC,aAAa,KAAK,IAAI;YAC7B,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,YAAY,IAAI;YACxC,QAAQ,EAAE,WAAW,CAAC,IAAI,CAAC,aAAa,EAAE,WAAW,CAAC;SACvD,CAAC;QACJ,GAAG,CAAC,IAAI,CAAC,SAAS,IAAI,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC;QACpD,GAAG,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC;QACpC,GAAG,CAAC,SAAS,CAAC,YAAY,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC;QACrD,GAAG,CAAC,IAAI,CAAC,aAAa,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC;KACjD,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"products.js","sourceRoot":"","sources":["../../src/format/products.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAyB1C;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,SAAoB,EAAE,WAAwB;IAC1E,MAAM,EAAE,IAAI,EAAE,GAAG,SAAS,CAAC;IAC3B,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAkB,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAC/F,OAAO;QACL,SAAS,EAAE,IAAI,CAAC,EAAE;QAClB,IAAI,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI;QACrE,GAAG,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC;QACxC,GAAG,CAAC,IAAI,CAAC,YAAY,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,YAAY,EAAE,CAAC;QACrD,KAAK,EAAE,WAAW,CAAC,IAAI,CAAC,YAAY,EAAE,WAAW,CAAC;QAClD,GAAG,CAAC,IAAI,CAAC,aAAa,KAAK,IAAI;YAC7B,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,YAAY,IAAI;YACxC,QAAQ,EAAE,WAAW,CAAC,IAAI,CAAC,aAAa,EAAE,WAAW,CAAC;SACvD,CAAC;QACJ,GAAG,CAAC,IAAI,CAAC,SAAS,IAAI,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC;QACpD,GAAG,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC;QACpC,GAAG,CAAC,SAAS,CAAC,YAAY,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC;QACrD,GAAG,CAAC,IAAI,CAAC,aAAa,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC;KACjD,CAAC;AACJ,CAAC"}
@@ -36,5 +36,6 @@ export type RecipeOutput = {
36
36
  ingredients: RecipeIngredientOutput[];
37
37
  steps?: string[];
38
38
  };
39
- export declare function formatRecipeSummary(recipe: SearchRecipe): RecipeSummaryOutput;
39
+ /** A recipe from search results or the saved recipes; both have these fields. */
40
+ export declare function formatRecipeSummary(recipe: Pick<SearchRecipe, "id" | "name" | "subtitle" | "tags">): RecipeSummaryOutput;
40
41
  export declare function formatRecipe(recipe: Recipe, countryCode: CountryCode): RecipeOutput;
@@ -1,6 +1,7 @@
1
1
  import { formatPrice } from "./prices.js";
2
2
  /** Steps are cut at this many characters each, to keep the output short. */
3
3
  const MAX_STEP = 600;
4
+ /** A recipe from search results or the saved recipes; both have these fields. */
4
5
  export function formatRecipeSummary(recipe) {
5
6
  return {
6
7
  recipeId: recipe.id,
@@ -1 +1 @@
1
- {"version":3,"file":"recipes.js","sourceRoot":"","sources":["../../src/format/recipes.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1C,4EAA4E;AAC5E,MAAM,QAAQ,GAAG,GAAG,CAAC;AAuCrB,MAAM,UAAU,mBAAmB,CAAC,MAAoB;IACtD,OAAO;QACL,QAAQ,EAAE,MAAM,CAAC,EAAE;QACnB,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,GAAG,CAAC,MAAM,CAAC,QAAQ,IAAI,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC;QACrD,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC;KACrD,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,MAAc,EAAE,WAAwB;IACnE,OAAO;QACL,QAAQ,EAAE,MAAM,CAAC,EAAE;QACnB,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,GAAG,CAAC,MAAM,CAAC,kBAAkB,KAAK,IAAI,IAAI,EAAE,kBAAkB,EAAE,MAAM,CAAC,kBAAkB,EAAE,CAAC;QAC5F,GAAG,CAAC,MAAM,CAAC,WAAW,IAAI,EAAE,WAAW,EAAE,MAAM,CAAC,WAAW,EAAE,CAAC;QAC9D,SAAS,EAAE,EAAE,QAAQ,EAAE,MAAM,CAAC,SAAS,CAAC,QAAQ,EAAE,UAAU,EAAE,MAAM,CAAC,SAAS,CAAC,UAAU,EAAE;QAC3F,WAAW,EAAE,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;YACnD,GAAG,CAAC,UAAU,CAAC,IAAI,IAAI,EAAE,IAAI,EAAE,UAAU,CAAC,IAAI,EAAE,CAAC;YACjD,GAAG,CAAC,UAAU,CAAC,aAAa,IAAI,EAAE,SAAS,EAAE,UAAU,CAAC,aAAa,EAAE,CAAC;YACxE,QAAQ,EAAE,UAAU,CAAC,QAAQ;YAC7B,GAAG,CAAC,UAAU,CAAC,UAAU,IAAI,EAAE,MAAM,EAAE,UAAU,CAAC,UAAU,EAAE,CAAC;YAC/D,GAAG,CAAC,UAAU,CAAC,KAAK,KAAK,IAAI,IAAI,EAAE,KAAK,EAAE,WAAW,CAAC,UAAU,CAAC,KAAK,EAAE,WAAW,CAAC,EAAE,CAAC;YACvF,KAAK,EAAE,UAAU,CAAC,OAAO;YACzB,GAAG,CAAC,UAAU,CAAC,IAAI,KAAK,UAAU,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;YACzD,GAAG,CAAC,CAAC,UAAU,CAAC,WAAW,IAAI;gBAC7B,WAAW,EAAE,UAAU,CAAC,iBAAiB,IAAI,eAAe;aAC7D,CAAC;SACH,CAAC,CAAC;QACH,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI;YAC7B,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAC/B,IAAI,CAAC,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAC9D;SACF,CAAC;KACH,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"recipes.js","sourceRoot":"","sources":["../../src/format/recipes.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1C,4EAA4E;AAC5E,MAAM,QAAQ,GAAG,GAAG,CAAC;AAuCrB,iFAAiF;AACjF,MAAM,UAAU,mBAAmB,CACjC,MAA+D;IAE/D,OAAO;QACL,QAAQ,EAAE,MAAM,CAAC,EAAE;QACnB,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,GAAG,CAAC,MAAM,CAAC,QAAQ,IAAI,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC;QACrD,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC;KACrD,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,MAAc,EAAE,WAAwB;IACnE,OAAO;QACL,QAAQ,EAAE,MAAM,CAAC,EAAE;QACnB,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,GAAG,CAAC,MAAM,CAAC,kBAAkB,KAAK,IAAI,IAAI,EAAE,kBAAkB,EAAE,MAAM,CAAC,kBAAkB,EAAE,CAAC;QAC5F,GAAG,CAAC,MAAM,CAAC,WAAW,IAAI,EAAE,WAAW,EAAE,MAAM,CAAC,WAAW,EAAE,CAAC;QAC9D,SAAS,EAAE,EAAE,QAAQ,EAAE,MAAM,CAAC,SAAS,CAAC,QAAQ,EAAE,UAAU,EAAE,MAAM,CAAC,SAAS,CAAC,UAAU,EAAE;QAC3F,WAAW,EAAE,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;YACnD,GAAG,CAAC,UAAU,CAAC,IAAI,IAAI,EAAE,IAAI,EAAE,UAAU,CAAC,IAAI,EAAE,CAAC;YACjD,GAAG,CAAC,UAAU,CAAC,aAAa,IAAI,EAAE,SAAS,EAAE,UAAU,CAAC,aAAa,EAAE,CAAC;YACxE,QAAQ,EAAE,UAAU,CAAC,QAAQ;YAC7B,GAAG,CAAC,UAAU,CAAC,UAAU,IAAI,EAAE,MAAM,EAAE,UAAU,CAAC,UAAU,EAAE,CAAC;YAC/D,GAAG,CAAC,UAAU,CAAC,KAAK,KAAK,IAAI,IAAI,EAAE,KAAK,EAAE,WAAW,CAAC,UAAU,CAAC,KAAK,EAAE,WAAW,CAAC,EAAE,CAAC;YACvF,KAAK,EAAE,UAAU,CAAC,OAAO;YACzB,GAAG,CAAC,UAAU,CAAC,IAAI,KAAK,UAAU,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;YACzD,GAAG,CAAC,CAAC,UAAU,CAAC,WAAW,IAAI;gBAC7B,WAAW,EAAE,UAAU,CAAC,iBAAiB,IAAI,eAAe;aAC7D,CAAC;SACH,CAAC,CAAC;QACH,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI;YAC7B,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAC/B,IAAI,CAAC,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAC9D;SACF,CAAC;KACH,CAAC;AACJ,CAAC"}
package/dist/index.d.ts CHANGED
@@ -4,3 +4,4 @@ export type { ProductOutput } from "./format/products.js";
4
4
  export type { CartOutput, CartLineOutput, CartSummaryOutput } from "./format/cart.js";
5
5
  export { DEFAULT_TOOL_GROUPS, TOOL_GROUPS, type ToolGroup } from "./tools/groups.js";
6
6
  export { IMAGES_META_KEY, type ImageUrls } from "./tools/result.js";
7
+ export type { PromotionOutput } from "./format/discover.js";
package/dist/server.d.ts CHANGED
@@ -13,7 +13,7 @@ export type CreateServerOptions = ({
13
13
  /** The country of the client's account. Default: "NL". */
14
14
  countryCode?: CountryCode;
15
15
  }) & {
16
- /** The tool groups to turn on. Default: `["cart", "slots", "product"]`. */
16
+ /** The tool groups to turn on. Default: `["cart", "slots", "product", "discover"]`. */
17
17
  tools?: readonly ToolGroup[];
18
18
  /** Called with errors from Picnic before the tool returns a short message. Default: log to stderr. */
19
19
  onError?: (error: unknown) => void;
@@ -1,9 +1,14 @@
1
1
  import * as z from "zod";
2
+ import { CART_MAY_HAVE_CHANGED, describeError, isProductError, mayHaveChangedCart, } from "../errors.js";
2
3
  import { formatCart, formatCartSummary, formatUnavailability } from "../format/cart.js";
3
4
  import { imageUrls } from "./context.js";
4
5
  import { productId, quantity } from "./inputs.js";
5
6
  import { loadReplacements } from "./replacements.js";
6
7
  import { errorResult, jsonResult, runTool } from "./result.js";
8
+ /** At most this many products per add_to_cart call: each is one request to Picnic. */
9
+ const MAX_ITEMS = 20;
10
+ const NOT_ADDED = "Picnic did not add it. Check the product id with search_products.";
11
+ const UNAVAILABLE_HINT = "Some products are in the cart but can't be delivered in the selected delivery window: tell the user, and offer the replacements if there are any.";
7
12
  export function registerCartTools(server, context) {
8
13
  const { client, countryCode, onError } = context;
9
14
  server.registerTool("get_cart", {
@@ -21,35 +26,93 @@ export function registerCartTools(server, context) {
21
26
  }, onError));
22
27
  server.registerTool("add_to_cart", {
23
28
  title: "Add to cart",
24
- description: "Add a product to the user's Picnic shopping cart. Get the product id from search_products first. " +
25
- "Returns the product with the quantity now in the cart, and the cart total. " +
26
- "If the product can't be delivered in the selected delivery window, it says so and lists `replacements`: tell the user and offer them. " +
29
+ description: "Add one or more products to the user's Picnic shopping cart. Get the product ids from search_products first; " +
30
+ `put all products the user asked for in one call (at most ${MAX_ITEMS}). ` +
31
+ "Returns each added product with the quantity now in the cart, the products that failed, and the cart total. " +
32
+ "A product that can't be delivered in the selected delivery window has `unavailable` and `replacements`: tell the user and offer them. " +
33
+ 'To change how many of a product are in the cart ("make it 4"), use set_cart_quantity instead. ' +
27
34
  "This does not place an order.",
28
- inputSchema: z.object({ productId, quantity: quantity("add") }),
35
+ inputSchema: z.object({
36
+ items: z
37
+ .array(z.object({ productId, quantity: quantity("add") }))
38
+ .min(1)
39
+ .max(MAX_ITEMS)
40
+ .describe('The products to add, e.g. [{"productId": "s1004201", "quantity": 2}].'),
41
+ }),
29
42
  annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },
30
- }, ({ productId, quantity }) => runTool(async () => {
31
- const cart = await client.cart.addProductToCart(productId, quantity);
32
- const lines = linesOf(cart, productId);
33
- if (lines.length === 0) {
34
- return errorResult(`Picnic did not add ${productId}. Check the product id with search_products.`);
43
+ }, ({ items }) => runTool(async () => {
44
+ let cart;
45
+ /** The quantity this call added, by product id, in the order of the items. */
46
+ const added = new Map();
47
+ const failed = [];
48
+ for (const [index, item] of items.entries()) {
49
+ try {
50
+ cart = await client.cart.addProductToCart(item.productId, item.quantity);
51
+ if (linesOf(cart, item.productId).length === 0) {
52
+ failed.push({ productId: item.productId, error: NOT_ADDED });
53
+ }
54
+ else {
55
+ added.set(item.productId, (added.get(item.productId) ?? 0) + item.quantity);
56
+ }
57
+ }
58
+ catch (error) {
59
+ onError(error);
60
+ const message = describeError(error);
61
+ failed.push({
62
+ productId: item.productId,
63
+ error: mayHaveChangedCart(error) ? `${message} ${CART_MAY_HAVE_CHANGED}` : message,
64
+ });
65
+ // An error that isn't about this product (the auth key, an outage) hits the rest too.
66
+ if (!isProductError(error)) {
67
+ for (const rest of items.slice(index + 1)) {
68
+ failed.push({
69
+ productId: rest.productId,
70
+ error: "Not tried after the error above.",
71
+ });
72
+ }
73
+ break;
74
+ }
75
+ }
35
76
  }
36
- const unavailableLine = lines.find((line) => line.isUnavailable);
37
- const replacements = unavailableLine
38
- ? await loadReplacements(context, cart, [productId])
77
+ if (!cart || added.size === 0) {
78
+ return errorResult(failed.map((item) => `${item.productId}: ${item.error}`).join("\n") || NOT_ADDED);
79
+ }
80
+ const lines = [...added.keys()].map((id) => linesOf(cart, id));
81
+ const unavailableIds = lines
82
+ .filter((productLines) => productLines.some((line) => line.isUnavailable))
83
+ .map((productLines) => productLines[0].productId);
84
+ const alreadyInCart = lines.some((productLines) => quantityOf(productLines) > (added.get(productLines[0].productId) ?? 0));
85
+ const replacements = unavailableIds.length > 0
86
+ ? await loadReplacements(context, cart, unavailableIds)
39
87
  : undefined;
88
+ const hints = [
89
+ ...(unavailableIds.length > 0 ? [UNAVAILABLE_HINT] : []),
90
+ ...(failed.length > 0 ? ["Some products were not added: see `failed`."] : []),
91
+ ...(alreadyInCart
92
+ ? [
93
+ 'Some products were in the cart already, so quantityInCart is more than was added. If the user asked for a total ("make it 4"), correct it with set_cart_quantity.',
94
+ ]
95
+ : []),
96
+ ];
40
97
  return jsonResult({
41
- ...(unavailableLine && {
42
- next: "The product is in the cart, but it can't be delivered in the selected delivery window. Tell the user, and offer the replacements if there are any.",
98
+ ...(hints.length > 0 && { next: hints.join(" ") }),
99
+ added: lines.map((productLines) => {
100
+ const unavailableLine = productLines.find((line) => line.isUnavailable);
101
+ const id = productLines[0].productId;
102
+ return {
103
+ productId: id,
104
+ name: productLines[0].name,
105
+ quantityInCart: quantityOf(productLines),
106
+ ...(unavailableLine &&
107
+ formatUnavailability(unavailableLine, replacements?.byProduct.get(id))),
108
+ };
43
109
  }),
44
- added: {
45
- productId,
46
- name: lines[0].name,
47
- quantityInCart: quantityOf(lines),
48
- ...(unavailableLine &&
49
- formatUnavailability(unavailableLine, replacements?.byProduct.get(productId))),
50
- },
110
+ ...(failed.length > 0 && { failed }),
51
111
  cart: formatCartSummary(cart, countryCode),
52
- }, { ...imageUrls(context, lines.slice(0, 1)), ...replacements?.images });
112
+ }, {
113
+ ...imageUrls(context, lines.map((productLines) => productLines[0])),
114
+ ...replacements?.images,
115
+ });
53
116
  }, onError, { changesCart: true }));
54
117
  server.registerTool("remove_from_cart", {
55
118
  title: "Remove from cart",
@@ -64,6 +127,47 @@ export function registerCartTools(server, context) {
64
127
  cart: formatCartSummary(cart, countryCode),
65
128
  });
66
129
  }, onError, { changesCart: true }));
130
+ server.registerTool("set_cart_quantity", {
131
+ title: "Set cart quantity",
132
+ description: 'Set how many of a product are in the user\'s Picnic shopping cart, e.g. when the user says "make it 3". ' +
133
+ "0 removes the product. Get the product id from get_cart or search_products. " +
134
+ "Returns the quantity now in the cart and the cart total.",
135
+ inputSchema: z.object({
136
+ productId,
137
+ quantity: z
138
+ .number()
139
+ .int()
140
+ .min(0)
141
+ .max(50)
142
+ .describe("How many should be in the cart. 0 removes the product."),
143
+ }),
144
+ annotations: { readOnlyHint: false, destructiveHint: true, openWorldHint: true },
145
+ }, ({ productId, quantity }) => runTool(async () => {
146
+ let cart = await client.cart.getCart();
147
+ const difference = quantity - quantityOf(linesOf(cart, productId));
148
+ if (difference > 0)
149
+ cart = await client.cart.addProductToCart(productId, difference);
150
+ if (difference < 0)
151
+ cart = await client.cart.removeProductFromCart(productId, -difference);
152
+ const lines = linesOf(cart, productId);
153
+ if (quantity > 0 && lines.length === 0)
154
+ return errorResult(NOT_ADDED);
155
+ const unavailableLine = lines.find((line) => line.isUnavailable);
156
+ const replacements = unavailableLine
157
+ ? await loadReplacements(context, cart, [productId])
158
+ : undefined;
159
+ return jsonResult({
160
+ ...(unavailableLine && { next: UNAVAILABLE_HINT }),
161
+ product: {
162
+ productId,
163
+ ...(lines[0] && { name: lines[0].name }),
164
+ quantityInCart: quantityOf(lines),
165
+ ...(unavailableLine &&
166
+ formatUnavailability(unavailableLine, replacements?.byProduct.get(productId))),
167
+ },
168
+ cart: formatCartSummary(cart, countryCode),
169
+ }, { ...imageUrls(context, lines.slice(0, 1)), ...replacements?.images });
170
+ }, onError, { changesCart: true }));
67
171
  }
68
172
  /** The lines of a product: more than one when it was also added for a recipe. */
69
173
  function linesOf(cart, productId) {
@@ -1 +1 @@
1
- {"version":3,"file":"cart.js","sourceRoot":"","sources":["../../src/tools/cart.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cart.js","sourceRoot":"","sources":["../../src/tools/cart.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC;AAEzB,OAAO,EACL,qBAAqB,EACrB,aAAa,EACb,cAAc,EACd,kBAAkB,GACnB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAExF,OAAO,EAAoB,SAAS,EAAE,MAAM,cAAc,CAAC;AAC3D,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAE/D,sFAAsF;AACtF,MAAM,SAAS,GAAG,EAAE,CAAC;AAErB,MAAM,SAAS,GAAG,mEAAmE,CAAC;AACtF,MAAM,gBAAgB,GACpB,mJAAmJ,CAAC;AAEtJ,MAAM,UAAU,iBAAiB,CAAC,MAAiB,EAAE,OAAoB;IACvE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC;IAEjD,MAAM,CAAC,YAAY,CACjB,UAAU,EACV;QACE,KAAK,EAAE,UAAU;QACjB,WAAW,EACT,wHAAwH;YACxH,+HAA+H;QACjI,WAAW,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE;KACzD,EACD,GAAG,EAAE,CACH,OAAO,CAAC,KAAK,IAAI,EAAE;QACjB,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;QACzC,MAAM,YAAY,GAAG,MAAM,gBAAgB,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;QAC3D,OAAO,UAAU,CAAC,UAAU,CAAC,IAAI,EAAE,WAAW,EAAE,YAAY,CAAC,SAAS,CAAC,EAAE;YACvE,GAAG,SAAS,CAAC,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC;YACjC,GAAG,YAAY,CAAC,MAAM;SACvB,CAAC,CAAC;IACL,CAAC,EAAE,OAAO,CAAC,CACd,CAAC;IAEF,MAAM,CAAC,YAAY,CACjB,aAAa,EACb;QACE,KAAK,EAAE,aAAa;QACpB,WAAW,EACT,+GAA+G;YAC/G,4DAA4D,SAAS,KAAK;YAC1E,8GAA8G;YAC9G,wIAAwI;YACxI,gGAAgG;YAChG,+BAA+B;QACjC,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC;YACpB,KAAK,EAAE,CAAC;iBACL,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;iBACzD,GAAG,CAAC,CAAC,CAAC;iBACN,GAAG,CAAC,SAAS,CAAC;iBACd,QAAQ,CAAC,uEAAuE,CAAC;SACrF,CAAC;QACF,WAAW,EAAE,EAAE,YAAY,EAAE,KAAK,EAAE,eAAe,EAAE,KAAK,EAAE,aAAa,EAAE,IAAI,EAAE;KAClF,EACD,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CACZ,OAAO,CACL,KAAK,IAAI,EAAE;QACT,IAAI,IAAsB,CAAC;QAC3B,8EAA8E;QAC9E,MAAM,KAAK,GAAG,IAAI,GAAG,EAAkB,CAAC;QACxC,MAAM,MAAM,GAA2C,EAAE,CAAC;QAE1D,KAAK,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,IAAI,KAAK,CAAC,OAAO,EAAE,EAAE,CAAC;YAC5C,IAAI,CAAC;gBACH,IAAI,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;gBACzE,IAAI,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;oBAC/C,MAAM,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC;gBAC/D,CAAC;qBAAM,CAAC;oBACN,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC;gBAC9E,CAAC;YACH,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,OAAO,CAAC,KAAK,CAAC,CAAC;gBACf,MAAM,OAAO,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC;gBACrC,MAAM,CAAC,IAAI,CAAC;oBACV,SAAS,EAAE,IAAI,CAAC,SAAS;oBACzB,KAAK,EAAE,kBAAkB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO,IAAI,qBAAqB,EAAE,CAAC,CAAC,CAAC,OAAO;iBACnF,CAAC,CAAC;gBACH,sFAAsF;gBACtF,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,CAAC;oBAC3B,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,EAAE,CAAC;wBAC1C,MAAM,CAAC,IAAI,CAAC;4BACV,SAAS,EAAE,IAAI,CAAC,SAAS;4BACzB,KAAK,EAAE,kCAAkC;yBAC1C,CAAC,CAAC;oBACL,CAAC;oBACD,MAAM;gBACR,CAAC;YACH,CAAC;QACH,CAAC;QAED,IAAI,CAAC,IAAI,IAAI,KAAK,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;YAC9B,OAAO,WAAW,CAChB,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG,IAAI,CAAC,SAAS,KAAK,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,SAAS,CACjF,CAAC;QACJ,CAAC;QAED,MAAM,KAAK,GAAG,CAAC,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC;QAC/D,MAAM,cAAc,GAAG,KAAK;aACzB,MAAM,CAAC,CAAC,YAAY,EAAE,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;aACzE,GAAG,CAAC,CAAC,YAAY,EAAE,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;QACpD,MAAM,aAAa,GAAG,KAAK,CAAC,IAAI,CAC9B,CAAC,YAAY,EAAE,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CACzF,CAAC;QACF,MAAM,YAAY,GAChB,cAAc,CAAC,MAAM,GAAG,CAAC;YACvB,CAAC,CAAC,MAAM,gBAAgB,CAAC,OAAO,EAAE,IAAI,EAAE,cAAc,CAAC;YACvD,CAAC,CAAC,SAAS,CAAC;QAChB,MAAM,KAAK,GAAG;YACZ,GAAG,CAAC,cAAc,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YACxD,GAAG,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,6CAA6C,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YAC7E,GAAG,CAAC,aAAa;gBACf,CAAC,CAAC;oBACE,mKAAmK;iBACpK;gBACH,CAAC,CAAC,EAAE,CAAC;SACR,CAAC;QAEF,OAAO,UAAU,CACf;YACE,GAAG,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;YAClD,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,YAAY,EAAE,EAAE;gBAChC,MAAM,eAAe,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;gBACxE,MAAM,EAAE,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;gBACrC,OAAO;oBACL,SAAS,EAAE,EAAE;oBACb,IAAI,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC,IAAI;oBAC1B,cAAc,EAAE,UAAU,CAAC,YAAY,CAAC;oBACxC,GAAG,CAAC,eAAe;wBACjB,oBAAoB,CAAC,eAAe,EAAE,YAAY,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;iBAC1E,CAAC;YACJ,CAAC,CAAC;YACF,GAAG,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC;YACpC,IAAI,EAAE,iBAAiB,CAAC,IAAI,EAAE,WAAW,CAAC;SAC3C,EACD;YACE,GAAG,SAAS,CACV,OAAO,EACP,KAAK,CAAC,GAAG,CAAC,CAAC,YAAY,EAAE,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAC7C;YACD,GAAG,YAAY,EAAE,MAAM;SACxB,CACF,CAAC;IACJ,CAAC,EACD,OAAO,EACP,EAAE,WAAW,EAAE,IAAI,EAAE,CACtB,CACJ,CAAC;IAEF,MAAM,CAAC,YAAY,CACjB,kBAAkB,EAClB;QACE,KAAK,EAAE,kBAAkB;QACzB,WAAW,EACT,2FAA2F;YAC3F,2DAA2D;QAC7D,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QAClE,WAAW,EAAE,EAAE,YAAY,EAAE,KAAK,EAAE,eAAe,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE;KACjF,EACD,CAAC,EAAE,SAAS,EAAE,QAAQ,EAAE,EAAE,EAAE,CAC1B,OAAO,CACL,KAAK,IAAI,EAAE;QACT,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,qBAAqB,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;QAC1E,OAAO,UAAU,CAAC;YAChB,OAAO,EAAE,EAAE,SAAS,EAAE,cAAc,EAAE,UAAU,CAAC,OAAO,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC,EAAE;YAC5E,IAAI,EAAE,iBAAiB,CAAC,IAAI,EAAE,WAAW,CAAC;SAC3C,CAAC,CAAC;IACL,CAAC,EACD,OAAO,EACP,EAAE,WAAW,EAAE,IAAI,EAAE,CACtB,CACJ,CAAC;IAEF,MAAM,CAAC,YAAY,CACjB,mBAAmB,EACnB;QACE,KAAK,EAAE,mBAAmB;QAC1B,WAAW,EACT,0GAA0G;YAC1G,8EAA8E;YAC9E,0DAA0D;QAC5D,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC;YACpB,SAAS;YACT,QAAQ,EAAE,CAAC;iBACR,MAAM,EAAE;iBACR,GAAG,EAAE;iBACL,GAAG,CAAC,CAAC,CAAC;iBACN,GAAG,CAAC,EAAE,CAAC;iBACP,QAAQ,CAAC,wDAAwD,CAAC;SACtE,CAAC;QACF,WAAW,EAAE,EAAE,YAAY,EAAE,KAAK,EAAE,eAAe,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE;KACjF,EACD,CAAC,EAAE,SAAS,EAAE,QAAQ,EAAE,EAAE,EAAE,CAC1B,OAAO,CACL,KAAK,IAAI,EAAE;QACT,IAAI,IAAI,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;QACvC,MAAM,UAAU,GAAG,QAAQ,GAAG,UAAU,CAAC,OAAO,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC;QACnE,IAAI,UAAU,GAAG,CAAC;YAAE,IAAI,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,gBAAgB,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;QACrF,IAAI,UAAU,GAAG,CAAC;YAChB,IAAI,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,qBAAqB,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC,CAAC;QAEzE,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;QACvC,IAAI,QAAQ,GAAG,CAAC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,WAAW,CAAC,SAAS,CAAC,CAAC;QACtE,MAAM,eAAe,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QACjE,MAAM,YAAY,GAAG,eAAe;YAClC,CAAC,CAAC,MAAM,gBAAgB,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,SAAS,CAAC,CAAC;YACpD,CAAC,CAAC,SAAS,CAAC;QACd,OAAO,UAAU,CACf;YACE,GAAG,CAAC,eAAe,IAAI,EAAE,IAAI,EAAE,gBAAgB,EAAE,CAAC;YAClD,OAAO,EAAE;gBACP,SAAS;gBACT,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;gBACxC,cAAc,EAAE,UAAU,CAAC,KAAK,CAAC;gBACjC,GAAG,CAAC,eAAe;oBACjB,oBAAoB,CAAC,eAAe,EAAE,YAAY,EAAE,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC;aACjF;YACD,IAAI,EAAE,iBAAiB,CAAC,IAAI,EAAE,WAAW,CAAC;SAC3C,EACD,EAAE,GAAG,SAAS,CAAC,OAAO,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,YAAY,EAAE,MAAM,EAAE,CACtE,CAAC;IACJ,CAAC,EACD,OAAO,EACP,EAAE,WAAW,EAAE,IAAI,EAAE,CACtB,CACJ,CAAC;AACJ,CAAC;AAED,iFAAiF;AACjF,SAAS,OAAO,CAAC,IAAU,EAAE,SAAiB;IAC5C,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC;AACnE,CAAC;AAED,SAAS,UAAU,CAAC,KAAqB;IACvC,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,CAAC,GAAG,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC;AAC7D,CAAC"}
@@ -7,14 +7,13 @@ export function registerDeliveryTools(server, context) {
7
7
  const { client, countryCode, onError } = context;
8
8
  server.registerTool("get_deliveries", {
9
9
  title: "Get deliveries",
10
- description: 'Show the user\'s Picnic deliveries: upcoming ones (the default), or the last past ones with when: "past". ' +
10
+ description: 'Show the user\'s Picnic deliveries: with when "upcoming" the ones still to come, with when "past" the last delivered ones, e.g. for "what did I order last time?". ' +
11
11
  "Each has the delivery window, the number of products and the total; an upcoming one also has the expected arrival while the driver is on the way. " +
12
12
  "Set includeProducts to list what was ordered, e.g. to order the same again: show the products and add the ones the user wants with add_to_cart.",
13
13
  inputSchema: z.object({
14
14
  when: z
15
15
  .enum(["upcoming", "past"])
16
- .default("upcoming")
17
- .describe('"upcoming" for deliveries still to come, "past" for the last delivered ones. Default upcoming.'),
16
+ .describe('"upcoming" for deliveries still to come, "past" for orders that were delivered already.'),
18
17
  includeProducts: z
19
18
  .boolean()
20
19
  .default(false)
@@ -30,7 +29,7 @@ export function registerDeliveryTools(server, context) {
30
29
  return jsonResult({
31
30
  next: past
32
31
  ? "The user has no past deliveries."
33
- : "The user has no upcoming deliveries.",
32
+ : 'The user has no upcoming deliveries. For orders delivered already: get_deliveries with when "past".',
34
33
  deliveries: [],
35
34
  });
36
35
  }
@@ -1 +1 @@
1
- {"version":3,"file":"deliveries.js","sourceRoot":"","sources":["../../src/tools/deliveries.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"deliveries.js","sourceRoot":"","sources":["../../src/tools/deliveries.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { McpServer } from "@modelcontextprotocol/server";
2
+ import { type ToolContext } from "./context.js";
3
+ export declare function registerDiscoverTools(server: McpServer, context: ToolContext): void;
@@ -0,0 +1,124 @@
1
+ import * as z from "zod";
2
+ import { formatPromotion, formatTiles } from "../format/discover.js";
3
+ import { imageUrls } from "./context.js";
4
+ import { errorResult, jsonResult, runTool } from "./result.js";
5
+ /** Without a section, this many products and promotions per section, to keep the overview short. */
6
+ const OVERVIEW_PRODUCTS = 2;
7
+ const OVERVIEW_PROMOTIONS = 3;
8
+ /** Without an aisle, this many favorites per aisle. */
9
+ const OVERVIEW_FAVORITES = 5;
10
+ /** At most this many products in a list. */
11
+ const MAX_PRODUCTS = 40;
12
+ export function registerDiscoverTools(server, context) {
13
+ const { client, countryCode, onError } = context;
14
+ const images = (tiles) => imageUrls(context, tiles.map((tile) => ({ productId: tile.id, imageId: tile.imageId })));
15
+ server.registerTool("get_promotions", {
16
+ title: "Get promotions",
17
+ description: "List what is on promotion at Picnic this week. Without input it lists the sections (e.g. per category) with a few products and promotions each. " +
18
+ "Pass a section title for all products and promotions in it, or a promotionId for the products of one promotion. " +
19
+ "Products have ids for add_to_cart.",
20
+ inputSchema: z.object({
21
+ section: z
22
+ .string()
23
+ .trim()
24
+ .min(1)
25
+ .optional()
26
+ .describe("A section title from the overview, e.g. a category. Leave out for the overview."),
27
+ promotionId: z
28
+ .string()
29
+ .trim()
30
+ .regex(/^[\w-]+$/, "Use a promotionId from get_promotions.")
31
+ .optional()
32
+ .describe("A promotionId from get_promotions, for the products of that promotion."),
33
+ }),
34
+ annotations: { readOnlyHint: true, openWorldHint: true },
35
+ }, ({ section, promotionId }) => runTool(async () => {
36
+ if (promotionId) {
37
+ const group = await client.catalog.getPromotionGroup(promotionId);
38
+ const products = group.products.slice(0, MAX_PRODUCTS);
39
+ return jsonResult({
40
+ ...(products.length === 0 && {
41
+ next: "This promotion has no products (any more). Try get_promotions without input.",
42
+ }),
43
+ promotion: group.name,
44
+ products: formatTiles(products, countryCode),
45
+ }, images(products));
46
+ }
47
+ const { sections } = await client.catalog.getPromotions();
48
+ if (section) {
49
+ const found = sections.find((candidate) => candidate.title.toLowerCase() === section.toLowerCase());
50
+ if (!found) {
51
+ return errorResult(`No section "${section}". The sections are: ${sections.map((s) => s.title).join(", ")}.`);
52
+ }
53
+ const products = found.products.slice(0, MAX_PRODUCTS);
54
+ return jsonResult({
55
+ section: found.title,
56
+ products: formatTiles(products, countryCode),
57
+ promotions: found.groups.map(formatPromotion),
58
+ ...(found.groups.length > 0 && {
59
+ next: "For the products of a promotion: get_promotions with its promotionId.",
60
+ }),
61
+ }, images(products));
62
+ }
63
+ const shown = sections.map((candidate) => ({
64
+ section: candidate,
65
+ products: candidate.products.slice(0, OVERVIEW_PRODUCTS),
66
+ }));
67
+ return jsonResult({
68
+ next: "For everything in a section: get_promotions with its title. For the products of a promotion: get_promotions with its promotionId.",
69
+ sections: shown.map(({ section, products }) => ({
70
+ title: section.title,
71
+ products: formatTiles(products, countryCode),
72
+ promotions: section.groups.slice(0, OVERVIEW_PROMOTIONS).map(formatPromotion),
73
+ more: Math.max(0, section.products.length - OVERVIEW_PRODUCTS) +
74
+ Math.max(0, section.groups.length - OVERVIEW_PROMOTIONS),
75
+ })),
76
+ }, images(shown.flatMap(({ products }) => products)));
77
+ }, onError));
78
+ server.registerTool("get_favorites", {
79
+ title: "Get favorites",
80
+ description: 'List the products the user buys at Picnic, per aisle, e.g. for "what do I usually buy?" or to offer products for "my usual groceries". ' +
81
+ "Without input it lists the aisles with a few products each; pass an aisleId for all of the user's products in that aisle. " +
82
+ "Products have ids for add_to_cart; add only the ones the user asks for.",
83
+ inputSchema: z.object({
84
+ aisleId: z
85
+ .string()
86
+ .trim()
87
+ .regex(/^[A-Za-z_]+$/, "Use an aisleId from get_favorites, e.g. DAIRY.")
88
+ .optional()
89
+ .describe("An aisleId from get_favorites, e.g. DAIRY. Leave out for the overview."),
90
+ }),
91
+ annotations: { readOnlyHint: true, openWorldHint: true },
92
+ }, ({ aisleId }) => runTool(async () => {
93
+ if (aisleId) {
94
+ const products = (await client.catalog.getFavoritesInAisle(aisleId.toUpperCase())).slice(0, MAX_PRODUCTS);
95
+ return jsonResult({
96
+ ...(products.length === 0 && {
97
+ next: "No products in this aisle. Use an aisleId from get_favorites without input.",
98
+ }),
99
+ aisleId: aisleId.toUpperCase(),
100
+ products: formatTiles(products, countryCode),
101
+ }, images(products));
102
+ }
103
+ const { aisles } = await client.catalog.getFavorites();
104
+ const shown = aisles
105
+ .filter((aisle) => aisle.products.length > 0)
106
+ .map((aisle) => ({ aisle, products: aisle.products.slice(0, OVERVIEW_FAVORITES) }));
107
+ const others = aisles.filter((aisle) => aisle.products.length === 0);
108
+ return jsonResult({
109
+ next: shown.length > 0
110
+ ? "These are the first products per aisle, from what the user bought before; it isn't a shopping list, so only add the products the user asks for. For all of them, or for the other aisles: get_favorites with the aisleId."
111
+ : "The user has no favorites yet.",
112
+ aisles: shown.map(({ aisle, products }) => ({
113
+ aisleId: aisle.id,
114
+ name: aisle.title,
115
+ products: formatTiles(products, countryCode),
116
+ ...((!aisle.complete || aisle.products.length > products.length) && { more: true }),
117
+ })),
118
+ ...(others.length > 0 && {
119
+ otherAisles: others.map((aisle) => ({ aisleId: aisle.id, name: aisle.title })),
120
+ }),
121
+ }, images(shown.flatMap(({ products }) => products)));
122
+ }, onError));
123
+ }
124
+ //# sourceMappingURL=discover.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discover.js","sourceRoot":"","sources":["../../src/tools/discover.ts"],"names":[],"mappings":"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"}
@@ -1,10 +1,10 @@
1
1
  import type { McpServer } from "@modelcontextprotocol/server";
2
2
  import { type ToolContext } from "./context.js";
3
3
  /** A set of tools that can be turned on together. */
4
- export type ToolGroup = "cart" | "slots" | "product" | "deliveries" | "recipes";
4
+ export type ToolGroup = "cart" | "slots" | "product" | "discover" | "deliveries" | "recipes";
5
5
  /** Every group, in the order the tools are registered. */
6
6
  export declare const TOOL_GROUPS: ToolGroup[];
7
- /** The groups that are on when none are given: the cart flow and read-only product details. */
7
+ /** The groups that are on when none are given: the cart flow and the read-only product tools. */
8
8
  export declare const DEFAULT_TOOL_GROUPS: readonly ToolGroup[];
9
9
  /** Reads a comma-separated list of groups, e.g. "cart,recipes". */
10
10
  export declare function parseToolGroups(value: string): ToolGroup[];
@@ -1,6 +1,7 @@
1
1
  import { registerCartTools } from "./cart.js";
2
2
  import { SEARCH_LANGUAGES } from "./context.js";
3
3
  import { registerDeliveryTools } from "./deliveries.js";
4
+ import { registerDiscoverTools } from "./discover.js";
4
5
  import { registerProductTools } from "./product.js";
5
6
  import { registerRecipeTools } from "./recipes.js";
6
7
  import { registerSearchProducts } from "./search-products.js";
@@ -11,7 +12,7 @@ const GROUPS = {
11
12
  registerSearchProducts(server, context);
12
13
  registerCartTools(server, context);
13
14
  },
14
- instructions: ({ countryCode }) => `To add a product: search_products (query in ${SEARCH_LANGUAGES[countryCode]}), then add_to_cart with the product id. If the search returns choices, ask the user first.`,
15
+ instructions: ({ countryCode }) => `To add products: search_products for each (query in ${SEARCH_LANGUAGES[countryCode]}), then one add_to_cart with all product ids. If a search returns choices, ask the user first. To change a quantity: set_cart_quantity.`,
15
16
  },
16
17
  slots: {
17
18
  register: registerSlotTools,
@@ -21,19 +22,23 @@ const GROUPS = {
21
22
  register: registerProductTools,
22
23
  instructions: () => "For a product's ingredients, allergens or nutrition: get_product.",
23
24
  },
25
+ discover: {
26
+ register: registerDiscoverTools,
27
+ instructions: () => 'For what is on sale: get_promotions. For the products the user usually buys ("my usual groceries"): get_favorites.',
28
+ },
24
29
  deliveries: {
25
30
  register: registerDeliveryTools,
26
31
  instructions: () => 'For orders on their way: get_deliveries. To order the same as before: get_deliveries with when "past" and includeProducts.',
27
32
  },
28
33
  recipes: {
29
34
  register: registerRecipeTools,
30
- instructions: () => "For recipes: search_recipes, get_recipe, then add_recipe_to_cart once the user picked one.",
35
+ instructions: () => "For recipes: search_recipes or get_saved_recipes, get_recipe, then add_recipe_to_cart once the user picked one.",
31
36
  },
32
37
  };
33
38
  /** Every group, in the order the tools are registered. */
34
39
  export const TOOL_GROUPS = Object.keys(GROUPS);
35
- /** The groups that are on when none are given: the cart flow and read-only product details. */
36
- export const DEFAULT_TOOL_GROUPS = ["cart", "slots", "product"];
40
+ /** The groups that are on when none are given: the cart flow and the read-only product tools. */
41
+ export const DEFAULT_TOOL_GROUPS = ["cart", "slots", "product", "discover"];
37
42
  /** Reads a comma-separated list of groups, e.g. "cart,recipes". */
38
43
  export function parseToolGroups(value) {
39
44
  const groups = value
@@ -1 +1 @@
1
- {"version":3,"file":"groups.js","sourceRoot":"","sources":["../../src/tools/groups.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"groups.js","sourceRoot":"","sources":["../../src/tools/groups.ts"],"names":[],"mappings":"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"}
@@ -75,6 +75,43 @@ export function registerRecipeTools(server, context) {
75
75
  cart: formatCartSummary(cart, countryCode),
76
76
  });
77
77
  }, onError, { changesCart: true }));
78
+ server.registerTool("get_saved_recipes", {
79
+ title: "Get saved recipes",
80
+ description: "List the recipes the user saved in the Picnic app. Returns recipe ids for get_recipe and add_recipe_to_cart.",
81
+ annotations: { readOnlyHint: true, openWorldHint: true },
82
+ }, () => runTool(async () => {
83
+ const recipes = (await client.recipe.getSavedRecipes()).map(formatRecipeSummary);
84
+ return jsonResult({
85
+ ...(recipes.length === 0 && {
86
+ next: "The user has no saved recipes. Use search_recipes to find one.",
87
+ }),
88
+ recipes,
89
+ });
90
+ }, onError));
91
+ server.registerTool("save_recipe", {
92
+ title: "Save recipe",
93
+ description: "Save a recipe to the user's saved recipes in the Picnic app, by recipeId or a recipe link the user shared.",
94
+ inputSchema: z.object({ recipeId }),
95
+ annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },
96
+ }, ({ recipeId: link }) => runTool(async () => {
97
+ const recipeId = await resolveRecipeLink(link);
98
+ if (!recipeId)
99
+ return errorResult(NOT_A_RECIPE);
100
+ await client.recipe.saveRecipe(recipeId);
101
+ return jsonResult({ saved: { recipeId } });
102
+ }, onError));
103
+ server.registerTool("unsave_recipe", {
104
+ title: "Unsave recipe",
105
+ description: "Remove a recipe from the user's saved recipes in the Picnic app. Get the recipeId from get_saved_recipes.",
106
+ inputSchema: z.object({ recipeId }),
107
+ annotations: { readOnlyHint: false, destructiveHint: true, openWorldHint: true },
108
+ }, ({ recipeId: link }) => runTool(async () => {
109
+ const recipeId = await resolveRecipeLink(link);
110
+ if (!recipeId)
111
+ return errorResult(NOT_A_RECIPE);
112
+ await client.recipe.unsaveRecipe(recipeId);
113
+ return jsonResult({ unsaved: { recipeId } });
114
+ }, onError));
78
115
  server.registerTool("remove_recipe_from_cart", {
79
116
  title: "Remove recipe from cart",
80
117
  description: "Remove a recipe and the ingredients that were added for it from the user's cart. " +
@@ -1 +1 @@
1
- {"version":3,"file":"recipes.js","sourceRoot":"","sources":["../../src/tools/recipes.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"recipes.js","sourceRoot":"","sources":["../../src/tools/recipes.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import type { CallToolResult } from "@modelcontextprotocol/server";
1
+ import type { CallToolResult, InputRequiredResult } from "@modelcontextprotocol/server";
2
2
  /** The `_meta` key with the image URLs of the products in a result, by product id. */
3
3
  export declare const IMAGES_META_KEY = "picnic-mcp/images";
4
4
  /** Image URLs by product id. */
@@ -14,6 +14,6 @@ export declare function errorResult(message: string): CallToolResult;
14
14
  * the cart, the error says when the change may have gone through anyway, so the model checks the
15
15
  * cart instead of retrying blindly.
16
16
  */
17
- export declare function runTool(run: () => Promise<CallToolResult>, onError: (error: unknown) => void, options?: {
17
+ export declare function runTool<T extends CallToolResult | InputRequiredResult>(run: () => Promise<T>, onError: (error: unknown) => void, options?: {
18
18
  changesCart?: boolean;
19
- }): Promise<CallToolResult>;
19
+ }): Promise<T | CallToolResult>;
@@ -1 +1 @@
1
- {"version":3,"file":"result.js","sourceRoot":"","sources":["../../src/tools/result.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,qBAAqB,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAExF,sFAAsF;AACtF,MAAM,CAAC,MAAM,eAAe,GAAG,mBAAmB,CAAC;AAKnD;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,IAAa,EAAE,MAAM,GAAc,EAAE;IAC9D,OAAO;QACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC;QACvD,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,eAAe,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC;KAChF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,OAAe;IACzC,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AACvE,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,OAAO,CAC3B,GAAkC,EAClC,OAAiC,EACjC,OAAO,GAA8B,EAAE;IAEvC,IAAI,CAAC;QACH,OAAO,MAAM,GAAG,EAAE,CAAC;IACrB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,CAAC;QACf,MAAM,OAAO,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC;QACrC,OAAO,WAAW,CAChB,OAAO,CAAC,WAAW,IAAI,kBAAkB,CAAC,KAAK,CAAC;YAC9C,CAAC,CAAC,GAAG,OAAO,IAAI,qBAAqB,EAAE;YACvC,CAAC,CAAC,OAAO,CACZ,CAAC;IACJ,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"result.js","sourceRoot":"","sources":["../../src/tools/result.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,qBAAqB,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAExF,sFAAsF;AACtF,MAAM,CAAC,MAAM,eAAe,GAAG,mBAAmB,CAAC;AAKnD;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,IAAa,EAAE,MAAM,GAAc,EAAE;IAC9D,OAAO;QACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC;QACvD,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,eAAe,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC;KAChF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,OAAe;IACzC,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AACvE,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,OAAO,CAC3B,GAAqB,EACrB,OAAiC,EACjC,OAAO,GAA8B,EAAE;IAEvC,IAAI,CAAC;QACH,OAAO,MAAM,GAAG,EAAE,CAAC;IACrB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,CAAC;QACf,MAAM,OAAO,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC;QACrC,OAAO,WAAW,CAChB,OAAO,CAAC,WAAW,IAAI,kBAAkB,CAAC,KAAK,CAAC;YAC9C,CAAC,CAAC,GAAG,OAAO,IAAI,qBAAqB,EAAE;YACvC,CAAC,CAAC,OAAO,CACZ,CAAC;IACJ,CAAC;AACH,CAAC"}
@@ -1,3 +1,3 @@
1
- import type { McpServer } from "@modelcontextprotocol/server";
1
+ import { type McpServer } from "@modelcontextprotocol/server";
2
2
  import { type ToolContext } from "./context.js";
3
3
  export declare function registerSearchProducts(server: McpServer, context: ToolContext): void;
@@ -1,3 +1,4 @@
1
+ import { CLIENT_CAPABILITIES_META_KEY, inputRequired, inputResponse, } from "@modelcontextprotocol/server";
1
2
  import * as z from "zod";
2
3
  import { formatProduct } from "../format/products.js";
3
4
  import { listCandidates, matchProducts } from "../match.js";
@@ -5,8 +6,26 @@ import { SEARCH_LANGUAGES, imageUrls } from "./context.js";
5
6
  import { jsonResult, runTool } from "./result.js";
6
7
  /** At most this many products in the output, to keep it short. */
7
8
  const MAX_PRODUCTS = 8;
9
+ /** The key of the choice in the elicitation request and its response. */
10
+ const CHOICE_KEY = "choice";
11
+ /** The option for "none of these" in the choice. */
12
+ const NONE = "none";
13
+ /** The texts of the choice the user sees in their client, in the account's language. */
14
+ const CHOICE_TEXTS = {
15
+ NL: { question: (query) => `Welke "${query}" wil je?`, none: "Geen van deze" },
16
+ DE: { question: (query) => `Welches Produkt für „${query}“?`, none: "Keins davon" },
17
+ FR: { question: (query) => `Quel produit pour « ${query} » ?`, none: "Aucun de ceux-ci" },
18
+ };
8
19
  export function registerSearchProducts(server, context) {
9
20
  const language = SEARCH_LANGUAGES[context.countryCode];
21
+ const canAskUser = (ctx) => {
22
+ const envelope = ctx.mcpReq.envelope;
23
+ const capabilities = envelope?.[CLIENT_CAPABILITIES_META_KEY] ??
24
+ server.server.getClientCapabilities();
25
+ const elicitation = capabilities?.elicitation;
26
+ // An empty elicitation capability means form mode.
27
+ return elicitation !== undefined && (elicitation.form !== undefined || !elicitation.url);
28
+ };
10
29
  server.registerTool("search_products", {
11
30
  title: "Search products",
12
31
  description: "Search the Picnic supermarket for a product and get its id for add_to_cart. " +
@@ -17,7 +36,7 @@ export function registerSearchProducts(server, context) {
17
36
  query: z.string().trim().min(1).describe(`The product to search for, in ${language}.`),
18
37
  }),
19
38
  annotations: { readOnlyHint: true, openWorldHint: true },
20
- }, ({ query }) => runTool(async () => {
39
+ }, ({ query }, ctx) => runTool(async () => {
21
40
  const results = await context.client.catalog.getSearchResults(query);
22
41
  const match = matchProducts(listCandidates(results));
23
42
  const format = (candidates) => candidates.map((candidate) => formatProduct(candidate, context.countryCode));
@@ -25,20 +44,50 @@ export function registerSearchProducts(server, context) {
25
44
  ? { searchedFor: results.correctedQuery }
26
45
  : {};
27
46
  const images = (shown) => imageUrls(context, shown.map(({ tile }) => ({ productId: tile.id, imageId: tile.imageId })));
28
- if (match.type === "best") {
29
- const others = match.others.slice(0, MAX_PRODUCTS - 1);
47
+ const bestMatch = (best, others, next) => {
48
+ const shown = others.slice(0, MAX_PRODUCTS - 1);
30
49
  return jsonResult({
31
50
  ...corrected,
32
- next: "Add bestMatch with add_to_cart, unless the user asked for something else.",
33
- bestMatch: formatProduct(match.best, context.countryCode),
34
- otherResults: format(others),
35
- }, images([match.best, ...others]));
51
+ next,
52
+ bestMatch: formatProduct(best, context.countryCode),
53
+ otherResults: format(shown),
54
+ }, images([best, ...shown]));
55
+ };
56
+ if (match.type === "best") {
57
+ return bestMatch(match.best, match.others, "Add bestMatch with add_to_cart, unless the user asked for something else.");
36
58
  }
37
59
  if (match.type === "choose") {
60
+ // A client that can show a form lets the user pick; the search runs again on its answer.
61
+ if (canAskUser(ctx)) {
62
+ const answer = inputResponse(ctx.mcpReq.inputResponses, CHOICE_KEY);
63
+ if (answer.kind === "missing") {
64
+ return inputRequired({
65
+ inputRequests: {
66
+ [CHOICE_KEY]: inputRequired.elicit({
67
+ message: CHOICE_TEXTS[context.countryCode].question(query),
68
+ requestedSchema: choiceSchema(match.choices, context.countryCode),
69
+ }),
70
+ },
71
+ });
72
+ }
73
+ const picked = answer.kind === "elicit" && answer.action === "accept"
74
+ ? answer.content?.productId
75
+ : undefined;
76
+ if (picked === NONE) {
77
+ return jsonResult({
78
+ ...corrected,
79
+ next: "The user wants none of these products. Ask what they want instead, or search with other words.",
80
+ });
81
+ }
82
+ const chosen = match.choices.find((choice) => choice.tile.id === picked);
83
+ if (chosen) {
84
+ return bestMatch(chosen, candidatesWithout(match, chosen), "The user picked bestMatch: add it with add_to_cart.");
85
+ }
86
+ }
38
87
  const others = match.others.slice(0, MAX_PRODUCTS - match.choices.length);
39
88
  return jsonResult({
40
89
  ...corrected,
41
- next: "No clear match. Ask the user which of the choices they want, then add it with add_to_cart.",
90
+ next: "Ask the user which of the choices they want and wait for the answer. Don't call add_to_cart before the user picked one: there is no clear match.",
42
91
  choices: format(match.choices),
43
92
  otherResults: format(others),
44
93
  }, images([...match.choices, ...others]));
@@ -53,4 +102,29 @@ export function registerSearchProducts(server, context) {
53
102
  }, images(others));
54
103
  }, context.onError));
55
104
  }
105
+ /** The candidates of a choice, without the one the user picked. */
106
+ function candidatesWithout(match, picked) {
107
+ return [...match.choices, ...match.others].filter((candidate) => candidate !== picked);
108
+ }
109
+ /** A form with one choice: each product with its size and price, and "none of these". */
110
+ function choiceSchema(choices, countryCode) {
111
+ const options = choices.map((choice) => {
112
+ const product = formatProduct(choice, countryCode);
113
+ return {
114
+ const: product.productId,
115
+ title: [product.name, product.size, product.price].filter(Boolean).join(" · "),
116
+ };
117
+ });
118
+ return {
119
+ type: "object",
120
+ properties: {
121
+ productId: {
122
+ type: "string",
123
+ title: "Product",
124
+ oneOf: [...options, { const: NONE, title: CHOICE_TEXTS[countryCode].none }],
125
+ },
126
+ },
127
+ required: ["productId"],
128
+ };
129
+ }
56
130
  //# sourceMappingURL=search-products.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"search-products.js","sourceRoot":"","sources":["../../src/tools/search-products.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"search-products.js","sourceRoot":"","sources":["../../src/tools/search-products.ts"],"names":[],"mappings":"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"}
package/dist/types.d.ts CHANGED
@@ -13,3 +13,4 @@ export type DeliverySummary = PicnicClient.Types.delivery.DeliverySummary;
13
13
  export type Delivery = PicnicClient.Types.delivery.Delivery;
14
14
  export type DeliveryPosition = PicnicClient.Types.delivery.DeliveryPosition;
15
15
  export type Recipe = PicnicClient.Types.recipe.Recipe;
16
+ export type PromotionGroup = PicnicClient.Types.catalog.PromotionGroup;
package/package.json CHANGED
@@ -1,7 +1,8 @@
1
1
  {
2
2
  "name": "picnic-mcp",
3
- "version": "0.5.0",
4
- "description": "MCP server for the online supermarket Picnic: search products and manage the cart",
3
+ "mcpName": "io.github.MRVDH/picnic-mcp",
4
+ "version": "1.0.0",
5
+ "description": "MCP server for the online supermarket Picnic: search products, fill the cart and pick a delivery slot",
5
6
  "keywords": [
6
7
  "picnic",
7
8
  "mcp",
@@ -43,11 +44,13 @@
43
44
  "typecheck": "tsc --noEmit",
44
45
  "test": "vitest run",
45
46
  "format": "prettier --write .",
46
- "format:check": "prettier --check ."
47
+ "format:check": "prettier --check .",
48
+ "bundle": "bash scripts/bundle.sh",
49
+ "eval": "tsx eval/run.ts"
47
50
  },
48
51
  "dependencies": {
49
52
  "@modelcontextprotocol/server": "^2.3.1",
50
- "picnic-api": "^5.2.0",
53
+ "picnic-api": "^5.3.0",
51
54
  "zod": "^4.6.7"
52
55
  },
53
56
  "devDependencies": {
@@ -55,6 +58,7 @@
55
58
  "@trivago/prettier-plugin-sort-imports": "^6.0.2",
56
59
  "@types/node": "^26.6.5",
57
60
  "prettier": "^3.9.10",
61
+ "tsx": "^4.23.15",
58
62
  "typescript": "^7.0.2",
59
63
  "vitest": "^5.0.5"
60
64
  }