@trustrails/mcp-server 1.0.24 → 1.0.26

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
@@ -66,8 +66,9 @@ Just ask Claude naturally — it will decompose your request into the right quer
66
66
 
67
67
  Claude will search across multiple UK retailers and show you:
68
68
  - Real-time prices & availability
69
- - Direct purchase links
70
- - Then call `get_product` for a product's attributes, description and every offer when you need details
69
+ - Purchase links (trustrails.app/go/ redirects to the retailer, through an affiliate link)
70
+ - Every known structured spec (`attributes`), so products can be compared from the search alone
71
+ - Then `get_product` for your final 1-3 picks, only when you need what search lacks: the retailer's description, or every retailer's offer and buy link (search carries only the best offer's `purchase_url`, cheapest in stock)
71
72
 
72
73
  ---
73
74
 
@@ -75,33 +76,41 @@ Claude will search across multiple UK retailers and show you:
75
76
 
76
77
  ### `search_products`
77
78
 
78
- Search 26,000+ UK electronics products. Returns summary data (title, price, availability, category). For a product's structured `attributes`, the retailer's description and every offer, use `get_product`.
79
+ Search 26,000+ UK electronics products across 7 retailers with price comparison. Prices are in GBP. The tool text tells the assistant to split the request into filters first: brand, category and price go in their own arguments, RAM, storage, screen size, resolution, refresh rate, wattage and Wi-Fi generation go in `constraints`, and only what is left over goes in `query`.
79
80
 
80
81
  **Parameters:**
81
- - `query` (string) - Refinement terms after brand and category are extracted: model lines, series, variants, technology descriptors, or model numbers (e.g., "neo", "ultra", "oled", "WH-1000XM5"). Omit entirely if brand + category alone describe what's needed. Never put brand names, product family names, or prices here — use filters. Query words must appear in the title, except words naming the category ("router" in Networking) and bare numbers or specs ("4070", "16GB"), which are ignored when finding products and only rank them: put a model number with its prefix ("RTX 4070", not "4070") and check each title for it.
82
- - `min_price` (number, optional) - Minimum price in GBP
83
- - `max_price` (number, optional) - Maximum price in GBP
84
- - `brand` (string, optional) - Filter by brand, exact match (e.g., "Sony", "HP", "Apple")
85
- - `category` (string, optional) - Filter by category: Laptops, Desktops, Tablets, Phones, TVs, Monitors, Headphones, Speakers, Cameras, Keyboards, Mice, Printers, Networking, Storage, Gaming, Wearables, Drones, Audio, Cables & Chargers.
86
- - `constraints` (object, optional) - Hard spec requirements, checked per product against its `attributes`: `{"memory_gb":{"gte":24},"storage_gb":{"gte":1000},"screen_in":{"eq":15}}`. Operators `eq`, `gte`, `lte`; a range is `{"gte":..,"lte":..}`. Names and units: `memory_gb` (RAM, GB), `storage_gb` (GB, 1TB = 1000), `screen_in` (inches), `resolution_p` (pixels high: 4K = 2160, QHD = 1440, Full HD = 1080), `refresh_hz` (Hz), `power_w` (W), `wifi_gen` (Wi-Fi generation: 6, 6E = 6.5, 7). On every operator, storage matches within 3% (1TB = 1000–1024GB) and screen size within 0.5 inch; a whole-number screen size N also covers up to N+1 on `eq` and `lte` (`gte` is unchanged); other specs exactly. Wins over the same spec written in `query`. Always set a `category` or `brand` with it. A bad request (unknown name or operator, negative value, a combination nothing can meet such as `gte` above `lte`, or constraints with no category, brand or search words) returns an error listing the valid ones. See [Structured specs](#structured-specs).
87
- - `lite` (boolean, optional) - Return trimmed product objects (reduces payload by ~80%). Always use for LLM integrations.
88
- - `limit` (number, optional) - Maximum products to return (default 50, max 100)
89
- - `sort` (string, optional) - Sort order: `relevance` (default), `price_asc` (cheapest first), `price_desc` (most expensive first). Use `price_asc` when comparing prices. With constraints, matched products still come first.
90
-
91
- **Returns:** Up to 50 products with summary data. With `lite: true`, returns only essential fields (id, title, brand, price, currency, availability, image_url, purchase_url, offer_count and, with constraints, `constraint_status` and the `attributes` of the constrained names).
82
+ - `query` (string, optional) - Refinement terms ONLY: model lines, series, variants, model numbers (e.g. 'neo', 'ultra', 'oled', 'WH-1000XM5', 's25 ultra'). Never a category name (BAD query='tablet', query='smartwatch', query='laptop': set the category filter instead), never a brand name (BAD query='Sony': set the brand filter instead), never a price. Omit entirely when browsing a category or brand: 'show me tablets' = category='Tablets', no query. Query words must appear in the title, except words naming the category ('router' in Networking) and bare numbers or specs ('4070', '16GB'), which are ignored when finding products and only rank them. Put a model number with its prefix ('RTX 4070', not '4070') and check each title for it. Leave out use-case words like gaming, cheap or best.
83
+ - `min_price` (number, optional) - Minimum price in GBP.
84
+ - `max_price` (number, optional) - Maximum price in GBP.
85
+ - `brand` (string, optional) - Filter by brand name (exact match, case-insensitive). Examples: Apple, Samsung, Sony, HP, Dell, Lenovo, Anker, Bose, LG
86
+ - `category` (string, optional) - Filter by product category. Use ONLY these exact values: Laptops, Desktops, Tablets, Phones, TVs, Monitors, Headphones, Speakers, Cameras, Keyboards, Mice, Printers, Networking, Storage, Gaming, Wearables, Drones, Audio, Cables & Chargers. 'Smartphones' is not valid (use 'Phones'), nor is 'Televisions' (use 'TVs'). Gaming headsets are category='Headphones', query='gaming headset': the Gaming category is consoles, controllers and accessories only.
87
+ - `constraints` (object, optional) - Hard spec requirements, checked per product against its `attributes`. Shape `{name: {op: number}}` with op `eq`, `gte` or `lte`; a range is `{gte, lte}`. On every operator, storage matches within 3% and screen size within 0.5 inch; a whole-number screen size N also covers up to N+1 on `eq` and `lte` (`gte` is unchanged); other specs exactly: `gte 1024` accepts a 1TB drive, `eq 22` a 21.5" screen, `eq 13` a 13.6" one, `lte 15` a 15.6" one. Example: `{"memory_gb": {"gte": 24}, "storage_gb": {"gte": 1000}, "screen_in": {"eq": 15}}`. Names and units: `memory_gb` (RAM, GB), `storage_gb` (GB, 1TB = 1000), `screen_in` (inches), `resolution_p` (pixels high: 4K = 2160, QHD = 1440, Full HD = 1080), `refresh_hz` (Hz), `power_w` (W), `wifi_gen` (Wi-Fi generation: 6, 6E = 6.5, 7). A spec written in `query` counts only when it says what it is ('24GB RAM', '1TB', '144Hz', '55"') and means at least, except screen size (that size); a bare '24GB' stays a search word. Explicit constraints win over it. A plain `16GB` or `65W` is `gte`; use `eq` only when the user says exactly, and for screen size. Always set `category` (and brand if known) with constraints: a search of only specs is rejected, as is a bad request (unknown name or operator, negative value, a combination nothing can meet such as `gte` above `lte`); the error lists the valid ones. See [Structured specs](#structured-specs).
88
+ - `lite` (boolean, optional) - Return trimmed product objects with only essential fields (id, title, brand, price, currency, availability, image_url, purchase_url, offer_count, attributes (every known spec as {status, value}, without sources) and, with constraints, constraint_status). Always set to true; it still carries attributes. Use false only for ean, category, provenance or all sources at once.
89
+ - `limit` (number, optional) - Maximum number of products to return (default 50, max 100)
90
+ - `sort` (string, optional) - Sort order: 'relevance' (default), 'price_asc' (in stock first, then cheapest), 'price_desc' (in stock first, then most expensive). With constraints, matched products still come first.
91
+
92
+ **Returns:** `products` and a `total`. Each product carries every known `attributes` spec (a product with no `attributes` key has none of these seven specs known: say so only if the user asked about one): compare specs from these. State the value of a `confirmed` or `inferred` spec; only `conflicting` (retailers disagree) or a missing name (unknown) needs a caveat. With constraints, each product has `constraint_status` per name (`matched`: a retailer's title states a value that meets it; `unverified`: not known to meet it, so never treat it as a match), `total` counts the products that match every constraint, `unverified_total` the unverified ones that passed the other filters, and `excluded_by_constraints` the products whose stated value fails. `candidates_truncated: true` means the first 2,000 candidates in the chosen sort order were checked and more exist: add a brand or category, or a narrower query, and search again. `availability` is `in_stock`, `low_stock`, `out_of_stock` or `unknown` (the retailer gave no stock signal), and with `purchase_url` and `price` it comes from the product's best offer: in stock first, then cheapest. If `offer_count` is above 1, call `get_product` for your final 1-3 picks to compare retailers. Before claiming a saving, read `offers[].title` (from `get_product`): they must name the same model; if they differ, don't claim one. Before recommending any pick, check its title is the product type asked for (not a cable, accessory or adapter).
92
93
 
93
94
  ### `get_product`
94
95
 
95
- Get full details for a single product. Returns structured `attributes` (see [Structured specs](#structured-specs)), `specs.description` (the retailer's own prose, for processor, ports, graphics and anything `attributes` does not cover), stock level, delivery time, and all retailer offers with per-retailer pricing. Use after `search_products` for detailed comparison or recommendations.
96
+ Get full details for a single product by ID. Returns structured `attributes` (see [Structured specs](#structured-specs)), `specs.description` (the retailer's own prose, for processor, GPU, ports, weight, battery and features that `attributes` does not cover), pricing, availability, delivery time, and all retailer offers with per-retailer pricing (`offers[].stock` is a unit count only when the retailer supplies one, otherwise null). Accepts both canonical product IDs and original retailer offer IDs. Use after `search_products` only for your final 1-3 picks, and only when you need what search lacks: details only the description has (if it doesn't give a detail, tell the user it isn't listed), or every retailer's offer and buy link (search carries only the best offer's `purchase_url`, cheapest in stock). Search results already carry `attributes` to compare specs. A pick with `offer_count` 1 needs no call unless the user asked for a description-only detail.
96
97
 
97
98
  **Parameters:**
98
- - `product_id` (string) - The product ID from search results
99
+ - `product_id` (string) - The unique product ID from search results
99
100
 
100
- **Returns:** Complete product with structured `attributes`, `specs` (including the retailer's `specs.description`), pricing across all retailers, and provenance information
101
+ **Returns:** Complete product with structured `attributes`, `specs` (including the retailer's `specs.description`), `offers` sorted in stock first then cheapest, and provenance information
101
102
 
102
103
  ### Structured specs
103
104
 
104
- `get_product` returns `attributes`: structured specs (RAM, storage, screen size, resolution, refresh rate, power, Wi-Fi generation) read from retailer titles when the catalogue is imported, next to `specs`. Each has a `status`, and a spec nobody states is absent (unknown):
105
+ Search results and `get_product` return `attributes`: structured specs (RAM, storage, screen size, resolution, refresh rate, power, Wi-Fi generation) read from retailer titles when the catalogue is imported. Each has a `status`, and a spec nobody states is absent (unknown); a product with no `attributes` key has none of these seven specs known (say so only if the user asked about one). What each call returns:
106
+
107
+ | Call | Returns |
108
+ |------|---------|
109
+ | `search_products` with `lite=true` (what agents should always set) | `id`, `title`, `brand`, `price`, `currency`, `availability`, `image_url`, `purchase_url`, `offer_count`, every known attribute as `{status, value}` (or `{status, values}` when conflicting) without sources, and `constraint_status` when constrained |
110
+ | `search_products` without `lite` | the lite fields plus `ean`, `category`, `product_type`, `provenance` and every attribute with its `sources` |
111
+ | `get_product` | everything, including `specs.description` and dimensions, `offers` and `delivery_time` |
112
+
113
+ Names and units are as in `constraints`. State the value for `confirmed` and `inferred`; only `conflicting` or a missing name needs a caveat. The statuses:
105
114
 
106
115
  - `confirmed`: two or more retailers state the same value.
107
116
  - `inferred`: one retailer's title states it.
@@ -121,7 +130,7 @@ For one Galaxy S26 Ultra, where only JoyBuy states the RAM (12GB) and two retail
121
130
  }
122
131
  ```
123
132
 
124
- Searches with constraints return the constraints applied, `excluded_by_constraints`, `unverified_total`, and a `constraint_status` on each product: `matched` (a retailer's title states a value that meets the constraint) or `unverified` (not known to meet it: never treat as a match, tell the user it is unconfirmed; check `attributes[name]`, where `conflicting` means retailers disagree and missing means unknown). Products whose stated value fails a constraint are left out. A lite result also carries the `status` and value of just the constrained names, without `sources`, so a 64GB laptop is told apart from a 16GB one and disagreeing from unknown.
133
+ Searches with constraints return the constraints applied, `excluded_by_constraints`, `unverified_total`, and a `constraint_status` on each product: `matched` (a retailer's title states a value that meets the constraint) or `unverified` (not known to meet it: never treat as a match, tell the user it is unconfirmed; check `attributes[name]`, where `conflicting` means retailers disagree and missing means unknown). Products whose stated value fails a constraint are left out. A lite result carries the `status` and value of every known spec, without `sources`, so a 64GB laptop is told apart from a 16GB one and disagreeing from unknown.
125
134
 
126
135
  - **Tolerance:** storage within 3% (1TB = 1000–1024GB) and screen size within 0.5 inch, on every operator. Retailers round sizes down, so a whole-number screen size N also covers up to N+1 on `eq` and `lte` (`eq 13` accepts 13.6", `lte 15` accepts 15.6", `gte` is unchanged). Other specs, memory included, are exact.
127
136
  - **Specs in `query`:** only a spec that says what it is counts ("24GB RAM", "1TB", "512GB SSD", "144Hz", `55"`). A bare "24GB" stays a search word. Memory, storage, resolution, refresh rate, power and Wi-Fi mean at least; screen size means that size.
@@ -141,8 +150,8 @@ Search across **26,000+ electronics products** from major UK retailers including
141
150
 
142
151
  **Budget shopping:**
143
152
  ```
144
- "Find gaming laptops under £800"
145
- → category='Laptops', query='gaming', max_price=800, sort='price_asc', lite=true
153
+ "Find laptops with at least 16GB RAM under £800"
154
+ → category='Laptops', constraints={"memory_gb": {"gte": 16}}, max_price=800, sort='price_asc', lite=true
146
155
  ```
147
156
 
148
157
  **Brand search:**
@@ -166,7 +175,7 @@ Search across **26,000+ electronics products** from major UK retailers including
166
175
  **Detailed specs:**
167
176
  ```
168
177
  "Tell me the specs of this laptop"
169
- → get_product(product_id) — returns its structured attributes, the retailer's description and every offer
178
+ → compare specs from search; get_product(product_id) only for description-only details or every offer
170
179
  ```
171
180
 
172
181
  **Price range:**
@@ -197,7 +206,7 @@ Search across **26,000+ electronics products** from major UK retailers including
197
206
  - ✅ **Real-time data** - Product feeds updated twice daily
198
207
  - ✅ **Multiple retailers** - Compare prices in one search
199
208
  - ✅ **Stock information** - See what's actually available to buy
200
- - ✅ **Direct purchase links** - Click through to buy immediately
209
+ - ✅ **Purchase links** - Click through to the retailer to buy (affiliate links)
201
210
  - ✅ **Zero setup** - Works out of the box with shared public key
202
211
  - ✅ **UK-focused** - Optimized for UK electronics shopping
203
212
 
package/dist/index.js CHANGED
@@ -1,15 +1,18 @@
1
1
  #!/usr/bin/env node
2
+ import { readFileSync } from "node:fs";
2
3
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
3
4
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
5
  import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
5
6
  // TrustRails API configuration
6
7
  const API_KEY = process.env.TRUSTRAILS_API_KEY || "mcp-public-2026";
7
8
  const BASE_URL = process.env.TRUSTRAILS_BASE_URL || "https://trustrails.app";
8
- const CONSTRAINT_NAMES = ["memory_gb", "storage_gb", "screen_in", "resolution_p", "refresh_hz", "power_w", "wifi_gen"];
9
+ // package.json sits one level above both src/ and dist/
10
+ const pkg = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf-8"));
11
+ const CONSTRAINT_NAMES = ["memory_gb", "storage_gb", "power_w", "refresh_hz", "resolution_p", "screen_in", "wifi_gen"];
9
12
  // Create server instance
10
13
  const server = new Server({
11
14
  name: "trustrails",
12
- version: "0.1.0",
15
+ version: pkg.version,
13
16
  }, {
14
17
  capabilities: {
15
18
  tools: {},
@@ -35,13 +38,13 @@ async function searchProducts(params) {
35
38
  if (params.category) {
36
39
  searchParams.append("category", params.category);
37
40
  }
38
- if (params.constraints && Object.keys(params.constraints).length > 0) {
41
+ if (params.constraints != null) {
39
42
  searchParams.append("constraints", JSON.stringify(params.constraints));
40
43
  }
41
- if (params.lite) {
44
+ if (params.lite === true) {
42
45
  searchParams.append("lite", "true");
43
46
  }
44
- if (params.limit && params.limit > 0) {
47
+ if (typeof params.limit === "number") {
45
48
  searchParams.append("limit", params.limit.toString());
46
49
  }
47
50
  if (params.sort) {
@@ -68,7 +71,7 @@ async function searchProducts(params) {
68
71
  * Get detailed information about a specific product
69
72
  */
70
73
  async function getProduct(productId) {
71
- const url = `${BASE_URL}/api/product/${productId}`;
74
+ const url = `${BASE_URL}/api/product/${encodeURIComponent(productId)}`;
72
75
  const response = await fetch(url, {
73
76
  headers: {
74
77
  ...(API_KEY && { "Authorization": `Bearer ${API_KEY}` }),
@@ -82,130 +85,122 @@ async function getProduct(productId) {
82
85
  }
83
86
  return await response.json();
84
87
  }
85
- // Handle tool listing
86
- server.setRequestHandler(ListToolsRequestSchema, async () => {
87
- return {
88
- tools: [
89
- {
90
- name: "search_products",
91
- description: "Search 26,000+ deduplicated UK electronics products across multiple retailers with price comparison. " +
92
- "Returns summary data: title, brand, price, availability, category, purchase link, and offer_count. " +
93
- "When offer_count > 1, the product is available from multiple retailers — call get_product for the 1-3 products you will recommend, not for every result, to see all offers. " +
94
- "Searches that pass constraints add constraint_status and the constrained attributes; for every attribute, the retailer's description and all offers, call get_product with the product ID. " +
95
- "Only compare prices and claim savings between offers of the same configuration: if any attribute is `conflicting`, check offers[].title first and never claim a saving between different sizes or configurations. " +
96
- "All prices in GBP. " +
97
- "IMPORTANT RULES: " +
98
- "1) Decompose the user's request: extract brand → brand filter, category → category filter, price → price filters, RAM/storage/screen size/resolution/refresh rate/wattage/Wi-Fi generation → constraints. What remains is the query. " +
99
- " Example: 'Sony headphones under £200' → brand='Sony', category='Headphones', max_price=200, query omitted. " +
100
- " Example: 'MacBook Neo' → brand='Apple', category='Laptops', query='neo'. " +
101
- " Example: 'Samsung QLED TV' → brand='Samsung', category='TVs', query='qled'. " +
102
- " Example: 'Sony WH-1000XM5' → brand='Sony', category='Headphones', query='WH-1000XM5'. " +
103
- "2) DO NOT put brand names, product family names, full product name strings, or prices in the query — use filters. DO put differentiating identifiers: model lines, series, variants, technology descriptors, and model numbers (e.g. 'neo', 'ultra', 'oled', 'qled', 'WH-1000XM5', 's25 ultra'). Any product family name uniquely associated with a brand (e.g. MacBook→Apple, Galaxy→Samsung, ThinkPad→Lenovo) is already implied by brand+category — never put it in query. BAD: query='macbook neo' → GOOD: brand='Apple', category='Laptops', query='neo'. " +
104
- "3) If brand + category alone fully describe what the user wants, omit the query entirely — fewer query words gives cleaner results. " +
105
- "Query words must appear in the title, except words naming the category ('router' in Networking) and bare numbers or specs ('4070', '16GB'), which are ignored when finding products and only rank them. Put a model number with its prefix ('RTX 4070', not '4070') and check each title for it. Leave out use-case words like gaming, cheap or best. " +
106
- "4) Always set lite=true to reduce payload size. " +
107
- "5) If 0 results, try a shorter/broader query or drop filters (but never present a near miss as meeting a requirement). " +
108
- "6) Use get_product for a product's attributes, description and every offer — do not rely on search results for detailed attributes. " +
109
- "AI USAGE PROTOCOL: " +
110
- "For simple browsing, search with lite=true is sufficient. " +
111
- "For specs not in `attributes` (ports, weight, battery), ALWAYS search first, then call get_product on the top 3-5 results and validate against the description before recommending; don't guess them from titles. If specs are missing, state that explicitly. " +
112
- "SPEC REQUIREMENTS: put exact requirements in `constraints`, not in query, and always set `category` (and brand if known) with them: a search of only specs, with no category, brand or search words, is rejected. " +
113
- "If a requirement is ambiguous (e.g. '16GB' could be RAM or storage), ask the user or search without that constraint. " +
114
- "With constraints, every product has `constraint_status` per name: " +
115
- "'matched' = a retailer's title states a value that meets it. 'unverified' = not known to meet it: check `attributes[name]`, where `conflicting` means retailers disagree and missing means unknown. " +
116
- "Never treat 'unverified' as a match or say a product meets a requirement because it was returned: tell the user it is unconfirmed. " +
117
- "Products whose stated value fails are left out (`excluded_by_constraints`). Matched results come first, also with sort='price_asc'. " +
118
- "With constraints, `total` counts the products that match every constraint and `unverified_total` the unverified products that passed the other filters (only some may be in `products`). If `total` is 0, say no product is known to meet every requirement and offer the unverified ones only as unconfirmed. " +
119
- "With lite=true, `attributes` holds only the constrained names, as {status, value} or {status, values} when conflicting: state the value from there, and call get_product for the rest. " +
120
- "If `candidates_truncated` is true, the first 2,000 candidates in the chosen sort order were checked and more exist: add a brand or category, or a narrower query, and search again before saying nothing matches. If the search was already narrowed, tell the user the results may be incomplete. " +
121
- "STOCK AVAILABILITY: When a product is availability: out_of_stock, do not recommend it as a purchase. Instead mention it as a notable alternative — especially if it offers a meaningful price advantage — and suggest the user check back. Example: 'This model is £X cheaper at [retailer] but currently out of stock — worth checking back if you're not in a rush.' Never silently omit out-of-stock results; surface them transparently.",
122
- inputSchema: {
88
+ const TOOLS = [
89
+ {
90
+ name: "search_products",
91
+ description: "HOW TO CALL THIS TOOL — read before every call: " +
92
+ "Decompose the user's request into filters first. Only what's left over goes in query. " +
93
+ "STEP 1: brand name → brand filter. STEP 2: product category → category filter. STEP 3: price → min_price/max_price. STEP 4: RAM, storage, screen size, resolution, refresh rate, wattage, Wi-Fi generation → constraints. STEP 5: what remains → query. " +
94
+ "BAD: query='Sony headphones under £200' | GOOD: brand='Sony', category='Headphones', max_price=200, no query. " +
95
+ "BAD: query='tablet' | GOOD: category='Tablets', no query. " +
96
+ "BAD: query='macbook neo' | GOOD: brand='Apple', category='Laptops', query='neo'. " +
97
+ "BAD: query='Samsung QLED TV' | GOOD: brand='Samsung', category='TVs', query='qled'. " +
98
+ "If brand+category alone cover what the user wants, omit query entirely. " +
99
+ "Only put differentiating terms in query: model lines (neo, ultra, oled), variants, model numbers (WH-1000XM5, s25 ultra). " +
100
+ "Query words must appear in the title, except words naming the category ('router' in Networking) and bare numbers or specs ('4070', '16GB'), which are ignored when finding products and only rank them. Put a model number with its prefix ('RTX 4070', not '4070') and check each title for it. Leave out use-case words like gaming, cheap or best. " +
101
+ "CROSS-CATEGORY NOTE: Gaming headsets → category='Headphones', query='gaming headset'. The Gaming category is consoles/controllers/accessories only. " +
102
+ "Always set lite=true (it still carries `attributes`). If 0 results, broaden the query or drop filters (but never present a near miss as meeting a requirement). " +
103
+ "Searches 26,000+ UK electronics products across 7 retailers with price comparison. Prices are in GBP. Every listing is new (refurbished and used are excluded). " +
104
+ "PRICE COMPARISON: for a final pick with offer_count > 1, get_product returns offers[] (sorted in-stock first, then cheapest): show the cheapest in-stock retailer, the other prices with the difference and the exact saving among in-stock offers. " +
105
+ "Before claiming a saving, read offers[].title (from get_product): they must name the same model; if they differ, don't claim one. Before recommending any pick, check its title is the product type asked for (not a cable, accessory or adapter). " +
106
+ "COMPARING SPECS: compare products from the `attributes` in the search results, not by calling get_product on each. Every spec known for a product is there as {status, value}, or {status, values} when conflicting, without sources; names and units are as in `constraints`. 'confirmed' (two or more retailers state the same value) and 'inferred' (one retailer's title states it) are both the product's spec: state the value. Only `conflicting` (retailers disagree: say so, don't pick one) or a missing name (unknown) needs a caveat. A product with no `attributes` has none of these seven specs known: say so only if the user asked about one. " +
107
+ "Call get_product only for your final 1-3 picks, and only when you need what search lacks: what only the retailer's description has (processor, GPU, ports, weight, battery), or every retailer's offer and buy link (search results carry only the best offer's purchase_url (cheapest in stock)). A pick with offer_count 1 needs no call unless the user asked for a description-only detail. Don't guess those details from titles. " +
108
+ "SPEC REQUIREMENTS: put exact requirements in `constraints`, not in query, and always set `category` (and brand if known) with `constraints`: a search of only specs is rejected. " +
109
+ "If a requirement is ambiguous (e.g. '16GB' could be RAM or storage), ask the user or search without that constraint. " +
110
+ "With constraints, every product has `constraint_status` per name: " +
111
+ "'matched' = a retailer's title states a value that meets it. 'unverified' = not known to meet it: check `attributes[name]`, where `conflicting` means retailers disagree and missing means unknown. " +
112
+ "Never treat 'unverified' as a match or say a product meets a requirement because it was returned: tell the user it is unconfirmed. " +
113
+ "Products whose stated value fails are left out (`excluded_by_constraints`). Matched results come first, also with sort='price_asc'. " +
114
+ "With constraints, `total` counts the products that match every constraint and `unverified_total` the unverified products that passed the other filters (only some may be in `products`). If `total` is 0, say no product is known to meet every requirement and offer the unverified ones only as unconfirmed. " +
115
+ "If `candidates_truncated` is true, the first 2,000 candidates in the chosen sort order were checked and more exist: add a brand or category, or a narrower query, and search again before saying nothing matches. If the search was already narrowed, tell the user the results may be incomplete. " +
116
+ "STOCK: availability is in_stock, low_stock, out_of_stock or unknown (the retailer gave no stock signal: say so, don't assume). When availability is out_of_stock, mention it as an alternative and suggest checking back — do not silently omit it. " +
117
+ "purchase_url is a trustrails.app/go/ redirect through an affiliate link; TrustRails may earn a commission, and the price is the same. " +
118
+ "Colour variants have separate barcodes and are separate products: when price matters, search again without the colour or check other colours of the same model.",
119
+ inputSchema: {
120
+ type: "object",
121
+ properties: {
122
+ query: {
123
+ type: "string",
124
+ description: "Refinement terms ONLY — model lines, series, variants, model numbers (e.g. 'neo', 'ultra', 'oled', 'WH-1000XM5', 's25 ultra'). " +
125
+ "NEVER a category name: BAD query='tablet', query='smartwatch', query='laptop'. Set the category filter instead. " +
126
+ "NEVER a brand name: BAD query='Sony'. Set the brand filter instead. " +
127
+ "NEVER a price. " +
128
+ "Omit entirely when browsing a category or brand — 'show me tablets' = category='Tablets', no query.",
129
+ },
130
+ min_price: {
131
+ type: "number",
132
+ description: "Minimum price in GBP.",
133
+ },
134
+ max_price: {
135
+ type: "number",
136
+ description: "Maximum price in GBP.",
137
+ },
138
+ brand: {
139
+ type: "string",
140
+ description: "Filter by brand name (exact match, case-insensitive). Examples: Apple, Samsung, Sony, HP, Dell, Lenovo, Anker, Bose, LG",
141
+ },
142
+ category: {
143
+ type: "string",
144
+ description: "Filter by product category. Use ONLY these exact values: " +
145
+ "Laptops, Desktops, Tablets, Phones, TVs, Monitors, " +
146
+ "Headphones, Speakers, Cameras, Keyboards, Mice, Printers, Networking, " +
147
+ "Storage, Gaming, Wearables, Drones, Audio, Cables & Chargers. " +
148
+ "NOTE: 'Smartphones' is not valid — use 'Phones'. 'Televisions' is not valid — use 'TVs'.",
149
+ },
150
+ constraints: {
123
151
  type: "object",
124
- properties: {
125
- query: {
126
- type: "string",
127
- description: "Refinement terms after brand and category are extracted. Use for model lines, series names, variants, or model numbers (e.g. 'neo', 'ultra', 'oled', 'qled', 'WH-1000XM5'). " +
128
- "Query words must appear in the title, except words naming the category ('router' in Networking) and bare numbers or specs ('4070', '16GB'), which are ignored when finding products and only rank them: put a model number with its prefix ('RTX 4070', not '4070') and check each title for it. " +
129
- "DO NOT include brand names, product family names, or prices — use filters. " +
130
- "Omit entirely if brand + category fully describe what the user wants.",
131
- },
132
- min_price: {
133
- type: "number",
134
- description: "Minimum price in GBP. Use this instead of putting prices in the query.",
135
- },
136
- max_price: {
137
- type: "number",
138
- description: "Maximum price in GBP. Use this instead of putting prices in the query.",
139
- },
140
- brand: {
141
- type: "string",
142
- description: "Filter by brand name (exact match, case-insensitive). " +
143
- "Use this instead of putting brand names in the query. " +
144
- "Examples: Apple, Samsung, Sony, HP, Dell, Lenovo, Anker, Bose, LG",
145
- },
146
- category: {
147
- type: "string",
148
- description: "Filter by product category. Use ONLY these exact values: " +
149
- "Laptops, Desktops, Tablets, Phones, TVs, Monitors, " +
150
- "Headphones, Speakers, Cameras, Keyboards, Mice, Printers, Networking, " +
151
- "Storage, Gaming, Wearables, Drones, Audio, Cables & Chargers. " +
152
- "NOTE: 'Smartphones' is not valid — use 'Phones'. 'Televisions' is not valid — use 'TVs'.",
153
- },
154
- constraints: {
155
- type: "object",
156
- description: "Hard spec requirements, checked per product against its attributes. Shape {name: {op: number}} with op eq, gte or lte; a range is {gte, lte}. " +
157
- "On every operator, storage matches within 3% and screen size within 0.5 inch; a whole-number screen size N also covers up to N+1 on eq and lte (gte is unchanged); other specs exactly: gte 1024 accepts a 1TB drive, eq 22 a 21.5\" screen, eq 13 a 13.6\" one, lte 15 a 15.6\" one. " +
158
- "Example: {\"memory_gb\": {\"gte\": 24}, \"storage_gb\": {\"gte\": 1000}, \"screen_in\": {\"eq\": 15}}. " +
159
- "Names and units: memory_gb (RAM, GB), storage_gb (GB, 1TB = 1000), screen_in (inches), resolution_p (pixels high: 4K = 2160, QHD = 1440, Full HD = 1080), " +
160
- "refresh_hz (Hz), power_w (W), wifi_gen (Wi-Fi generation: 6, 6E = 6.5, 7). " +
161
- "A spec written in query counts only when it says what it is ('24GB RAM', '1TB', '144Hz', '55\"') and means at least, except screen size (that size); a bare '24GB' stays a search word. Explicit constraints win over it.",
162
- properties: Object.fromEntries(CONSTRAINT_NAMES.map((name) => [
163
- name,
164
- { type: "object", properties: { eq: { type: "number" }, gte: { type: "number" }, lte: { type: "number" } } },
165
- ])),
166
- },
167
- lite: {
168
- type: "boolean",
169
- description: "Return trimmed product objects with only essential fields " +
170
- "(id, title, brand, price, currency, availability, image_url, purchase_url, offer_count and, with constraints, constraint_status and the status and value of the constrained names). " +
171
- "Always set to true unless the user specifically needs full product objects.",
172
- },
173
- limit: {
174
- type: "number",
175
- description: "Maximum number of products to return (default 50, max 100)",
176
- },
177
- sort: {
178
- type: "string",
179
- description: "Sort order: 'relevance' (default), 'price_asc' (cheapest first), 'price_desc' (most expensive first). Use 'price_asc' when comparing prices.",
180
- },
181
- },
152
+ description: "Hard spec requirements, checked per product against its attributes. Shape {name: {op: number}} with op eq, gte or lte; a range is {gte, lte}. " +
153
+ "On every operator, storage matches within 3% and screen size within 0.5 inch; a whole-number screen size N also covers up to N+1 on eq and lte (gte is unchanged); other specs exactly: gte 1024 accepts a 1TB drive, eq 22 a 21.5\" screen, eq 13 a 13.6\" one, lte 15 a 15.6\" one. " +
154
+ "Example: {\"memory_gb\": {\"gte\": 24}, \"storage_gb\": {\"gte\": 1000}, \"screen_in\": {\"eq\": 15}}. " +
155
+ "Names and units: memory_gb (RAM, GB), storage_gb (GB, 1TB = 1000), screen_in (inches), resolution_p (pixels high: 4K = 2160, QHD = 1440, Full HD = 1080), " +
156
+ "refresh_hz (Hz), power_w (W), wifi_gen (Wi-Fi generation: 6, 6E = 6.5, 7). " +
157
+ "A spec written in query counts only when it says what it is ('24GB RAM', '1TB', '144Hz', '55\"') and means at least, except screen size (that size); a bare '24GB' stays a search word. Explicit constraints win over it. A plain '16GB' or '65W' is gte; use eq only when the user says exactly, and for screen size.",
158
+ properties: Object.fromEntries(CONSTRAINT_NAMES.map((name) => [
159
+ name,
160
+ { type: "object", properties: { eq: { type: "number" }, gte: { type: "number" }, lte: { type: "number" } } },
161
+ ])),
162
+ },
163
+ lite: {
164
+ type: "boolean",
165
+ description: "Return trimmed product objects with only essential fields (id, title, brand, price, currency, availability, image_url, purchase_url, offer_count, attributes (every known spec as {status, value}, without sources) and, with constraints, constraint_status). Always set to true; it still carries attributes. Use false only for ean, category, provenance or all sources at once.",
166
+ },
167
+ limit: {
168
+ type: "number",
169
+ description: "Maximum number of products to return (default 50, max 100)",
170
+ },
171
+ sort: {
172
+ type: "string",
173
+ description: "Sort order: 'relevance' (default), 'price_asc' (in stock first, then cheapest), 'price_desc' (in stock first, then most expensive).",
182
174
  },
183
175
  },
184
- {
185
- name: "get_product",
186
- description: "Get full details for a single product by ID. " +
187
- "Returns `attributes`: structured specs read from retailer titles, each name mapping to {status, value, sources}; a conflicting one has values: [{value, sources}] instead of value and sources. " +
188
- "Names and units as in the search constraints argument. status: 'confirmed' = two or more retailers state the same value; 'inferred' = one retailer's title states it; " +
189
- "'conflicting' = retailers state different values (none is picked, tell the user they disagree; a retailer can appear under two values, so read offers[].title to see which listing states which); a missing name = unknown. " +
190
- "Also returns specs.description, the retailer's own prose: use it only for details attributes do not cover (processor, GPU, ports, weight, battery, features). " +
191
- "It can describe another configuration or a maximum ('up to 32GB'), so it never overrides or fills in an attribute: if an attribute is missing or conflicting, that spec is unknown or unconfirmed, and you may mention what the description says only as 'the retailer's description mentions X, unconfirmed'. " +
192
- "It also returns pricing, stock level, delivery time, and all retailer offers with per-retailer pricing. " +
193
- "Accepts both canonical product IDs and original retailer offer IDs. " +
194
- "Use this after search_products to get detailed specs for comparison or recommendations. " +
195
- "Always call this when a user needs precise product attributes, compatibility info, side-by-side comparisons, or price comparison across retailers.",
196
- inputSchema: {
197
- type: "object",
198
- properties: {
199
- product_id: {
200
- type: "string",
201
- description: "The unique product ID",
202
- },
203
- },
204
- required: ["product_id"],
176
+ },
177
+ },
178
+ {
179
+ name: "get_product",
180
+ description: "Get full details for a single product by ID. " +
181
+ "Returns `attributes`: structured specs read from retailer titles, each name mapping to {status, value, sources}; a conflicting one has values: [{value, sources}] instead of value and sources. " +
182
+ "Names and units as in the search constraints argument. status: 'confirmed' = two or more retailers state the same value; 'inferred' = one retailer's title states it; " +
183
+ "'conflicting' = retailers state different values (none is picked, tell the user they disagree; a retailer can appear under two values, so read offers[].title to see which listing states which); a missing name = unknown. " +
184
+ "Also returns specs.description, the retailer's own prose: use it only for details attributes do not cover (processor, GPU, ports, weight, battery, features); if it doesn't give a detail, tell the user it isn't listed. " +
185
+ "It can describe another configuration or a maximum ('up to 32GB'), so it never overrides or fills in an attribute: if an attribute is missing or conflicting, that spec is unknown or unconfirmed, and you may mention what the description says only as 'the retailer's description mentions X, unconfirmed'. " +
186
+ "It also returns pricing, availability, delivery time, and all retailer offers with per-retailer pricing (offers[].stock is a unit count only when the retailer supplies one, otherwise null). " +
187
+ "Accepts both canonical product IDs and original retailer offer IDs. " +
188
+ "Use this after search_products only for your final 1-3 picks, and only when you need what search lacks: details only the description has, or every retailer's offer and buy link. Search results already carry `attributes` to compare specs.",
189
+ inputSchema: {
190
+ type: "object",
191
+ properties: {
192
+ product_id: {
193
+ type: "string",
194
+ description: "The unique product ID from search results",
205
195
  },
206
196
  },
207
- ],
208
- };
197
+ required: ["product_id"],
198
+ },
199
+ },
200
+ ];
201
+ // Handle tool listing
202
+ server.setRequestHandler(ListToolsRequestSchema, async () => {
203
+ return { tools: TOOLS };
209
204
  });
210
205
  // Handle tool execution
211
206
  server.setRequestHandler(CallToolRequestSchema, async (request) => {
@@ -219,7 +214,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
219
214
  content: [
220
215
  {
221
216
  type: "text",
222
- text: JSON.stringify(results, null, 2),
217
+ text: JSON.stringify(results),
223
218
  },
224
219
  ],
225
220
  };
@@ -234,7 +229,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
234
229
  content: [
235
230
  {
236
231
  type: "text",
237
- text: JSON.stringify(product, null, 2),
232
+ text: JSON.stringify(product),
238
233
  },
239
234
  ],
240
235
  };
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "@trustrails/mcp-server",
3
- "version": "1.0.24",
3
+ "version": "1.0.26",
4
4
  "mcpName": "app.trustrails/server",
5
5
  "description": "MCP server for searching UK electronics products across multiple retailers",
6
6
  "type": "module",
7
7
  "bin": {
8
- "trustrails-mcp": "./dist/index.js"
8
+ "trustrails-mcp": "dist/index.js"
9
9
  },
10
10
  "files": [
11
11
  "dist"
@@ -30,7 +30,7 @@
30
30
  "license": "MIT",
31
31
  "repository": {
32
32
  "type": "git",
33
- "url": "https://github.com/james-webdev/trustrails-mcp-server.git"
33
+ "url": "git+https://github.com/james-webdev/trustrails-mcp-server.git"
34
34
  },
35
35
  "dependencies": {
36
36
  "@modelcontextprotocol/sdk": "^1.25.1"