@rbillon59/vinted-mcp-server 0.1.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 +232 -0
- package/dist/api/browser-utils.d.ts +21 -0
- package/dist/api/browser-utils.d.ts.map +1 -0
- package/dist/api/browser-utils.js +64 -0
- package/dist/api/browser-utils.js.map +1 -0
- package/dist/api/client.d.ts +45 -0
- package/dist/api/client.d.ts.map +1 -0
- package/dist/api/client.js +220 -0
- package/dist/api/client.js.map +1 -0
- package/dist/api/session-provider.d.ts +30 -0
- package/dist/api/session-provider.d.ts.map +1 -0
- package/dist/api/session-provider.js +69 -0
- package/dist/api/session-provider.js.map +1 -0
- package/dist/api/types.d.ts +83 -0
- package/dist/api/types.d.ts.map +1 -0
- package/dist/api/types.js +12 -0
- package/dist/api/types.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -0
- package/dist/server.d.ts +3 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +22 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/brands.d.ts +3 -0
- package/dist/tools/brands.d.ts.map +1 -0
- package/dist/tools/brands.js +34 -0
- package/dist/tools/brands.js.map +1 -0
- package/dist/tools/categories.d.ts +3 -0
- package/dist/tools/categories.d.ts.map +1 -0
- package/dist/tools/categories.js +28 -0
- package/dist/tools/categories.js.map +1 -0
- package/dist/tools/item.d.ts +3 -0
- package/dist/tools/item.d.ts.map +1 -0
- package/dist/tools/item.js +155 -0
- package/dist/tools/item.js.map +1 -0
- package/dist/tools/search.d.ts +3 -0
- package/dist/tools/search.d.ts.map +1 -0
- package/dist/tools/search.js +73 -0
- package/dist/tools/search.js.map +1 -0
- package/dist/tools/user-items.d.ts +3 -0
- package/dist/tools/user-items.d.ts.map +1 -0
- package/dist/tools/user-items.js +50 -0
- package/dist/tools/user-items.js.map +1 -0
- package/dist/tools/user.d.ts +3 -0
- package/dist/tools/user.d.ts.map +1 -0
- package/dist/tools/user.js +38 -0
- package/dist/tools/user.js.map +1 -0
- package/dist/utils/cache.d.ts +17 -0
- package/dist/utils/cache.d.ts.map +1 -0
- package/dist/utils/cache.js +65 -0
- package/dist/utils/cache.js.map +1 -0
- package/dist/utils/mcp-error.d.ts +11 -0
- package/dist/utils/mcp-error.d.ts.map +1 -0
- package/dist/utils/mcp-error.js +11 -0
- package/dist/utils/mcp-error.js.map +1 -0
- package/dist/utils/rate-limiter.d.ts +22 -0
- package/dist/utils/rate-limiter.d.ts.map +1 -0
- package/dist/utils/rate-limiter.js +47 -0
- package/dist/utils/rate-limiter.js.map +1 -0
- package/package.json +45 -0
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Browser-based session provider for Vinted.
|
|
3
|
+
*
|
|
4
|
+
* Uses puppeteer-extra with the stealth plugin to solve Cloudflare challenges,
|
|
5
|
+
* extract cookies, and return them for use with regular fetch calls.
|
|
6
|
+
* The browser is launched only during session refresh and closed immediately after.
|
|
7
|
+
*/
|
|
8
|
+
import { buildCookieString, hasSessionCookie, launchStealthBrowser, parseTimeoutEnv, } from "./browser-utils.js";
|
|
9
|
+
const BROWSER_TIMEOUT_MS = 30_000;
|
|
10
|
+
const COOKIE_POLL_INTERVAL_MS = 500;
|
|
11
|
+
function buildConfig(overrides) {
|
|
12
|
+
return {
|
|
13
|
+
timeoutMs: overrides?.timeoutMs ?? parseTimeoutEnv(BROWSER_TIMEOUT_MS),
|
|
14
|
+
executablePath: overrides?.executablePath
|
|
15
|
+
?? process.env["PUPPETEER_EXECUTABLE_PATH"]
|
|
16
|
+
?? "",
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
export class BrowserSessionProvider {
|
|
20
|
+
config;
|
|
21
|
+
browser = null;
|
|
22
|
+
constructor(config) {
|
|
23
|
+
this.config = buildConfig(config);
|
|
24
|
+
}
|
|
25
|
+
async refreshSession(domain) {
|
|
26
|
+
const browser = await launchStealthBrowser(this.config.executablePath);
|
|
27
|
+
this.browser = browser;
|
|
28
|
+
try {
|
|
29
|
+
const page = await browser.newPage();
|
|
30
|
+
const cookie = await this.solveChallenge(page, domain);
|
|
31
|
+
return { cookie, fetchedAt: Date.now() };
|
|
32
|
+
}
|
|
33
|
+
finally {
|
|
34
|
+
await this.closeBrowser();
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
async destroy() {
|
|
38
|
+
await this.closeBrowser();
|
|
39
|
+
}
|
|
40
|
+
async solveChallenge(page, domain) {
|
|
41
|
+
const url = `https://${domain}`;
|
|
42
|
+
await page.goto(url, { waitUntil: "domcontentloaded" });
|
|
43
|
+
const deadline = Date.now() + this.config.timeoutMs;
|
|
44
|
+
while (Date.now() < deadline) {
|
|
45
|
+
const cookies = await page.cookies();
|
|
46
|
+
if (hasSessionCookie(cookies)) {
|
|
47
|
+
return buildCookieString(cookies);
|
|
48
|
+
}
|
|
49
|
+
await new Promise((resolve) => setTimeout(resolve, COOKIE_POLL_INTERVAL_MS));
|
|
50
|
+
}
|
|
51
|
+
throw new Error(`Cloudflare challenge not resolved within ${this.config.timeoutMs}ms for ${domain}`);
|
|
52
|
+
}
|
|
53
|
+
async closeBrowser() {
|
|
54
|
+
if (this.browser) {
|
|
55
|
+
const browser = this.browser;
|
|
56
|
+
this.browser = null;
|
|
57
|
+
try {
|
|
58
|
+
await browser.close();
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
// Browser may already be closed — ignore
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
export function createSessionProvider(config) {
|
|
67
|
+
return new BrowserSessionProvider(config);
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=session-provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-provider.js","sourceRoot":"","sources":["../../src/api/session-provider.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EACL,iBAAiB,EACjB,gBAAgB,EAChB,oBAAoB,EACpB,eAAe,GAChB,MAAM,oBAAoB,CAAC;AAE5B,MAAM,kBAAkB,GAAG,MAAM,CAAC;AAClC,MAAM,uBAAuB,GAAG,GAAG,CAAC;AAiBpC,SAAS,WAAW,CAAC,SAAiC;IACpD,OAAO;QACL,SAAS,EAAE,SAAS,EAAE,SAAS,IAAI,eAAe,CAAC,kBAAkB,CAAC;QACtE,cAAc,EAAE,SAAS,EAAE,cAAc;eACpC,OAAO,CAAC,GAAG,CAAC,2BAA2B,CAAC;eACxC,EAAE;KACR,CAAC;AACJ,CAAC;AAED,MAAM,OAAO,sBAAsB;IAChB,MAAM,CAAkC;IACjD,OAAO,GAAmB,IAAI,CAAC;IAEvC,YAAY,MAA8B;QACxC,IAAI,CAAC,MAAM,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC;IACpC,CAAC;IAED,KAAK,CAAC,cAAc,CAAC,MAAc;QACjC,MAAM,OAAO,GAAG,MAAM,oBAAoB,CAAC,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC;QACvE,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QAEvB,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,OAAO,EAAE,CAAC;YACrC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;YACvD,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;QAC3C,CAAC;gBAAS,CAAC;YACT,MAAM,IAAI,CAAC,YAAY,EAAE,CAAC;QAC5B,CAAC;IACH,CAAC;IAED,KAAK,CAAC,OAAO;QACX,MAAM,IAAI,CAAC,YAAY,EAAE,CAAC;IAC5B,CAAC;IAEO,KAAK,CAAC,cAAc,CAAC,IAAU,EAAE,MAAc;QACrD,MAAM,GAAG,GAAG,WAAW,MAAM,EAAE,CAAC;QAEhC,MAAM,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,kBAAkB,EAAE,CAAC,CAAC;QAExD,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC;QAEpD,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,EAAE,CAAC;YAC7B,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC;YAErC,IAAI,gBAAgB,CAAC,OAAO,CAAC,EAAE,CAAC;gBAC9B,OAAO,iBAAiB,CAAC,OAAO,CAAC,CAAC;YACpC,CAAC;YAED,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,uBAAuB,CAAC,CAAC,CAAC;QAC/E,CAAC;QAED,MAAM,IAAI,KAAK,CACb,4CAA4C,IAAI,CAAC,MAAM,CAAC,SAAS,UAAU,MAAM,EAAE,CACpF,CAAC;IACJ,CAAC;IAEO,KAAK,CAAC,YAAY;QACxB,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACjB,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;YAC7B,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;YACpB,IAAI,CAAC;gBACH,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;YACxB,CAAC;YAAC,MAAM,CAAC;gBACP,yCAAyC;YAC3C,CAAC;QACH,CAAC;IACH,CAAC;CACF;AAED,MAAM,UAAU,qBAAqB,CAAC,MAA8B;IAClE,OAAO,IAAI,sBAAsB,CAAC,MAAM,CAAC,CAAC;AAC5C,CAAC"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vinted API response types.
|
|
3
|
+
* Typed from observed API responses - only includes fields we use.
|
|
4
|
+
*/
|
|
5
|
+
export interface VintedPhoto {
|
|
6
|
+
id: number;
|
|
7
|
+
url: string;
|
|
8
|
+
dominant_color: string;
|
|
9
|
+
is_main: boolean;
|
|
10
|
+
}
|
|
11
|
+
export interface VintedPrice {
|
|
12
|
+
amount: string;
|
|
13
|
+
currency_code: string;
|
|
14
|
+
}
|
|
15
|
+
export interface VintedItemSummary {
|
|
16
|
+
id: number;
|
|
17
|
+
title: string;
|
|
18
|
+
price: string | VintedPrice;
|
|
19
|
+
currency?: string;
|
|
20
|
+
brand_title?: string;
|
|
21
|
+
size_title?: string;
|
|
22
|
+
/** Wardrobe endpoint uses `brand` instead of `brand_title`. */
|
|
23
|
+
brand?: string;
|
|
24
|
+
/** Wardrobe endpoint uses `size` instead of `size_title`. */
|
|
25
|
+
size?: string;
|
|
26
|
+
url: string;
|
|
27
|
+
photo: VintedPhoto | null;
|
|
28
|
+
favourite_count: number;
|
|
29
|
+
view_count: number;
|
|
30
|
+
user: {
|
|
31
|
+
id: number;
|
|
32
|
+
login: string;
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
/** Extract displayable price string from either format. */
|
|
36
|
+
export declare function formatPrice(price: string | VintedPrice, currency?: string): string;
|
|
37
|
+
export interface VintedSearchResponse {
|
|
38
|
+
items: VintedItemSummary[];
|
|
39
|
+
pagination: {
|
|
40
|
+
current_page: number;
|
|
41
|
+
total_pages: number;
|
|
42
|
+
total_entries: number;
|
|
43
|
+
per_page: number;
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
export interface VintedBrand {
|
|
47
|
+
id: number;
|
|
48
|
+
title: string;
|
|
49
|
+
slug: string;
|
|
50
|
+
favourite_count: number;
|
|
51
|
+
item_count: number;
|
|
52
|
+
is_luxury: boolean;
|
|
53
|
+
}
|
|
54
|
+
export interface VintedBrandSearchResponse {
|
|
55
|
+
brands: VintedBrand[];
|
|
56
|
+
}
|
|
57
|
+
export interface VintedCatalog {
|
|
58
|
+
id: number;
|
|
59
|
+
title: string;
|
|
60
|
+
code: string;
|
|
61
|
+
catalogs: VintedCatalog[];
|
|
62
|
+
}
|
|
63
|
+
export interface VintedCatalogResponse {
|
|
64
|
+
catalogs: VintedCatalog[];
|
|
65
|
+
}
|
|
66
|
+
export interface VintedUserProfile {
|
|
67
|
+
user: {
|
|
68
|
+
id: number;
|
|
69
|
+
login: string;
|
|
70
|
+
feedback_reputation: number;
|
|
71
|
+
feedback_count: number;
|
|
72
|
+
positive_feedback_count: number;
|
|
73
|
+
negative_feedback_count: number;
|
|
74
|
+
item_count: number;
|
|
75
|
+
given_item_count: number;
|
|
76
|
+
city: string;
|
|
77
|
+
country_title: string;
|
|
78
|
+
last_loged_on_ts: string;
|
|
79
|
+
created_at: string;
|
|
80
|
+
photo: VintedPhoto | null;
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/api/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,MAAM,CAAC;IACZ,cAAc,EAAE,MAAM,CAAC;IACvB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,GAAG,WAAW,CAAC;IAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,+DAA+D;IAC/D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,6DAA6D;IAC7D,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,WAAW,GAAG,IAAI,CAAC;IAC1B,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE;QACJ,EAAE,EAAE,MAAM,CAAC;QACX,KAAK,EAAE,MAAM,CAAC;KACf,CAAC;CACH;AAED,2DAA2D;AAC3D,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,WAAW,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAKlF;AAED,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,iBAAiB,EAAE,CAAC;IAC3B,UAAU,EAAE;QACV,YAAY,EAAE,MAAM,CAAC;QACrB,WAAW,EAAE,MAAM,CAAC;QACpB,aAAa,EAAE,MAAM,CAAC;QACtB,QAAQ,EAAE,MAAM,CAAC;KAClB,CAAC;CACH;AAED,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,yBAAyB;IACxC,MAAM,EAAE,WAAW,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,aAAa,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,aAAa,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE;QACJ,EAAE,EAAE,MAAM,CAAC;QACX,KAAK,EAAE,MAAM,CAAC;QACd,mBAAmB,EAAE,MAAM,CAAC;QAC5B,cAAc,EAAE,MAAM,CAAC;QACvB,uBAAuB,EAAE,MAAM,CAAC;QAChC,uBAAuB,EAAE,MAAM,CAAC;QAChC,UAAU,EAAE,MAAM,CAAC;QACnB,gBAAgB,EAAE,MAAM,CAAC;QACzB,IAAI,EAAE,MAAM,CAAC;QACb,aAAa,EAAE,MAAM,CAAC;QACtB,gBAAgB,EAAE,MAAM,CAAC;QACzB,UAAU,EAAE,MAAM,CAAC;QACnB,KAAK,EAAE,WAAW,GAAG,IAAI,CAAC;KAC3B,CAAC;CACH"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vinted API response types.
|
|
3
|
+
* Typed from observed API responses - only includes fields we use.
|
|
4
|
+
*/
|
|
5
|
+
/** Extract displayable price string from either format. */
|
|
6
|
+
export function formatPrice(price, currency) {
|
|
7
|
+
if (typeof price === "string") {
|
|
8
|
+
return currency ? `${price} ${currency}` : price;
|
|
9
|
+
}
|
|
10
|
+
return `${price.amount} ${price.currency_code}`;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/api/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAmCH,2DAA2D;AAC3D,MAAM,UAAU,WAAW,CAAC,KAA2B,EAAE,QAAiB;IACxE,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,QAAQ,CAAC,CAAC,CAAC,GAAG,KAAK,IAAI,QAAQ,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC;IACnD,CAAC;IACD,OAAO,GAAG,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,aAAa,EAAE,CAAC;AAClD,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
3
|
+
import { createServer } from "./server.js";
|
|
4
|
+
import { destroyClient } from "./api/client.js";
|
|
5
|
+
async function main() {
|
|
6
|
+
const server = createServer();
|
|
7
|
+
const transport = new StdioServerTransport();
|
|
8
|
+
const shutdown = async () => {
|
|
9
|
+
await destroyClient();
|
|
10
|
+
process.exit(0);
|
|
11
|
+
};
|
|
12
|
+
process.on("SIGINT", () => void shutdown());
|
|
13
|
+
process.on("SIGTERM", () => void shutdown());
|
|
14
|
+
await server.connect(transport);
|
|
15
|
+
}
|
|
16
|
+
main().catch((error) => {
|
|
17
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
18
|
+
process.stderr.write(`Fatal error: ${message}\n`);
|
|
19
|
+
process.exit(1);
|
|
20
|
+
});
|
|
21
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAEhD,KAAK,UAAU,IAAI;IACjB,MAAM,MAAM,GAAG,YAAY,EAAE,CAAC;IAC9B,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAE7C,MAAM,QAAQ,GAAG,KAAK,IAAmB,EAAE;QACzC,MAAM,aAAa,EAAE,CAAC;QACtB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC;IAEF,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,KAAK,QAAQ,EAAE,CAAC,CAAC;IAC5C,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,KAAK,QAAQ,EAAE,CAAC,CAAC;IAE7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;AAClC,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;IAC9B,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACvE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,gBAAgB,OAAO,IAAI,CAAC,CAAC;IAClD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AASpE,wBAAgB,YAAY,IAAI,SAAS,CAexC"}
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { registerSearchTool } from "./tools/search.js";
|
|
3
|
+
import { registerItemTool } from "./tools/item.js";
|
|
4
|
+
import { registerUserTool } from "./tools/user.js";
|
|
5
|
+
import { registerUserItemsTool } from "./tools/user-items.js";
|
|
6
|
+
import { registerBrandsTool } from "./tools/brands.js";
|
|
7
|
+
import { registerCategoriesTool } from "./tools/categories.js";
|
|
8
|
+
export function createServer() {
|
|
9
|
+
const server = new McpServer({
|
|
10
|
+
name: "vinted-mcp-server",
|
|
11
|
+
version: "0.1.0",
|
|
12
|
+
});
|
|
13
|
+
// Read-only tools (always available)
|
|
14
|
+
registerSearchTool(server);
|
|
15
|
+
registerItemTool(server);
|
|
16
|
+
registerUserTool(server);
|
|
17
|
+
registerUserItemsTool(server);
|
|
18
|
+
registerBrandsTool(server);
|
|
19
|
+
registerCategoriesTool(server);
|
|
20
|
+
return server;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAG/D,MAAM,UAAU,YAAY;IAC1B,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;QAC3B,IAAI,EAAE,mBAAmB;QACzB,OAAO,EAAE,OAAO;KACjB,CAAC,CAAC;IAEH,qCAAqC;IACrC,kBAAkB,CAAC,MAAM,CAAC,CAAC;IAC3B,gBAAgB,CAAC,MAAM,CAAC,CAAC;IACzB,gBAAgB,CAAC,MAAM,CAAC,CAAC;IACzB,qBAAqB,CAAC,MAAM,CAAC,CAAC;IAC9B,kBAAkB,CAAC,MAAM,CAAC,CAAC;IAC3B,sBAAsB,CAAC,MAAM,CAAC,CAAC;IAE/B,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"brands.d.ts","sourceRoot":"","sources":["../../src/tools/brands.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAsBpE,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAuB1D"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { getClient } from "../api/client.js";
|
|
3
|
+
import { mcpError } from "../utils/mcp-error.js";
|
|
4
|
+
function formatBrands(data, query) {
|
|
5
|
+
if (data.brands.length === 0) {
|
|
6
|
+
return `No brands found matching "${query}".`;
|
|
7
|
+
}
|
|
8
|
+
const header = `Brands matching "${query}":\n`;
|
|
9
|
+
const brands = data.brands.map((brand) => {
|
|
10
|
+
const parts = [`- **${brand.title}** (ID: ${brand.id})`];
|
|
11
|
+
parts[0] += ` — ${brand.item_count} items`;
|
|
12
|
+
if (brand.is_luxury)
|
|
13
|
+
parts[0] += " [Luxury]";
|
|
14
|
+
return parts.join("");
|
|
15
|
+
});
|
|
16
|
+
return header + brands.join("\n");
|
|
17
|
+
}
|
|
18
|
+
export function registerBrandsTool(server) {
|
|
19
|
+
server.tool("search_brands", "Search for Vinted brand IDs by name. Use the returned IDs with the brand_ids filter in search_items.", {
|
|
20
|
+
query: z.string().min(1).describe("Brand name to search for (e.g., 'Nike', 'Zara')"),
|
|
21
|
+
}, async (params) => {
|
|
22
|
+
try {
|
|
23
|
+
const data = await getClient().get("/brands", { keyword: params.query });
|
|
24
|
+
const text = formatBrands(data, params.query);
|
|
25
|
+
return {
|
|
26
|
+
content: [{ type: "text", text }],
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
return mcpError("Failed to search brands", error);
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=brands.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"brands.js","sourceRoot":"","sources":["../../src/tools/brands.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAE7C,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAEjD,SAAS,YAAY,CAAC,IAA+B,EAAE,KAAa;IAClE,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC7B,OAAO,6BAA6B,KAAK,IAAI,CAAC;IAChD,CAAC;IAED,MAAM,MAAM,GAAG,oBAAoB,KAAK,MAAM,CAAC;IAC/C,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;QACvC,MAAM,KAAK,GAAG,CAAC,OAAO,KAAK,CAAC,KAAK,WAAW,KAAK,CAAC,EAAE,GAAG,CAAC,CAAC;QACzD,KAAK,CAAC,CAAC,CAAC,IAAI,MAAM,KAAK,CAAC,UAAU,QAAQ,CAAC;QAC3C,IAAI,KAAK,CAAC,SAAS;YAAE,KAAK,CAAC,CAAC,CAAC,IAAI,WAAW,CAAC;QAC7C,OAAO,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACxB,CAAC,CAAC,CAAC;IAEH,OAAO,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACpC,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,MAAiB;IAClD,MAAM,CAAC,IAAI,CACT,eAAe,EACf,sGAAsG,EACtG;QACE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,iDAAiD,CAAC;KACrF,EACD,KAAK,EAAE,MAAM,EAAE,EAAE;QACf,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,SAAS,EAAE,CAAC,GAAG,CAChC,SAAS,EACT,EAAE,OAAO,EAAE,MAAM,CAAC,KAAK,EAAE,CAC1B,CAAC;YACF,MAAM,IAAI,GAAG,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;YAE9C,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,CAAC;aAC3C,CAAC;QACJ,CAAC;QAAC,OAAO,KAAc,EAAE,CAAC;YACxB,OAAO,QAAQ,CAAC,yBAAyB,EAAE,KAAK,CAAC,CAAC;QACpD,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"categories.d.ts","sourceRoot":"","sources":["../../src/tools/categories.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAmBpE,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAkB9D"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { getClient } from "../api/client.js";
|
|
2
|
+
import { mcpError } from "../utils/mcp-error.js";
|
|
3
|
+
function formatCatalogs(catalogs, depth = 0) {
|
|
4
|
+
const lines = [];
|
|
5
|
+
const indent = " ".repeat(depth);
|
|
6
|
+
for (const catalog of catalogs) {
|
|
7
|
+
lines.push(`${indent}- **${catalog.title}** (ID: ${catalog.id})`);
|
|
8
|
+
if (catalog.catalogs.length > 0) {
|
|
9
|
+
lines.push(formatCatalogs(catalog.catalogs, depth + 1));
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
return lines.join("\n");
|
|
13
|
+
}
|
|
14
|
+
export function registerCategoriesTool(server) {
|
|
15
|
+
server.tool("get_categories", "Get the Vinted category tree. Use the returned IDs with the catalog_ids filter in search_items.", {}, async () => {
|
|
16
|
+
try {
|
|
17
|
+
const data = await getClient().get("/catalogs");
|
|
18
|
+
const text = "# Vinted Categories\n\n" + formatCatalogs(data.catalogs);
|
|
19
|
+
return {
|
|
20
|
+
content: [{ type: "text", text }],
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
catch (error) {
|
|
24
|
+
return mcpError("Failed to get categories", error);
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=categories.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"categories.js","sourceRoot":"","sources":["../../src/tools/categories.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAE7C,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAEjD,SAAS,cAAc,CAAC,QAAyB,EAAE,QAAgB,CAAC;IAClE,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAElC,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,KAAK,CAAC,IAAI,CAAC,GAAG,MAAM,OAAO,OAAO,CAAC,KAAK,WAAW,OAAO,CAAC,EAAE,GAAG,CAAC,CAAC;QAClE,IAAI,OAAO,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAChC,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,QAAQ,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC;QAC1D,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,MAAiB;IACtD,MAAM,CAAC,IAAI,CACT,gBAAgB,EAChB,iGAAiG,EACjG,EAAE,EACF,KAAK,IAAI,EAAE;QACT,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,SAAS,EAAE,CAAC,GAAG,CAAwB,WAAW,CAAC,CAAC;YACvE,MAAM,IAAI,GAAG,yBAAyB,GAAG,cAAc,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YAEvE,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,CAAC;aAC3C,CAAC;QACJ,CAAC;QAAC,OAAO,KAAc,EAAE,CAAC;YACxB,OAAO,QAAQ,CAAC,0BAA0B,EAAE,KAAK,CAAC,CAAC;QACrD,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"item.d.ts","sourceRoot":"","sources":["../../src/tools/item.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AA2KpE,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAwCxD"}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { getClient } from "../api/client.js";
|
|
3
|
+
import { mcpError } from "../utils/mcp-error.js";
|
|
4
|
+
function extractJsonLd(html) {
|
|
5
|
+
const match = html.match(/<script type="application\/ld\+json"[^>]*>([\s\S]*?)<\/script>/);
|
|
6
|
+
if (!match?.[1])
|
|
7
|
+
return null;
|
|
8
|
+
try {
|
|
9
|
+
const data = JSON.parse(match[1]);
|
|
10
|
+
if (typeof data === "object" && data !== null && data["@type"] === "Product") {
|
|
11
|
+
return data;
|
|
12
|
+
}
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
function extractOgMeta(html, property) {
|
|
20
|
+
// Handle both attribute orders: property then content, or content then property
|
|
21
|
+
const patterns = [
|
|
22
|
+
new RegExp(`<meta\\s+(?:property|name)="${property}"\\s+content="([^"]*)"`, "i"),
|
|
23
|
+
new RegExp(`<meta\\s+content="([^"]*)"\\s+(?:property|name)="${property}"`, "i"),
|
|
24
|
+
];
|
|
25
|
+
for (const re of patterns) {
|
|
26
|
+
const match = html.match(re);
|
|
27
|
+
if (match?.[1])
|
|
28
|
+
return match[1];
|
|
29
|
+
}
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Extract RSC plugin data using indexOf-based search instead of backtrack-heavy regex.
|
|
34
|
+
*/
|
|
35
|
+
function extractRscPlugins(html) {
|
|
36
|
+
const plugins = [];
|
|
37
|
+
const markers = ['"name":"attributes"', '"name":"description"', '"name":"summary"'];
|
|
38
|
+
let searchStart = 0;
|
|
39
|
+
for (;;) {
|
|
40
|
+
let earliest = -1;
|
|
41
|
+
for (const marker of markers) {
|
|
42
|
+
const idx = html.indexOf(marker, searchStart);
|
|
43
|
+
if (idx !== -1 && (earliest === -1 || idx < earliest)) {
|
|
44
|
+
earliest = idx;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
if (earliest === -1)
|
|
48
|
+
break;
|
|
49
|
+
// Walk backwards to find the opening brace
|
|
50
|
+
const openBrace = html.lastIndexOf("{", earliest);
|
|
51
|
+
if (openBrace === -1) {
|
|
52
|
+
searchStart = earliest + 1;
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
// Walk forward counting braces to find the matching close
|
|
56
|
+
let depth = 0;
|
|
57
|
+
let end = -1;
|
|
58
|
+
for (let i = openBrace; i < html.length; i++) {
|
|
59
|
+
if (html[i] === "{")
|
|
60
|
+
depth++;
|
|
61
|
+
else if (html[i] === "}")
|
|
62
|
+
depth--;
|
|
63
|
+
if (depth === 0) {
|
|
64
|
+
end = i + 1;
|
|
65
|
+
break;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
if (end === -1) {
|
|
69
|
+
searchStart = earliest + 1;
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
const candidate = html.slice(openBrace, end);
|
|
73
|
+
try {
|
|
74
|
+
const plugin = JSON.parse(candidate);
|
|
75
|
+
if (typeof plugin === "object" && plugin !== null && "name" in plugin && "data" in plugin) {
|
|
76
|
+
plugins.push(plugin);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
// Malformed JSON — skip
|
|
81
|
+
}
|
|
82
|
+
searchStart = end;
|
|
83
|
+
}
|
|
84
|
+
return plugins;
|
|
85
|
+
}
|
|
86
|
+
const CONDITION_MAP = {
|
|
87
|
+
NewCondition: "New",
|
|
88
|
+
UsedCondition: "Used",
|
|
89
|
+
RefurbishedCondition: "Refurbished",
|
|
90
|
+
};
|
|
91
|
+
function formatCondition(condition) {
|
|
92
|
+
if (!condition)
|
|
93
|
+
return "Unknown";
|
|
94
|
+
const bare = condition.replace("https://schema.org/", "");
|
|
95
|
+
return CONDITION_MAP[bare] ?? bare;
|
|
96
|
+
}
|
|
97
|
+
function buildItemDetail(itemId, jsonLd, ogDescription, rscPlugins, itemUrl) {
|
|
98
|
+
const lines = [];
|
|
99
|
+
const title = jsonLd?.name ?? `Item ${itemId}`;
|
|
100
|
+
lines.push(`# ${title}`);
|
|
101
|
+
if (jsonLd?.offers) {
|
|
102
|
+
lines.push(`**Price:** ${jsonLd.offers.price} ${jsonLd.offers.priceCurrency ?? "EUR"}`);
|
|
103
|
+
lines.push(`**Condition:** ${formatCondition(jsonLd.offers.itemCondition)}`);
|
|
104
|
+
}
|
|
105
|
+
const attrPlugin = rscPlugins.find((p) => p.name === "attributes");
|
|
106
|
+
if (attrPlugin?.data.attributes) {
|
|
107
|
+
for (const attr of attrPlugin.data.attributes) {
|
|
108
|
+
if (attr.data.title && attr.data.value) {
|
|
109
|
+
lines.push(`**${attr.data.title}:** ${attr.data.value}`);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
lines.push("");
|
|
114
|
+
const descPlugin = rscPlugins.find((p) => p.name === "description");
|
|
115
|
+
const description = descPlugin?.data.description ?? ogDescription;
|
|
116
|
+
if (description) {
|
|
117
|
+
lines.push("## Description");
|
|
118
|
+
lines.push(description);
|
|
119
|
+
lines.push("");
|
|
120
|
+
}
|
|
121
|
+
if (jsonLd?.image && jsonLd.image.length > 0) {
|
|
122
|
+
lines.push(`## Photos (${jsonLd.image.length})`);
|
|
123
|
+
jsonLd.image.forEach((url, i) => {
|
|
124
|
+
lines.push(`${i + 1}. ${url}`);
|
|
125
|
+
});
|
|
126
|
+
lines.push("");
|
|
127
|
+
}
|
|
128
|
+
lines.push(`**URL:** ${itemUrl}`);
|
|
129
|
+
return lines.join("\n");
|
|
130
|
+
}
|
|
131
|
+
export function registerItemTool(server) {
|
|
132
|
+
server.tool("get_item_details", "Get detailed information about a specific Vinted item including description, photos, seller info, and condition.", {
|
|
133
|
+
item_id: z.number().int().positive().describe("The Vinted item ID (from search results)"),
|
|
134
|
+
}, async (params) => {
|
|
135
|
+
try {
|
|
136
|
+
const client = getClient();
|
|
137
|
+
const itemUrl = `${client.baseUrl}/items/${params.item_id}`;
|
|
138
|
+
const html = await client.getHtml(itemUrl);
|
|
139
|
+
const jsonLd = extractJsonLd(html);
|
|
140
|
+
const ogDescription = extractOgMeta(html, "og:description");
|
|
141
|
+
const rscPlugins = extractRscPlugins(html);
|
|
142
|
+
if (!jsonLd && rscPlugins.length === 0) {
|
|
143
|
+
return mcpError("Failed to get item details", new Error("Could not extract item data (page may require authentication or Cloudflare challenge)"));
|
|
144
|
+
}
|
|
145
|
+
const text = buildItemDetail(params.item_id, jsonLd, ogDescription, rscPlugins, itemUrl);
|
|
146
|
+
return {
|
|
147
|
+
content: [{ type: "text", text }],
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
catch (error) {
|
|
151
|
+
return mcpError("Failed to get item details", error);
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
//# sourceMappingURL=item.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"item.js","sourceRoot":"","sources":["../../src/tools/item.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../src/tools/search.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AA8BpE,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA6C1D"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { getClient } from "../api/client.js";
|
|
3
|
+
import { formatPrice } from "../api/types.js";
|
|
4
|
+
import { mcpError } from "../utils/mcp-error.js";
|
|
5
|
+
function formatSearchResults(data) {
|
|
6
|
+
if (data.items.length === 0) {
|
|
7
|
+
return "No items found matching your search criteria.";
|
|
8
|
+
}
|
|
9
|
+
const { pagination } = data;
|
|
10
|
+
const header = `Found ${pagination.total_entries} items (page ${pagination.current_page}/${pagination.total_pages}):\n`;
|
|
11
|
+
const items = data.items.map((item) => {
|
|
12
|
+
const price = formatPrice(item.price, item.currency);
|
|
13
|
+
const parts = [
|
|
14
|
+
`- **${item.title}** — ${price}`,
|
|
15
|
+
];
|
|
16
|
+
if (item.brand_title)
|
|
17
|
+
parts[0] += ` | ${item.brand_title}`;
|
|
18
|
+
if (item.size_title)
|
|
19
|
+
parts[0] += ` | Size: ${item.size_title}`;
|
|
20
|
+
parts.push(` Seller: ${item.user.login} (ID: ${item.user.id}) | ❤ ${item.favourite_count} | 👁 ${item.view_count}`);
|
|
21
|
+
parts.push(` ${item.url}`);
|
|
22
|
+
parts.push(` ID: ${item.id}`);
|
|
23
|
+
return parts.join("\n");
|
|
24
|
+
});
|
|
25
|
+
return header + items.join("\n\n");
|
|
26
|
+
}
|
|
27
|
+
export function registerSearchTool(server) {
|
|
28
|
+
server.tool("search_items", "Search for items on the Vinted marketplace. Returns a list of items matching the query with prices, brands, sizes, and seller info.", {
|
|
29
|
+
query: z.string().min(1).describe("Search query (e.g., 'nike air max', 'robe vintage')"),
|
|
30
|
+
page: z.number().int().min(1).max(100).default(1).describe("Page number (default: 1)"),
|
|
31
|
+
per_page: z.number().int().min(1).max(96).default(20).describe("Results per page (default: 20, max: 96)"),
|
|
32
|
+
order: z.enum(["relevance", "price_low_to_high", "price_high_to_low", "newest_first"]).default("relevance").describe("Sort order"),
|
|
33
|
+
price_from: z.number().min(0).optional().describe("Minimum price filter"),
|
|
34
|
+
price_to: z.number().min(0).optional().describe("Maximum price filter"),
|
|
35
|
+
catalog_ids: z.string().optional().describe("Catalog/category IDs (comma-separated)"),
|
|
36
|
+
brand_ids: z.string().optional().describe("Brand IDs (comma-separated)"),
|
|
37
|
+
size_ids: z.string().optional().describe("Size IDs (comma-separated)"),
|
|
38
|
+
color_ids: z.string().optional().describe("Color IDs (comma-separated)"),
|
|
39
|
+
status_ids: z.string().optional().describe("Condition IDs (comma-separated): 6=New with tags, 1=New, 2=Very good, 3=Good, 4=Satisfactory"),
|
|
40
|
+
}, async (params) => {
|
|
41
|
+
try {
|
|
42
|
+
const queryParams = {
|
|
43
|
+
search_text: params.query,
|
|
44
|
+
page: String(params.page),
|
|
45
|
+
per_page: String(params.per_page),
|
|
46
|
+
order: params.order,
|
|
47
|
+
};
|
|
48
|
+
if (params.price_from !== undefined)
|
|
49
|
+
queryParams["price_from"] = String(params.price_from);
|
|
50
|
+
if (params.price_to !== undefined)
|
|
51
|
+
queryParams["price_to"] = String(params.price_to);
|
|
52
|
+
if (params.catalog_ids)
|
|
53
|
+
queryParams["catalog_ids"] = params.catalog_ids;
|
|
54
|
+
if (params.brand_ids)
|
|
55
|
+
queryParams["brand_ids"] = params.brand_ids;
|
|
56
|
+
if (params.size_ids)
|
|
57
|
+
queryParams["size_ids"] = params.size_ids;
|
|
58
|
+
if (params.color_ids)
|
|
59
|
+
queryParams["color_ids"] = params.color_ids;
|
|
60
|
+
if (params.status_ids)
|
|
61
|
+
queryParams["status_ids"] = params.status_ids;
|
|
62
|
+
const data = await getClient().get("/catalog/items", queryParams);
|
|
63
|
+
const text = formatSearchResults(data);
|
|
64
|
+
return {
|
|
65
|
+
content: [{ type: "text", text }],
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
return mcpError("Search failed", error);
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=search.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search.js","sourceRoot":"","sources":["../../src/tools/search.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"user-items.d.ts","sourceRoot":"","sources":["../../src/tools/user-items.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AA8BpE,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA8B7D"}
|