compare_prices
Compare prices for an item across multiple Vinted country sites simultaneously. Use median, mean, min, max, standard deviation to find the cheapest market.
Instructions
Compare prices for a search query across multiple Vinted country sites simultaneously. Returns median, mean, min, max, standard deviation, and sample count per country along with the local currency. Useful for finding the cheapest market to buy a specific item or understanding cross-border price gaps.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | Item to compare prices for, e.g. "Levi 501 jeans" or "iPhone 14 case" | |
| countries | No | List of country codes to compare. Defaults to all 19 Vinted countries if omitted. | |
| limit | No | Number of listings to sample per country. Higher values give more accurate statistics (max 96). |
Implementation Reference
- src/ops/compare.ts:30-76 (handler)Main handler function `opCompare` that executes the compare_prices tool logic. It fetches items from multiple Vinted country sites in parallel (with concurrency control), computes price statistics (median, mean, min, max, item count) per country, and returns the best buy/sell countries along with arbitrage spread percentage.
export async function opCompare( client: VintedClient, input: { query: string; countries?: Country[]; limit?: number; concurrency?: number }, ): Promise<CompareResult> { if (!input.query?.trim()) throw new Error('query is required'); const countries = input.countries ?? ['fr', 'de', 'it', 'es', 'nl', 'pl']; const limit = input.limit ?? 20; const concurrency = Math.max(1, Math.min(input.concurrency ?? 3, 6)); const fetchOne = async (c: Country): Promise<CountryStats | null> => { try { const items = await searchSlim(client, input.query, c, limit); if (!items.length) return null; const prices = items.map((i) => i.price); return { country: c, itemCount: items.length, currency: items[0].currency, avgPrice: round(prices.reduce((a, b) => a + b, 0) / prices.length), medianPrice: round(median(prices)), minPrice: round(Math.min(...prices)), maxPrice: round(Math.max(...prices)), } satisfies CountryStats; } catch { return null; } }; const results = await runWithConcurrency(countries, concurrency, fetchOne); const stats = results.filter((x): x is CountryStats => x !== null); if (!stats.length) { return { query: input.query, countries: [], bestBuyCountry: null, bestSellCountry: null, arbitrageSpreadPct: 0 }; } const byMedian = [...stats].sort((a, b) => a.medianPrice - b.medianPrice); const lo = byMedian[0]; const hi = byMedian[byMedian.length - 1]; const spread = lo.medianPrice > 0 ? ((hi.medianPrice - lo.medianPrice) / lo.medianPrice) * 100 : 0; return { query: input.query, countries: stats, bestBuyCountry: lo.country, bestSellCountry: hi.country, arbitrageSpreadPct: round(spread), }; } - src/ops/compare.ts:5-21 (schema)Type definitions for `CountryStats` (per-country price statistics with currency) and `CompareResult` (overall result with query, countries stats, best buy/sell countries, and arbitrage spread).
export interface CountryStats { country: Country; itemCount: number; currency: string; avgPrice: number; medianPrice: number; minPrice: number; maxPrice: number; } export interface CompareResult { query: string; countries: CountryStats[]; bestBuyCountry: Country | null; bestSellCountry: Country | null; arbitrageSpreadPct: number; } - src/ops/compare.ts:23-28 (helper)Helper function `median` to compute the median of a numeric array. Also includes `round` (line 78-80) for rounding to 2 decimal places and `runWithConcurrency` (line 82-98) for parallel execution with a concurrency limit.
function median(xs: number[]): number { if (!xs.length) return 0; const s = [...xs].sort((a, b) => a - b); const m = Math.floor(s.length / 2); return s.length % 2 ? s[m] : (s[m - 1] + s[m]) / 2; } - src/mcp.ts:85-97 (registration)MCP tool registration: defines the tool name 'compare_prices', its description, and input JSON schema (query, countries array, limit) in the TOOLS array.
{ name: 'compare_prices', description: 'Compare prices for a search query across multiple Vinted country sites simultaneously. Returns median, mean, min, max, standard deviation, and sample count per country along with the local currency. Useful for finding the cheapest market to buy a specific item or understanding cross-border price gaps.', inputSchema: { type: 'object', properties: { query: { type: 'string', description: 'Item to compare prices for, e.g. "Levi 501 jeans" or "iPhone 14 case"' }, countries: { type: 'array', items: { type: 'string', enum: COUNTRIES }, description: 'List of country codes to compare. Defaults to all 19 Vinted countries if omitted.' }, limit: { type: 'integer', default: 20, description: 'Number of listings to sample per country. Higher values give more accurate statistics (max 96).' }, }, required: ['query'], }, }, - src/mcp.ts:223-223 (handler)Routing: the MCP CallToolRequestSchema handler dispatches 'compare_prices' to call `opCompare(client, args)`.
case 'compare_prices': result = await opCompare(c, a as any); break;