AirShelf.Import into Postman

AirShelf Catalog MCP

Cross-vendor, datasheet-grounded product search for AI agents. Every verified fact carries a receipt so you can see what supports it. Search, compare, and request a quote through one MCP connection.

How it works

Connect an MCP client over Streamable HTTP. No authentication, API key, or local server install is required. The client discovers tools with tools/list and calls them with tools/call. Requests use JSON-RPC 2.0.

Send both headers below. Responses can arrive as server-sent events.

Content-Type: application/json
Accept: application/json, text/event-stream

Connect to the server

Add AirShelf to Claude Code.

claude mcp add --transport http airshelf https://mcp.airshelf.ai/mcp

Or add this server to your client's MCP configuration.

{
  "mcpServers": {
    "airshelf": {
      "type": "http",
      "url": "https://mcp.airshelf.ai/mcp"
    }
  }
}

Cursor and VS Code have one-click setup on the home page.

Tool endpoints

Use the generic endpoint across vendors, or choose a merchant-scoped endpoint.

EndpointScopeTools
https://mcp.airshelf.ai/mcpCross-vendor8
https://mcp.airshelf.ai/toshiba/mcptoshiba5
https://mcp.airshelf.ai/tuco-kids/mcptuco-kids5
https://mcp.airshelf.ai/maison-mugen/mcpmaison-mugen5
https://mcp.airshelf.ai/black-box/mcpblack-box5
https://mcp.airshelf.ai/airshelf/mcpairshelf5
https://mcp.airshelf.ai/cyble/mcpcyble8

Available tools

These tools are available at /mcp.

Examples include fields required by the schema. Read each parameter description for conditions on optional fields. To start research_shopping, supply need. Use research_id to poll an existing job.

Ask the buyer before calling a tool that emails a human. A quote request first emails the buyer for confirmation. The merchant receives nothing until the buyer confirms.

ToolEffect
search_catalogRead
get_productRead
compare_productsRead
explain_productRead
list_merchantsRead
request_quoteEmails a human
find_productsRead
research_shoppingQueues a job

search_catalog

Search product catalog

Search the AirShelf cross-vendor product catalog by natural-language query. The catalog covers industrial-automation, wiring-devices, digital-signage, business-display, mfp, barcode-printer, laser-printer, inkjet-printer, mechanical-keyboards, cybersecurity, threat-intelligence-platform. Industrial-automation and wiring-device rows are indexed by manufacturer part number, so a brand or part number in the query ("Pepperl+Fuchs retroreflective sensor", "IN5409") retrieves more reliably than a bare product type; those rows carry no normalized spec facets, so the `specs` filter does not apply to them. Returns ranked products with prices, specs, and per-row match accounting. Each row includes `unverified_specs`, the normalized spec names that lack claim-level receipts; never use those as decisive facts. Example queries: "tactile mechanical keyboard under $150", "Toshiba A3 colour multifunction device", "industrial barcode printer for a warehouse", "threat-intelligence platform with dark-web monitoring".

Result fields: • canonical_name — the exact catalog name of the product. • spec_absence_note — spec fields absent from this product's golden record (AirShelf's verified product record); null when nothing is missing. • constraint_match_score and matched_criteria — query constraints supported by claim-level receipts. unverified_criteria names matching catalog values that still need confirmation; missing_criteria names values that are absent or conflict. • parsed.price_availability — all_null = true means every returned price is null. For quote-gated B2B pricing, a null price with a quote path is expected rather than an error; query_had_budget reports whether the query carried one. • result.commercial_data — branch on actionable before using price or stock. Observations older than 24 hours are withheld from result.price/result.inStock and retained only as labelled last_observed history. • parsed.weak_match — the response contains an unresolved constraint, query match, or product-identity warning. parsed.unverified_identity_count counts returned names without an identity receipt. parsed.no_match — no product satisfies a hard constraint, and candidates violating it were excluded server-side.

On a miss or near-miss for a specific brand+model the response may also carry a `tier3` block, meaning a real-time lookup for the exact SKU asked about; it can appear alongside fuzzy-neighbour rows. • tier3.status = "resolved" — a single-source reading of the page at tier3.source_url. MPN-confirmed means the live lookup matched the manufacturer part number. Its verification is "live-unverified": confirmed on a live page during this run, but not yet matched to an AirShelf catalog record. A verified row is matched to the catalog record. tier3.cached = true means it came from a recent prior lookup, with fetched_at recording when the page was read. • tier3.status = "abstain" — the lookup could not confirm the product exists as asked, so no specs, price, or availability were established. tier3.guidance describes the quote-request path. • tier3.status = "declined" — an applicable lookup did not run; tier3.reason says why (disabled, rate_limited, daily_cap, negative_cache, error). No specs or availability were established, and none should be inferred. No tier3 block at all means a live lookup was not applicable to this query (no parseable brand+model identity).

Optional `market` (ISO 3166-1 alpha-2, e.g. "TH") excludes catalog rows whose country-specific URL conflicts with the buyer market and scopes tier3 lookup/cache. A remaining global URL is not local-availability proof: parsed.weak_match stays true and unsatisfied_constraints includes market_availability until every returned row has a matching country receipt. "Available in <market>" still does not guarantee stock.

Key parameters

NameRequiredTypeDescription
qYesstringNatural-language query, at most 200 characters. Supports budget hints (e.g. "under $150").
categoryNostringOptional category filter (industrial-automation, wiring-devices, digital-signage, business-display, mfp, barcode-printer, laser-printer, inkjet-printer, mechanical-keyboards, cybersecurity, threat-intelligence-platform)
limitNonumberMax results
marketNostringBuyer market as an assigned ISO 3166-1 alpha-2 country code (e.g. "TH", "AU"). Conflicting country receipts are excluded; global URLs remain market-unverified.
merchantNostringOptional merchant slug (e.g. "toshiba", "cyble") from list_merchants. Scopes the search to that merchant's own shelf, which is a SEPARATE substrate from the cross-vendor catalog: it is reached only when the cross-vendor catalog returns nothing, and its rows carry the merchant's own product data rather than datasheet-extracted golden records. Omit it for cross-vendor search, which is the default and the right choice for "what should I buy".
specsNoobjectHard spec facets, e.g. {"form_factor":"desktop","print_speed_ppm":33}. Filters by exact/range spec match.

Request example

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "search_catalog",
    "arguments": {
      "q": "industrial barcode printer"
    }
  }
}

get_product

Get product details

Get the full golden record (AirShelf's verified product record) and latest price for one catalog product by slug ("<manufacturer>-<model>").

Returns the product's specs and provenance (which page each fact came from), plus canonical_name (its exact catalog name). A field's evidence_sha256 is the SHA-256 of the source document AirShelf archived when it extracted that claim. A caller holding the same bytes can compare the hash to check that the cited document has not changed. AirShelf does not serve those archived bytes, and the hash does not promise they remain retrievable. Branch on commercial_data.actionable before using price or stock: observations older than 24 hours are withheld from latestPrice and retained only as labelled last_observed history. For quote-gated B2B pricing, a null price with a quote path is expected rather than an error. In clients that render MCP Apps the response also draws one product card per call. related_products — relationships extracted from vendor documents (e.g. compatible toner or drum accessories with their source quotes, functional equivalents, supersessions); each entry names the related catalog slug, the relation type, its direction (direction is "from_this" when the relation reads this-product → related-product, "to_this" when it reads related-product → this-product), and the source URL and quote the relation was extracted from.

Key parameters

NameRequiredTypeDescription
slugYesstringComposite slug, e.g. toshiba-b-ex4t1-ts12-qm-r

Request example

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "get_product",
    "arguments": {
      "slug": "toshiba-b-ex4t1-ts12-qm-r"
    }
  }
}

compare_products

Compare products

Compare 2-10 catalog products side-by-side on their datasheet specs. Slugs come from search_catalog and are case-insensitive and dash-tolerant ("e-STUDIO 331AC", "toshiba-e-studio-331ac" and "e-studio331ac" all resolve to the same product).

Returns one item per product with canonical_name and spec_absence_note (spec fields absent from that product's golden record, AirShelf's verified product record). Branch on each item's commercial_data.actionable before using price or stock; stale observations are withheld from action fields. A slug that does not resolve comes back as not_found with a did_you_mean suggestion. The `provenance` option adds the source page and source type already stored with each fact.

Key parameters

NameRequiredTypeDescription
slugsYesarrayCatalog slugs to compare
provenanceNobooleanInclude the stored source page and source type for each fact

Request example

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "compare_products",
    "arguments": {
      "slugs": [
        "toshiba-b-ex4t1-ts12-qm-r",
        "toshiba-bx420d"
      ]
    }
  }
}

explain_product

Explain how a record was built

Explain the evidence behind a catalog row. Returns stored processing stages when available and always returns a golden-record field summary with source coverage. A field's evidence_sha256 is the SHA-256 of the source document AirShelf archived when it extracted that claim. A caller holding the same bytes can compare the hash to check that the cited document has not changed. AirShelf does not serve those archived bytes, and the hash does not promise they remain retrievable. record.scraped_at is the catalog row's scrape time, not a per-claim evidence capture time.

Key parameters

NameRequiredTypeDescription
slugYesstringComposite slug to explain

Request example

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "explain_product",
    "arguments": {
      "slug": "toshiba-b-ex4t1-ts12-qm-r"
    }
  }
}

list_merchants

List merchants

List public AirShelf merchants that have an assigned slug and at least one active product. Internal/demo and empty catalogs are excluded. Returns each merchant's name, slug, and product count; the slug is the `merchant` argument for request_quote.

Key parameters

No parameters.

Request example

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "list_merchants",
    "arguments": {}
  }
}

request_quote

Request a quote from a merchant

Send a quote request for catalog products to a merchant's sales team on behalf of a named buyer.

This is a two-step, double opt-in flow. The first call emails a confirmation link to `contact.email` and returns status "confirmation_required"; no lead exists and no merchant is contacted until the buyer confirms. A later call with the same arguments reports "awaiting_confirmation" while the email is unconfirmed, or "received" with a reference_number after confirmation.

Merchant slugs come from list_merchants. Network-catalog brands that are absent from that list use merchant:"airshelf-network" with brandSlug:"<manufacturer-slug>"; AirShelf routes the confirmed request to that brand.

Key parameters

NameRequiredTypeDescription
merchantYesstringMerchant slug or id (from list_merchants), or "airshelf-network" for network-catalog brands
productsYesarrayCatalog slugs the buyer is interested in
quantityNonumberUnits the buyer wants
contactYesobjectBuyer contact details
notesNostringAny extra context from the buyer
brandSlugNostringManufacturer slug (from search results) — required with merchant:"airshelf-network" so the lead reaches the right brand

Request example

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "request_quote",
    "arguments": {
      "merchant": "toshiba",
      "products": [
        "toshiba-b-ex4t1-ts12-qm-r"
      ],
      "contact": {
        "name": "Example Buyer",
        "email": "buyer@example.com"
      }
    }
  }
}

find_products

Discover and verify products for a need

Discover candidate products for a buyer need. Takes a need in natural language (e.g. "best value home espresso machine", market "TH"), checks the verified catalog first, then uses live web discovery only when the catalog has no candidates. Returns up to 3 candidates with explicit fit accounting.

find_products is the quick candidate-list tool; research_shopping is the full verified-research job. For a specific brand+model, search_catalog is cheaper and returns the same live-lookup block on a miss.

Response fields: • candidates[].verification — "catalog-candidate" for a catalog starting point whose fit still needs checking, or "live-unverified" for a live page read during this run. • candidates[].status — "resolved" means both identity and the parsed buyer constraints were supported by the cited page; "abstain" means identity or need fit could not be established. Inspect constraint_check for matched, conflicting, and unverified requirements. • candidates[].constraint_check.receipts maps each receipt-backed matched requirement to its supporting source URL and trust label. • Candidates come from current web-search results, so they are a sample of what the market offers rather than a ranking. • status at the top level — "no_match" means discovery ran but no candidate was confirmed as satisfying the need; "disabled", "rate_limited", or "unavailable" means no discovery ran.

• live_discovery.status="unavailable" means receipted catalog candidates were returned while live discovery was unavailable.

Optional `market` (ISO 3166-1 alpha-2) biases discovery and marketplace checks toward seller pages serving that country and scopes the lookup cache. "Available in <market>" means the seller page serves that market, not that stock is guaranteed.

Key parameters

NameRequiredTypeDescription
needYesstringThe buyer need in natural language, e.g. "quiet mechanical keyboard for open office" or "best value home espresso machine".
marketNostringBuyer market as ISO 3166-1 alpha-2 country code (e.g. "TH"). Biases discovery and marketplace checks toward seller pages serving that country and scopes the cache; availability is not a stock guarantee.
maxNonumberMax candidates to verify (each costs a live lookup; capped at 3).

Request example

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "find_products",
    "arguments": {
      "need": "industrial barcode printer for a warehouse"
    }
  }
}

research_shopping

Research a considered purchase

research_shopping is the full verified-research job; find_products is the quick candidate-list tool. It runs as a background job and returns status "running" with a research ID while the minutes-long research continues; the same research ID returns the run on later polls until completion. Unsafe medical, legal, financial-advice, and professional-service asks return status "refused" before any work is queued. Completed runs return a researched recommendation with per-claim source receipts, or an explicit refusal when evidence is insufficient. Missing decision details return clarification questions before research starts. `market` biases discovery and marketplace checks toward seller pages serving that country; "available in <market>" means the seller page serves that market, not that stock is guaranteed. Example answer keys include {"budget":"500 USD","market":"US","category":"espresso machine"}.

Key parameters

NameRequiredTypeDescription
needNostringBuyer need in natural language. Required when starting a new research run.
marketNostringBuyer market as an ISO 3166-1 alpha-2 country code. Biases discovery and marketplace checks toward seller pages serving that country; availability is not a stock guarantee.
personaNoenumResearch persona; b2b produces a quotation/RFQ pack.
answersNoobjectAnswers to clarification questions. Set accept_defaults:true to accept budget and market defaults; it does not waive product type, use case, or must-have requirements.
research_idNostringExisting research run identifier to read instead of starting a new run.

Request example

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "research_shopping",
    "arguments": {
      "need": "industrial barcode printer for a warehouse"
    }
  }
}

Merchant endpoints

These tools are shared by every merchant above. Descriptions and examples below use toshiba. Use product slugs returned by search_products on your chosen endpoint. Replace sample contact details only with the buyer's consent.

ToolEffect
search_productsRead
get_productRead
compare_productsRead
find_equivalentsRead
request_quoteEmails a human

search_products

Search this merchant's catalog

Search this merchant's datasheet-grounded B2B catalog by natural-language query. Returns ranked products with specs, and resolves the exact catalog slug for a product named loosely.

Result fields: • canonical_name — the exact catalog name of the product. • spec_absence_note — spec fields absent from this product's golden record; null when nothing is missing. • constraint_match_score — how many of the query's spec constraints the row satisfies.

Each result's commercial_data.actionable must be true before using price or stock; observations older than 24 hours are withheld from action fields and retained only as labelled last_observed history.

parsed.price_availability: all_null = true means every returned price is null, which for this merchant means pricing is quoted on request rather than listed.

parsed.weak_match — the catalog could not satisfy the query's constraints, so the rows are approximate rather than matches. parsed.no_match — no catalog product satisfies a hard constraint, and candidates violating it were excluded server-side.

Key parameters

NameRequiredTypeDescription
qYesstringNatural-language query (max 160 chars), e.g. "industrial barcode printer for warehouse"
budgetNonumberOptional max budget (USD)

Request example

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "search_products",
    "arguments": {
      "q": "what the buyer needs, in their own words"
    }
  }
}

get_product

Get product details

Get the full datasheet-grounded spec for a single product by catalog slug.

Returns the product's golden record, including canonical_name (its exact catalog name). Branch on commercial_data.actionable before using price or stock; stale observations are withheld from latestPrice. In clients that render MCP Apps the response also draws one product card per call. related_products — relationships extracted from vendor documents (e.g. compatible toner or drum accessories with their source quotes); each entry names the related catalog slug, the relation type, its direction (direction is "from_this" when the relation reads this-product → related-product, "to_this" when it reads related-product → this-product), and the source URL and quote the relation was extracted from.

Key parameters

NameRequiredTypeDescription
slugYesstringCatalog slug, e.g. toshiba-b-ex4t1-ts12-qm-r

Request example

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "get_product",
    "arguments": {
      "slug": "toshiba-b-ex4t1-ts12-qm-r"
    }
  }
}

compare_products

Compare products

Compare 2-10 of this merchant's products side-by-side on their datasheet specs. Slugs are case-insensitive and dash-tolerant ('e-STUDIO 331AC', 'toshiba-e-studio-331ac' and 'e-studio331ac' all resolve to the same product).

Returns one item per product with canonical_name and spec_absence_note (spec fields absent from that product's golden record). Branch on each item's commercial_data.actionable before using price or stock; stale observations are withheld from action fields. A slug that does not resolve comes back as not_found with a did_you_mean suggestion.

Key parameters

NameRequiredTypeDescription
slugsYesarrayCatalog slugs to compare

Request example

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "compare_products",
    "arguments": {
      "slugs": [
        "toshiba-b-ex4t1-ts12-qm-r",
        "toshiba-bx420d"
      ]
    }
  }
}

find_equivalents

Find cross-vendor equivalents

Find cross-vendor functional equivalents for a product (e.g. this merchant's equivalent to a competitor SKU). Returns the matching catalog rows, or an error field when the slug has no recorded equivalents.

Key parameters

NameRequiredTypeDescription
slugYesstringCatalog slug to find equivalents for

Request example

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "find_equivalents",
    "arguments": {
      "slug": "toshiba-b-ex4t1-ts12-qm-r"
    }
  }
}

request_quote

Request a quote from this merchant

Send a quote request for this merchant's products to their sales team on behalf of a named buyer.

This is a two-step, double opt-in flow. The first call emails a confirmation link to `contact.email` and returns status "confirmation_required" — at that point no lead exists and the merchant has not been contacted. The buyer opens that email and confirms, and confirming is what sends their details onward. A later call with the same arguments reports where the request stands: "awaiting_confirmation" while the email is unconfirmed, or "received" with a reference_number once the buyer has confirmed.

Key parameters

NameRequiredTypeDescription
productsYesarrayCatalog slugs the buyer is interested in
quantityNonumberUnits the buyer wants
contactYesobjectBuyer contact details
notesNostringAny extra context from the buyer

Request example

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "request_quote",
    "arguments": {
      "products": [
        "toshiba-b-ex4t1-ts12-qm-r"
      ],
      "contact": {
        "name": "Example Buyer",
        "email": "buyer@example.com"
      }
    }
  }
}

Additional tools on /cyble/mcp

No price is disclosed until a corporate-email NDA unlock completes. The pricing tools guide the buyer through verification and NDA acceptance.

ToolEffect
get_pricingEmails a human
request_discountEmails a human
get_sealed_quoteRead

get_pricing

Get NDA-gated pricing

This merchant's prices live in an NDA-gated rate card rather than the public catalog, so catalog rows carry a null price and this tool is where a figure comes from. Retrieve NDA-gated annual list pricing for catalog product slugs.

Access is staged, and the response `status` reports which stage the buyer is at: a corporate work email is required (`nda_required`, `work_email_required`), an NDA link is emailed to that address (`verification_sent`), and the six-character unlock code shown after acceptance is passed back as `unlock_code`. `status` is "ok" only once prices are released, and each entry carries sku, name, unit and annual_price. Values may be masked depending on the merchant's disclosure settings (`masked`). Discounts are not part of this response — those are a human deal-desk decision via request_discount.

Key parameters

NameRequiredTypeDescription
productsYesarrayCatalog slugs to price
currencyNoenumRequested ratecard currency; defaults to KRW for LG and USD otherwise
contact_emailNostringBuyer work email used for verification and NDA acceptance
unlock_codeNostringSix-character code shown after NDA acceptance

Request example

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "get_pricing",
    "arguments": {
      "products": [
        "{{product_slug}}"
      ]
    }
  }
}

request_discount

Request a discount decision

Submit an NDA-entitled discount request to the merchant's human deal desk for a decision.

Returns `status` "escalated" with a `reference` when the request reaches the desk, or "over_ceiling" when it falls outside the desk's approval policy. Neither response discloses the merchant's approval ceiling or any numeric policy detail. Requires the same verified email and unlock code as get_pricing.

Key parameters

NameRequiredTypeDescription
productsYesarrayCatalog slugs to include in the requested quote
proposed_discount_pctYesnumberBuyer-proposed discount percentage in five-point increments
contact_emailNostringVerified buyer work email
unlock_codeNostringSix-character NDA unlock code
currencyNoenumRequested currency; defaults to KRW for LG and USD otherwise
term_monthsNonumberRequested contract term in months
quantity_noteNostringBuyer-supplied quantity or deployment context
justificationNostringBuyer rationale for the requested exception

Request example

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "request_discount",
    "arguments": {
      "products": [
        "{{product_slug}}"
      ],
      "proposed_discount_pct": 5
    }
  }
}

get_sealed_quote

Get the sealed quote

Retrieve the signed, verifiable sealed quote once the deal desk has decided.

Returns `status` "pending_approval" (with `retry_after_seconds` while the desk is still reviewing), "sealed" (with sealed_jws, payload_hash, valid_until and verifier_url), "declined", or "expired". `reference` is optional; without it the latest quote for the verified mailbox is returned.

Key parameters

NameRequiredTypeDescription
contact_emailNostringVerified buyer work email
unlock_codeNostringSix-character NDA unlock code
referenceNostringQuote reference returned by request_discount

Request example

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "get_sealed_quote",
    "arguments": {}
  }
}

Provenance

This abridged get_product response was recorded on September 23, 2026. The VEICHI robot's Payload field carries its value, source quote, trust label, and archived-document hash.

{
  "result": {
    "structuredContent": {
      "product": {
        "slug": "veichi-vcr07-960-series-7kg-960mm-six-axis-robot",
        "goldenRecord": {
          "fields": {
            "Payload": {
              "value": "Rated: 7kg",
              "quote": "Rated: 7kg",
              "source_url": "https://www.veichi.com/product/six-axis-robot-5.html",
              "trust": "catalog-verified",
              "evidence_sha256": "02b252458dd364afe28f2e0d7771c483ec863af377025425c6091572e159ef42"
            }
          }
        }
      }
    }
  }
}

A field's evidence_sha256 is the SHA-256 of the source document AirShelf archived when it extracted that claim. A caller holding the same bytes can compare the hash to check that the cited document has not changed. AirShelf does not serve those archived bytes, and the hash does not promise they remain retrievable.

Read the value alongside its source quote and trust label. A missing receipt leaves a claim unverified. Live lookup results are labelled live-unverified until matched to a catalog record.

Limits and errors

The limit is 120 tool operations per minute per IP. A JSON-RPC batch is charged for the work it asks for, rather than counting as one operation. On HTTP 429, wait for the Retry-After interval before retrying.

Calling get_product with empty arguments produces this validation response. The SDK returns -32602 inside a tool result with isError: true. Supply a product slug from search results, then retry.

{
  "result": {
    "content": [
      {
        "type": "text",
        "text": "MCP error -32602: Input validation error: Invalid arguments for tool get_product: [\n  {\n    \"expected\": \"string\",\n    \"code\": \"invalid_type\",\n    \"path\": [\n      \"slug\"\n    ],\n    \"message\": \"Invalid input: expected string, received undefined\"\n  }\n]"
      }
    ],
    "isError": true
  },
  "jsonrpc": "2.0",
  "id": 1
}