Skip to main content
Glama
pepesto-solutions

Pepesto MCP Server

Official

Pepesto Products (KgToken → real SKUs)

pepesto_products

Map recipe ingredients to supermarket products with live prices and images. Merge items across recipes to reduce waste, and let users pick from multiple matches.

Instructions

Map one or more recipe KgTokens (and an optional manual shopping list) to concrete supermarket products with prices, images, or currency. Items are merged across recipes to reduce waste; multiple matches per ingredient let you (or the user) pick. Show product title, image if available (json property image_url, don't search for external images, skip rendering the Pepesto image if the image has webp extesion)product_id when available linking to an (external) supermarket page (open in a new tab), price, ProductClassification (is_bio, is_frozen, is_substitution) tags. PricePromotion shows if the item is currently on promotion and what's current promo_percentage

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
recipe_kg_tokensYesKgTokens from pepesto_parse or pepesto_suggest.
supermarket_domainYesSupermarket domain or ID, e.g. 'coop.ch', 'tesco.com', 'ah.nl'. See README for the full list.
manual_shopping_listNoFree-text extra items to add (e.g. 'milk, bananas, kitchen towel').

Implementation Reference

  • The handler that executes the tool logic: calls client.post('/products', args) via the runTool helper. This is the actual implementation of pepesto_products.
      async (args) => runTool(() => client.post("/products", args)),
    );
  • The registration function that calls server.registerTool with name 'pepesto_products' and its schema + handler.
    export function registerProductsTool(server: McpServer, client: PepestoClient): void {
      server.registerTool(
        "pepesto_products",
        {
          title: "Pepesto Products (KgToken → real SKUs)",
          description:
            "Map one or more recipe KgTokens (and an optional manual shopping list) to concrete " +
            "supermarket products with prices, images, or currency. Items are " +
            "merged across recipes to reduce waste; multiple matches per ingredient let you (or the " +
            "user) pick. Show product title, image if available (json property `image_url`, don't search for external images, " +
            "skip rendering the Pepesto image if the image has webp extesion)" +
            "product_id when available linking to an (external) supermarket page (open in a new tab), " + 
            "price, ProductClassification (is_bio, is_frozen, is_substitution) tags. PricePromotion " + 
            "shows if the item is currently on promotion and what's current `promo_percentage`",
          inputSchema: {
            recipe_kg_tokens: z
              .array(KgToken)
              .min(1)
              .describe("KgTokens from pepesto_parse or pepesto_suggest."),
            supermarket_domain: SupermarketDomain,
            manual_shopping_list: z
              .string()
              .optional()
              .describe("Free-text extra items to add (e.g. 'milk, bananas, kitchen towel')."),
          },
        },
        async (args) => runTool(() => client.post("/products", args)),
      );
    }
  • Input schema defining the parameters: recipe_kg_tokens (array of KgToken), supermarket_domain, and optional manual_shopping_list.
    inputSchema: {
      recipe_kg_tokens: z
        .array(KgToken)
        .min(1)
        .describe("KgTokens from pepesto_parse or pepesto_suggest."),
      supermarket_domain: SupermarketDomain,
      manual_shopping_list: z
        .string()
        .optional()
        .describe("Free-text extra items to add (e.g. 'milk, bananas, kitchen towel')."),
    },
  • The runTool helper used by the handler — executes the async function, serializes success to JSON, or returns an error ToolResult.
    export async function runTool(fn: () => Promise<unknown>): Promise<ToolResult> {
      try {
        const result = await fn();
        return {
          content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
        };
      } catch (err) {
        const msg =
          err instanceof PepestoApiError
            ? err.message
            : err instanceof Error
            ? `Error: ${err.message}`
            : `Error: ${String(err)}`;
        return {
          content: [{ type: "text", text: msg }],
          isError: true,
        };
      }
    }
  • src/server.ts:26-28 (registration)
    Where registerProductsTool is called, wiring up the pepesto_products tool into the MCP server.
    registerProductsTool(server, client);
    registerCatalogTool(server, client);
    registerCreditsTool(server, client);
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description discloses key behavioral traits: merging items across recipes, multiple matches per ingredient for user selection, output fields (title, image, price, classification, promotion), and specific rendering instructions (skip webp images). However, it does not mention idempotency, rate limits, or authorization requirements.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single paragraph that covers all necessary details without excessive length. It could benefit from bullet points for output fields, but the information is front-loaded with the main purpose in the first sentence.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the absence of an output schema, the description thoroughly explains the return values (title, image, product_id, price, classification, promotion) and the merging/user-picking behavior. It provides sufficient detail for an agent to understand the tool's function and output.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so baseline is 3. The description adds only contextual behavior (merging, picking) but does not enhance parameter semantics beyond what the schema already provides (e.g., examples, source hints).

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb 'Map' and clearly states the resource transformation: KgTokens to supermarket products. It distinguishes itself from sibling tools that handle parsing (pepesto_parse) or suggestion (pepesto_suggest) by focusing on product mapping.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies the tool is used after obtaining KgTokens from pepesto_parse or pepesto_suggest, but it does not provide explicit guidance on when to use this tool versus alternatives, nor does it mention any prerequisites or exclusions.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

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/pepesto-solutions/pepesto-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server