@scavio/mcp-server 0.13.1 → 0.14.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.
Files changed (70) hide show
  1. package/dist/lib/trim-response.d.ts +6 -0
  2. package/dist/lib/trim-response.js +26 -0
  3. package/dist/lib/trim-response.js.map +1 -0
  4. package/dist/tools/airbnb.js +30 -49
  5. package/dist/tools/airbnb.js.map +1 -1
  6. package/dist/tools/amazon.js +11 -18
  7. package/dist/tools/amazon.js.map +1 -1
  8. package/dist/tools/appstore.js +16 -15
  9. package/dist/tools/appstore.js.map +1 -1
  10. package/dist/tools/booking.js +28 -45
  11. package/dist/tools/booking.js.map +1 -1
  12. package/dist/tools/capterra.js +16 -15
  13. package/dist/tools/capterra.js.map +1 -1
  14. package/dist/tools/companieshouse.js +11 -10
  15. package/dist/tools/companieshouse.js.map +1 -1
  16. package/dist/tools/ebay.js +21 -30
  17. package/dist/tools/ebay.js.map +1 -1
  18. package/dist/tools/extract.js +6 -5
  19. package/dist/tools/extract.js.map +1 -1
  20. package/dist/tools/g2.js +23 -22
  21. package/dist/tools/g2.js.map +1 -1
  22. package/dist/tools/glassdoor.js +18 -17
  23. package/dist/tools/glassdoor.js.map +1 -1
  24. package/dist/tools/google.js +154 -153
  25. package/dist/tools/google.js.map +1 -1
  26. package/dist/tools/googleads.js +20 -19
  27. package/dist/tools/googleads.js.map +1 -1
  28. package/dist/tools/googleplay.js +14 -13
  29. package/dist/tools/googleplay.js.map +1 -1
  30. package/dist/tools/homedepot.js +15 -28
  31. package/dist/tools/homedepot.js.map +1 -1
  32. package/dist/tools/indeed.js +20 -39
  33. package/dist/tools/indeed.js.map +1 -1
  34. package/dist/tools/instagram.js +59 -58
  35. package/dist/tools/instagram.js.map +1 -1
  36. package/dist/tools/kuaishou.js +47 -46
  37. package/dist/tools/kuaishou.js.map +1 -1
  38. package/dist/tools/linkedin.js +26 -25
  39. package/dist/tools/linkedin.js.map +1 -1
  40. package/dist/tools/metaads.js +21 -20
  41. package/dist/tools/metaads.js.map +1 -1
  42. package/dist/tools/reddit.js +48 -47
  43. package/dist/tools/reddit.js.map +1 -1
  44. package/dist/tools/redfin.js +29 -28
  45. package/dist/tools/redfin.js.map +1 -1
  46. package/dist/tools/sec.js +36 -35
  47. package/dist/tools/sec.js.map +1 -1
  48. package/dist/tools/target.js +19 -40
  49. package/dist/tools/target.js.map +1 -1
  50. package/dist/tools/threads.js +20 -19
  51. package/dist/tools/threads.js.map +1 -1
  52. package/dist/tools/tiktok-shop.js +38 -37
  53. package/dist/tools/tiktok-shop.js.map +1 -1
  54. package/dist/tools/tiktok.js +54 -53
  55. package/dist/tools/tiktok.js.map +1 -1
  56. package/dist/tools/tripadvisor.js +20 -43
  57. package/dist/tools/tripadvisor.js.map +1 -1
  58. package/dist/tools/usage.js +3 -2
  59. package/dist/tools/usage.js.map +1 -1
  60. package/dist/tools/walmart.js +35 -34
  61. package/dist/tools/walmart.js.map +1 -1
  62. package/dist/tools/x.js +44 -43
  63. package/dist/tools/x.js.map +1 -1
  64. package/dist/tools/yelp.js +21 -20
  65. package/dist/tools/yelp.js.map +1 -1
  66. package/dist/tools/youtube.js +77 -76
  67. package/dist/tools/youtube.js.map +1 -1
  68. package/dist/tools/zillow.js +38 -53
  69. package/dist/tools/zillow.js.map +1 -1
  70. package/package.json +1 -1
@@ -1,5 +1,6 @@
1
1
  import { z } from "zod";
2
2
  import { handleApiError } from "../lib/tool-error.js";
3
+ import { trimResponse } from "../lib/trim-response.js";
3
4
  // No zod `.default()` anywhere in this file, on purpose. The MCP SDK applies a
4
5
  // zod default BEFORE the handler runs, so a defaulted field is posted on every
5
6
  // single call whether the model set it or not — which is exactly how the
@@ -7,93 +8,69 @@ import { handleApiError } from "../lib/tool-error.js";
7
8
  // Upstream defaults are documented in the .describe() text instead and left for
8
9
  // the backend to apply.
9
10
  const geoIdField = () => z.string().min(1).max(500).optional()
10
- .describe("Tripadvisor geo id — the 'g' half of the g/d pair every Tripadvisor URL is keyed by. Accepts '30196', 'g30196', or any tripadvisor.com URL carrying one. Get it from resolve_tripadvisor_location.");
11
+ .describe("Geo id, e.g. '30196' or 'g30196'. Get from resolve_tripadvisor_location.");
11
12
  const categoryField = () => z.enum(["restaurants", "hotels", "attractions"]).optional()
12
- .describe("Which of Tripadvisor's three location families to read. These are separate URL families, not a filter — they are not interchangeable. Upstream default is 'restaurants'.");
13
+ .describe("Location family (default 'restaurants'). Separate URL families, not a filter.");
13
14
  export function registerTripadvisorTools(server, getClient) {
14
- server.tool("resolve_tripadvisor_location", `START HERE for Tripadvisor. Resolves a place or business NAME to the Tripadvisor ids every other Tripadvisor tool is keyed by, as JSON.
15
-
16
- Each row is either a GEO (a city, region or other destination — its geo_id is what search_tripadvisor takes) or a BUSINESS (a restaurant, hotel or attraction — its geo_id + location_id PAIR is what get_tripadvisor_location and get_tripadvisor_reviews take). Rows also carry the display name, type, and parent geography so you can pick the right "Springfield".
17
-
18
- Call this first whenever you only have a name. Those ids exist nowhere except inside Tripadvisor's own URLs, so there is no other entry point into this platform.
19
-
20
- limit only SIZES this response (1-20, upstream default 12) — it is not a page parameter and this lookup has no pagination. Costs 2 credits.`, {
15
+ server.tool("resolve_tripadvisor_location", `Resolve a place or business name to Tripadvisor ids (geo_id, location_id). Start here before other Tripadvisor tools. 2 credits.`, {
21
16
  query: z.string().min(1).max(120)
22
- .describe("A place or business name to resolve, e.g. 'Austin' or 'Franklin Barbecue'."),
17
+ .describe("Place or business name."),
23
18
  limit: z.number().int().min(1).max(20).optional()
24
- .describe("Rows to return, 1-20. Upstream default is 12. Sizes the response only — NOT a page parameter."),
19
+ .describe("Rows (default 12). Not paginated."),
25
20
  }, async (params) => {
26
21
  try {
27
22
  const data = await getClient().post("/api/v1/tripadvisor/locations", params);
28
- return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
23
+ return trimResponse(data);
29
24
  }
30
25
  catch (err) {
31
26
  return handleApiError(err);
32
27
  }
33
28
  });
34
- server.tool("search_tripadvisor", `List the restaurants, hotels or attractions in a Tripadvisor geo, in Tripadvisor's own ranked order, as JSON. Each row carries rating, review count, price band, address, coordinates, phone, opening hours, the Travelers' Choice badge, and the location_id + geo_id pair needed to look the place up in detail.
35
-
36
- Either geo_id or url is required. If you only have a place NAME, call resolve_tripadvisor_location first — geo ids exist only inside Tripadvisor's own URLs.
37
-
38
- category picks one of three separate URL families (restaurants, hotels, attractions), not a filter over one list; upstream default is restaurants.
39
-
40
- Paginate with page: 30 locations per page. A page beyond the last is a 404, NOT an empty result — stop when a page 404s. Costs 2 credits per page.`, {
29
+ server.tool("search_tripadvisor", `List restaurants/hotels/attractions in a Tripadvisor geo. 30/page, page past last = 404. geo_id or url required. 2 credits/page.`, {
41
30
  geo_id: geoIdField(),
42
31
  category: categoryField(),
43
32
  page: z.number().int().min(1).optional()
44
- .describe("Results page, 1-based. 30 locations per page. A page past the last is a 404, not an empty list."),
33
+ .describe("Page, 1-based. Page past last = 404."),
45
34
  url: z.string().min(1).max(500).optional()
46
- .describe("A full tripadvisor.com listing URL, e.g. 'https://www.tripadvisor.com/Restaurants-g30196-Austin_Texas.html', as an alternative to geo_id + category. Country sites (tripadvisor.co.uk, .fr) work. Either this or geo_id is required."),
35
+ .describe("Tripadvisor listing URL, alternative to geo_id."),
47
36
  }, async (params) => {
48
37
  try {
49
38
  const data = await getClient().post("/api/v1/tripadvisor/search", params);
50
- return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
39
+ return trimResponse(data);
51
40
  }
52
41
  catch (err) {
53
42
  return handleApiError(err);
54
43
  }
55
44
  });
56
- server.tool("get_tripadvisor_location", `Get one Tripadvisor restaurant, hotel or attraction in full as JSON: rating, the review histogram and per-aspect sub-ratings, its ranking within the city, price band, cuisines, amenities, address, coordinates, contact details, photos — and the FIRST PAGE OF REVIEWS.
57
-
58
- Because page 1 of the reviews already rides along here, do NOT call get_tripadvisor_reviews to read it; use that tool only to page PAST the first page.
59
-
60
- Either location_id or url is required, and a bare d-id additionally needs geo_id — Tripadvisor will not resolve a location without its geography. Get both from resolve_tripadvisor_location. An unknown location id is answered upstream with a 200 city listing that is BILLED and restated here as a 404, so use resolved ids rather than guesses.
61
-
62
- No pagination on this tool. Costs 2 credits.`, {
45
+ server.tool("get_tripadvisor_location", `Get full Tripadvisor location detail with first page of reviews included. Use get_tripadvisor_reviews only to page past page 1. location_id or url required (bare id needs geo_id too). 2 credits.`, {
63
46
  location_id: z.string().min(1).max(500).optional()
64
- .describe("Tripadvisor location id — the 'd' half of the pair. Accepts '1899234', 'd1899234', or a full _Review URL. Either this or url is required."),
47
+ .describe("Location id, e.g. '1899234'. Either this or url required."),
65
48
  geo_id: geoIdField(),
66
49
  category: categoryField(),
67
50
  url: z.string().min(1).max(500).optional()
68
- .describe("A full tripadvisor.com _Review URL, e.g. 'https://www.tripadvisor.com/Restaurant_Review-g30196-d1899234-Reviews.html', as an alternative to the id pair. Either this or location_id is required."),
51
+ .describe("Tripadvisor _Review URL, alternative to id pair."),
69
52
  }, async (params) => {
70
53
  try {
71
54
  const data = await getClient().post("/api/v1/tripadvisor/location", params);
72
- return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
55
+ return trimResponse(data);
73
56
  }
74
57
  catch (err) {
75
58
  return handleApiError(err);
76
59
  }
77
60
  });
78
- server.tool("get_tripadvisor_reviews", `Get a page of Tripadvisor reviews for one location as JSON: review text and rating, trip date and trip type, the reviewer's home town and contribution count, and any management response.
79
-
80
- Use this to page PAST page 1 — page 1 is already included in get_tripadvisor_location, so calling this for it spends a second 2-credit call on reviews you already have.
81
-
82
- Page size differs by family: 15 per page for restaurants, 10 for hotels and attractions. category must therefore MATCH the location's own type on any page past the first, or the offsets do not line up. A page beyond the last is a 404, not an empty result.
83
-
84
- Consecutive pages can REPEAT one review at the boundary — de-duplicate on review_id when concatenating pages. Either location_id or url is required (a bare d-id also needs geo_id). Costs 2 credits per page.`, {
61
+ server.tool("get_tripadvisor_reviews", `Page past the reviews already in get_tripadvisor_location. 15/page restaurants, 10/page hotels+attractions. Page past last = 404. De-dup on review_id at boundaries. 2 credits/page.`, {
85
62
  location_id: z.string().min(1).max(500).optional()
86
- .describe("Tripadvisor location id — '1899234', 'd1899234', or a full _Review URL. Either this or url is required."),
63
+ .describe("Location id. Either this or url required."),
87
64
  geo_id: geoIdField(),
88
65
  category: categoryField(),
89
66
  url: z.string().min(1).max(500).optional()
90
- .describe("A full tripadvisor.com _Review URL, as an alternative to the id pair. Either this or location_id is required."),
67
+ .describe("Tripadvisor _Review URL, alternative to id pair."),
91
68
  page: z.number().int().min(1).optional()
92
- .describe("Reviews page, 1-based. 15 per page for restaurants, 10 for hotels and attractions — set category to match the location's own type. A page past the last is a 404."),
69
+ .describe("Page, 1-based. Match category to location type."),
93
70
  }, async (params) => {
94
71
  try {
95
72
  const data = await getClient().post("/api/v1/tripadvisor/reviews", params);
96
- return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
73
+ return trimResponse(data);
97
74
  }
98
75
  catch (err) {
99
76
  return handleApiError(err);
@@ -1 +1 @@
1
- {"version":3,"file":"tripadvisor.js","sourceRoot":"","sources":["../../src/tools/tripadvisor.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"tripadvisor.js","sourceRoot":"","sources":["../../src/tools/tripadvisor.ts"],"names":[],"mappings":"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"}
@@ -1,9 +1,10 @@
1
1
  import { handleApiError } from "../lib/tool-error.js";
2
+ import { trimResponse } from "../lib/trim-response.js";
2
3
  export function registerUsageTool(server, getClient) {
3
- server.tool("get_usage", `Get the current user's credit balance, plan, searches used this month, and auto-recharge settings. Use when the user asks how many credits they have left, what plan they're on, or about their usage.`, {}, async () => {
4
+ server.tool("get_usage", `Get credit balance, plan, and usage stats. Free.`, {}, async () => {
4
5
  try {
5
6
  const data = await getClient().get("/api/v1/usage");
6
- return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
7
+ return trimResponse(data);
7
8
  }
8
9
  catch (err) {
9
10
  return handleApiError(err);
@@ -1 +1 @@
1
- {"version":3,"file":"usage.js","sourceRoot":"","sources":["../../src/tools/usage.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEtD,MAAM,UAAU,iBAAiB,CAAC,MAAiB,EAAE,SAA6B;IAChF,MAAM,CAAC,IAAI,CACT,WAAW,EACX,wMAAwM,EACxM,EAAE,EACF,KAAK,IAAI,EAAE;QACT,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,SAAS,EAAE,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;YACpD,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;QAC9E,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,cAAc,CAAC,GAAG,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"usage.js","sourceRoot":"","sources":["../../src/tools/usage.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAEvD,MAAM,UAAU,iBAAiB,CAAC,MAAiB,EAAE,SAA6B;IAChF,MAAM,CAAC,IAAI,CACT,WAAW,EACX,kDAAkD,EAClD,EAAE,EACF,KAAK,IAAI,EAAE;QACT,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,SAAS,EAAE,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;YACpD,OAAO,YAAY,CAAC,IAAI,CAAC,CAAC;QAC5B,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,cAAc,CAAC,GAAG,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -1,5 +1,6 @@
1
1
  import { z } from "zod";
2
2
  import { handleApiError } from "../lib/tool-error.js";
3
+ import { trimResponse } from "../lib/trim-response.js";
3
4
  /**
4
5
  * Walmart marketplace. This is the price-bearing parameter: com and ca bill 1
5
6
  * credit, com.mx bills 2. Only search and category accept it — walmart.ca
@@ -9,7 +10,7 @@ import { handleApiError } from "../lib/tool-error.js";
9
10
  * runs, so a default is posted on every call whether the caller meant it or not.
10
11
  */
11
12
  const domainField = z.enum(["com", "ca", "com.mx"]).optional()
12
- .describe("Walmart marketplace: 'com' (US, default, 1 credit), 'ca' (Canada, 1 credit), 'com.mx' (Mexico, 2 credits). Prices and product URLs come back in that marketplace's currency and domain. Omit for US.");
13
+ .describe("'com' (US, 1cr), 'ca' (Canada, 1cr), 'com.mx' (Mexico, 2cr). Default US.");
13
14
  /**
14
15
  * The backend enum is CLOSED to today|tomorrow. '2_days' leaks items 3-4 days
15
16
  * out and 'anytime' is a no-op, so both were retired upstream — and a zod
@@ -17,115 +18,115 @@ const domainField = z.enum(["com", "ca", "com.mx"]).optional()
17
18
  * There is deliberately no default.
18
19
  */
19
20
  const fulfillmentSpeedField = z.enum(["today", "tomorrow"]).optional()
20
- .describe("Only items deliverable today, or by tomorrow. For 'anytime', omit this parameter entirely — there is no 'anytime' value.");
21
+ .describe("'today' or 'tomorrow'. Omit for all items.");
21
22
  const sortByField = z.enum(["best_match", "price_low", "price_high", "best_seller", "rating_high", "new"]).optional()
22
- .describe("Result sort order. Defaults to 'best_match' when omitted.");
23
+ .describe("Sort order. Default 'best_match'.");
23
24
  export function registerWalmartTools(server, getClient) {
24
- server.tool("search_walmart", `Search Walmart.com and return structured product rows as JSON. Returns data.products, each with id (usItemId), title, url, image, price, currency, rating, rating_count, brand, seller_name, seller_catalog_id, sponsored, out_of_stock, availability_status, fulfillment and variants — plus products_count, page, max_page, has_more_pages, total_results (Walmart's own headline count, larger than what is returned), location, breadcrumb and related_searches. Page through results with the page parameter while data.has_more_pages is true. Costs 1 credit on walmart.com (default) and walmart.ca, and 2 credits on walmart.com.mx — the domain parameter sets the price. Results are always returned against Walmart's default store: delivery ZIP, store id and device emulation are not supported, and the store actually used is reported in data.location.`, {
25
+ server.tool("search_walmart", `Search Walmart products. Paginate with page while has_more_pages. 1 credit (US/CA), 2 credits (Mexico).`, {
25
26
  query: z.string().min(1).max(500)
26
- .describe("Product search query, e.g. 'air fryer 6 quart'."),
27
+ .describe("Product search query."),
27
28
  page: z.number().int().min(1).optional()
28
- .describe("Results page, 1-based. Defaults to page 1."),
29
+ .describe("Results page, 1-based."),
29
30
  sort_by: sortByField,
30
31
  min_price: z.number().optional()
31
- .describe("Minimum price filter, in the marketplace's currency."),
32
+ .describe("Min price."),
32
33
  max_price: z.number().optional()
33
- .describe("Maximum price filter, in the marketplace's currency."),
34
+ .describe("Max price."),
34
35
  fulfillment_speed: fulfillmentSpeedField,
35
36
  fulfillment_type: z.enum(["in_store"]).optional()
36
- .describe("Set to 'in_store' to return only items available for in-store pickup. Omit for all items."),
37
+ .describe("'in_store' for pickup only. Omit for all."),
37
38
  domain: domainField,
38
39
  }, async (params) => {
39
40
  try {
40
41
  const data = await getClient().post("/api/v1/walmart/search", params);
41
- return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
42
+ return trimResponse(data);
42
43
  }
43
44
  catch (err) {
44
45
  return handleApiError(err);
45
46
  }
46
47
  });
47
- server.tool("get_walmart_product", `Get the full detail page for one Walmart product as JSON. Returns id/sku, title, url, image and images, price, price_strikethrough, currency, rating, rating_count, brand, model, gtin, product_type, short_description, long_description, specifications, variants, availability_status, out_of_stock, fulfillment, category_path, offer_count, location, and the seller (seller_name, seller_id as a GUID, and seller_catalog_id — the NUMERIC id that get_walmart_seller and get_walmart_seller_products require). Does NOT include review text (call get_walmart_reviews) or the seller offer list (call get_walmart_offers). Not paginated. walmart.com (US) only — there is no domain parameter, because walmart.ca product pages cannot be fetched. Costs 1 credit.`, {
48
+ server.tool("get_walmart_product", `Get full Walmart product detail. No reviews (use get_walmart_reviews) or offers (use get_walmart_offers). US only (no domain param). seller_catalog_id is the NUMERIC id for seller endpoints. 1 credit.`, {
48
49
  product_id: z.string().min(1)
49
- .describe("Walmart item id (usItemId) — the numeric string at the end of a product URL /ip/<name>/<PRODUCT_ID>, e.g. '13544111159'."),
50
+ .describe("Walmart usItemId, e.g. '13544111159'."),
50
51
  }, async (params) => {
51
52
  try {
52
53
  const data = await getClient().post("/api/v1/walmart/product", params);
53
- return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
54
+ return trimResponse(data);
54
55
  }
55
56
  catch (err) {
56
57
  return handleApiError(err);
57
58
  }
58
59
  });
59
- server.tool("get_walmart_reviews", `Get customer reviews for a Walmart product as JSON. Returns data.reviews (review_id, rating, title, text, author, author_location, submitted_at, verified_purchase, helpful_count, unhelpful_count, photos), plus average_rating, total_review_count, reviews_with_text_count, recommended_percentage, rating_breakdown (the 1-5 star histogram), and top_positive_review / top_negative_review. Returns 10 reviews per page — page through with the page parameter, using total_review_count to know how many pages exist. Costs 1 credit per page.`, {
60
+ server.tool("get_walmart_reviews", `Get Walmart product reviews. 10/page, paginate with page param. Includes rating_breakdown and top positive/negative. 1 credit/page.`, {
60
61
  product_id: z.string().min(1)
61
- .describe("Walmart item id (usItemId), e.g. '13544111159'."),
62
+ .describe("Walmart usItemId."),
62
63
  page: z.number().int().min(1).optional()
63
- .describe("Reviews page, 1-based. 10 reviews per page. Defaults to page 1."),
64
+ .describe("Page, 1-based. 10 reviews/page."),
64
65
  sort: z.enum(["relevancy", "submission-desc", "submission-asc", "rating-desc", "rating-asc", "helpful-desc"]).optional()
65
- .describe("Review sort order: 'relevancy', 'submission-desc' (newest first), 'submission-asc' (oldest), 'rating-desc' (highest rated), 'rating-asc' (lowest rated), 'helpful-desc' (most helpful)."),
66
+ .describe("Sort order."),
66
67
  }, async (params) => {
67
68
  try {
68
69
  const data = await getClient().post("/api/v1/walmart/reviews", params);
69
- return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
70
+ return trimResponse(data);
70
71
  }
71
72
  catch (err) {
72
73
  return handleApiError(err);
73
74
  }
74
75
  });
75
- server.tool("get_walmart_category", `Browse the products inside a Walmart category as JSON, without a search query. Returns exactly the same shape as search_walmart: data.products (id, title, url, image, price, rating, brand, seller_catalog_id, sponsored, fulfillment, variants), products_count, page, max_page, has_more_pages, location and breadcrumb. Page through with the page parameter while data.has_more_pages is true. The limit parameter trims the returned list after Walmart has been fetched — it does NOT reduce the cost of the call. Costs 1 credit on walmart.com (default) and walmart.ca, and 2 credits on walmart.com.mx — the domain parameter sets the price.`, {
76
+ server.tool("get_walmart_category", `Browse Walmart category products (no query). Same shape as search_walmart. Paginate with page while has_more_pages. limit trims locally (doesn't reduce cost). 1 credit (US/CA), 2 credits (Mexico).`, {
76
77
  category_id: z.string().min(1)
77
- .describe("Walmart category id: either a leaf id ('1095191') or the full underscore-joined path ('3944_133251_1095191'). Both are accepted. Category ids appear in the breadcrumb and category_path fields of search and product responses."),
78
+ .describe("Category id, e.g. '1095191' or '3944_133251_1095191'."),
78
79
  page: z.number().int().min(1).optional()
79
- .describe("Results page, 1-based. Defaults to page 1."),
80
+ .describe("Page, 1-based."),
80
81
  limit: z.number().int().min(1).optional()
81
- .describe("Trim the returned products to at most this many. Applied after fetching — it does not reduce the credit cost."),
82
+ .describe("Max products to return (local trim, same cost)."),
82
83
  sort_by: sortByField,
83
84
  min_price: z.number().optional()
84
- .describe("Minimum price filter, in the marketplace's currency."),
85
+ .describe("Min price."),
85
86
  max_price: z.number().optional()
86
- .describe("Maximum price filter, in the marketplace's currency."),
87
+ .describe("Max price."),
87
88
  fulfillment_speed: fulfillmentSpeedField,
88
89
  domain: domainField,
89
90
  }, async (params) => {
90
91
  try {
91
92
  const data = await getClient().post("/api/v1/walmart/category", params);
92
- return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
93
+ return trimResponse(data);
93
94
  }
94
95
  catch (err) {
95
96
  return handleApiError(err);
96
97
  }
97
98
  });
98
- server.tool("get_walmart_offers", `Get the BUY-BOX offer for a Walmart product as JSON — which seller currently wins the listing, at what price. Returns product_id, title, url, count, total_offer_count (Walmart's own tally of purchasable offers, which is usually larger) and data.offers, each with offer_id, seller_name, seller_id, seller_catalog_id, seller_rating, seller_review_count, price, list_price, currency, condition, availability_status, shipping_price, fulfillment, wfs and is_buy_box_winner. This is NOT the full competing-offer list: Walmart server-renders only the buy-box winner, so expect one offer even when total_offer_count is higher. Not paginated. Costs 1 credit.`, {
99
+ server.tool("get_walmart_offers", `Get the buy-box offer for a Walmart product. Returns only the winning seller (not full offer list). Not paginated. 1 credit.`, {
99
100
  product_id: z.string().min(1)
100
- .describe("Walmart item id (usItemId), e.g. '2979510112'."),
101
+ .describe("Walmart usItemId."),
101
102
  }, async (params) => {
102
103
  try {
103
104
  const data = await getClient().post("/api/v1/walmart/offers", params);
104
- return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
105
+ return trimResponse(data);
105
106
  }
106
107
  catch (err) {
107
108
  return handleApiError(err);
108
109
  }
109
110
  });
110
- server.tool("get_walmart_seller", `Get a Walmart marketplace seller's storefront as JSON. Returns seller_id (numeric) and seller_guid, name, display_name, about, logo_url, url, seller_type (EXTERNAL is a marketplace seller, INTERNAL is Walmart itself), is_marketplace_seller, has_pro_seller_badge, is_active, is_alcohol_seller, rating, review_count, reviews_with_text_count, rating_breakdown and a sample of reviews. Business contact fields (email, phone, address) come back only for sellers whose details Walmart publishes; they are null for every seller Walmart marks as exempt. IMPORTANT: seller_id must be the NUMERIC catalog seller id, which is the seller_catalog_id field on a product, search or offers response — passing the GUID seller_id from those same responses returns 404. Not paginated. Costs 1 credit.`, {
111
+ server.tool("get_walmart_seller", `Get a Walmart seller's storefront. IMPORTANT: seller_id must be NUMERIC seller_catalog_id (not the GUID seller_id, which 404s). 1 credit.`, {
111
112
  seller_id: z.string().min(1)
112
- .describe("Numeric Walmart catalog seller id, e.g. '101480084'. Take it from the seller_catalog_id field of a product, search or offers response. The GUID-form seller_id is NOT accepted here — it 404s."),
113
+ .describe("Numeric seller_catalog_id, e.g. '101480084'. GUID form 404s."),
113
114
  }, async (params) => {
114
115
  try {
115
116
  const data = await getClient().post("/api/v1/walmart/seller", params);
116
- return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
117
+ return trimResponse(data);
117
118
  }
118
119
  catch (err) {
119
120
  return handleApiError(err);
120
121
  }
121
122
  });
122
- server.tool("get_walmart_seller_products", `List the products a Walmart marketplace seller sells, as JSON. Returns seller_id, seller_name, seller_display_name, count, products_count, total_count and data.products in the same shape as search_walmart (id, title, url, image, price, rating, brand, fulfillment, variants). HARD CAP: Walmart server-renders only roughly the FIRST 40 items and paginates the rest client-side, so this returns about 40 products no matter how large the catalog is, and there is no page or cursor parameter. Read total_count to see the seller's real catalog size and to know you are looking at a slice. IMPORTANT: seller_id must be the NUMERIC catalog seller id (the seller_catalog_id field on a product, search or offers response); the GUID form 404s. Costs 1 credit.`, {
123
+ server.tool("get_walmart_seller_products", `List a Walmart seller's products. HARD CAP: ~40 products max (no pagination). Use total_count for real catalog size. seller_id must be NUMERIC seller_catalog_id (GUID 404s). 1 credit.`, {
123
124
  seller_id: z.string().min(1)
124
- .describe("Numeric Walmart catalog seller id, e.g. '101480084', from the seller_catalog_id field of a product, search or offers response. The GUID-form seller_id 404s."),
125
+ .describe("Numeric seller_catalog_id, e.g. '101480084'. GUID form 404s."),
125
126
  }, async (params) => {
126
127
  try {
127
128
  const data = await getClient().post("/api/v1/walmart/seller-products", params);
128
- return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
129
+ return trimResponse(data);
129
130
  }
130
131
  catch (err) {
131
132
  return handleApiError(err);
@@ -1 +1 @@
1
- {"version":3,"file":"walmart.js","sourceRoot":"","sources":["../../src/tools/walmart.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEtD;;;;;;;GAOG;AACH,MAAM,WAAW,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,QAAQ,EAAE;KAC3D,QAAQ,CAAC,sMAAsM,CAAC,CAAC;AAEpN;;;;;GAKG;AACH,MAAM,qBAAqB,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC,CAAC,QAAQ,EAAE;KACnE,QAAQ,CAAC,0HAA0H,CAAC,CAAC;AAExI,MAAM,WAAW,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,KAAK,CAAC,CAAC,CAAC,QAAQ,EAAE;KAClH,QAAQ,CAAC,2DAA2D,CAAC,CAAC;AAEzE,MAAM,UAAU,oBAAoB,CAAC,MAAiB,EAAE,SAA6B;IACnF,MAAM,CAAC,IAAI,CACT,gBAAgB,EAChB,20BAA20B,EAC30B;QACE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;aAC9B,QAAQ,CAAC,iDAAiD,CAAC;QAC9D,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;aACrC,QAAQ,CAAC,4CAA4C,CAAC;QACzD,OAAO,EAAE,WAAW;QACpB,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;aAC7B,QAAQ,CAAC,sDAAsD,CAAC;QACnE,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;aAC7B,QAAQ,CAAC,sDAAsD,CAAC;QACnE,iBAAiB,EAAE,qBAAqB;QACxC,gBAAgB,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,QAAQ,EAAE;aAC9C,QAAQ,CAAC,2FAA2F,CAAC;QACxG,MAAM,EAAE,WAAW;KACpB,EACD,KAAK,EAAE,MAAM,EAAE,EAAE;QACf,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,SAAS,EAAE,CAAC,IAAI,CAAC,wBAAwB,EAAE,MAAM,CAAC,CAAC;YACtE,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;QAC9E,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,cAAc,CAAC,GAAG,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,qBAAqB,EACrB,4uBAA4uB,EAC5uB;QACE,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;aAC1B,QAAQ,CAAC,0HAA0H,CAAC;KACxI,EACD,KAAK,EAAE,MAAM,EAAE,EAAE;QACf,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,SAAS,EAAE,CAAC,IAAI,CAAC,yBAAyB,EAAE,MAAM,CAAC,CAAC;YACvE,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;QAC9E,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,cAAc,CAAC,GAAG,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,qBAAqB,EACrB,shBAAshB,EACthB;QACE,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;aAC1B,QAAQ,CAAC,iDAAiD,CAAC;QAC9D,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;aACrC,QAAQ,CAAC,iEAAiE,CAAC;QAC9E,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,aAAa,EAAE,YAAY,EAAE,cAAc,CAAC,CAAC,CAAC,QAAQ,EAAE;aACrH,QAAQ,CAAC,yLAAyL,CAAC;KACvM,EACD,KAAK,EAAE,MAAM,EAAE,EAAE;QACf,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,SAAS,EAAE,CAAC,IAAI,CAAC,yBAAyB,EAAE,MAAM,CAAC,CAAC;YACvE,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;QAC9E,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,cAAc,CAAC,GAAG,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,sBAAsB,EACtB,0nBAA0nB,EAC1nB;QACE,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;aAC3B,QAAQ,CAAC,kOAAkO,CAAC;QAC/O,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;aACrC,QAAQ,CAAC,4CAA4C,CAAC;QACzD,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;aACtC,QAAQ,CAAC,+GAA+G,CAAC;QAC5H,OAAO,EAAE,WAAW;QACpB,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;aAC7B,QAAQ,CAAC,sDAAsD,CAAC;QACnE,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;aAC7B,QAAQ,CAAC,sDAAsD,CAAC;QACnE,iBAAiB,EAAE,qBAAqB;QACxC,MAAM,EAAE,WAAW;KACpB,EACD,KAAK,EAAE,MAAM,EAAE,EAAE;QACf,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,SAAS,EAAE,CAAC,IAAI,CAAC,0BAA0B,EAAE,MAAM,CAAC,CAAC;YACxE,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;QAC9E,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,cAAc,CAAC,GAAG,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,oBAAoB,EACpB,2oBAA2oB,EAC3oB;QACE,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;aAC1B,QAAQ,CAAC,gDAAgD,CAAC;KAC9D,EACD,KAAK,EAAE,MAAM,EAAE,EAAE;QACf,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,SAAS,EAAE,CAAC,IAAI,CAAC,wBAAwB,EAAE,MAAM,CAAC,CAAC;YACtE,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;QAC9E,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,cAAc,CAAC,GAAG,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,oBAAoB,EACpB,+wBAA+wB,EAC/wB;QACE,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;aACzB,QAAQ,CAAC,gMAAgM,CAAC;KAC9M,EACD,KAAK,EAAE,MAAM,EAAE,EAAE;QACf,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,SAAS,EAAE,CAAC,IAAI,CAAC,wBAAwB,EAAE,MAAM,CAAC,CAAC;YACtE,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;QAC9E,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,cAAc,CAAC,GAAG,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,6BAA6B,EAC7B,8uBAA8uB,EAC9uB;QACE,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;aACzB,QAAQ,CAAC,8JAA8J,CAAC;KAC5K,EACD,KAAK,EAAE,MAAM,EAAE,EAAE;QACf,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,SAAS,EAAE,CAAC,IAAI,CAAC,iCAAiC,EAAE,MAAM,CAAC,CAAC;YAC/E,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;QAC9E,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,cAAc,CAAC,GAAG,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"walmart.js","sourceRoot":"","sources":["../../src/tools/walmart.ts"],"names":[],"mappings":"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"}
package/dist/tools/x.js CHANGED
@@ -1,153 +1,154 @@
1
1
  import { z } from "zod";
2
2
  import { handleApiError } from "../lib/tool-error.js";
3
+ import { trimResponse } from "../lib/trim-response.js";
3
4
  export function registerXTools(server, getClient) {
4
- server.tool("search_x", `Search X for tweets and people as JSON. Each result includes the tweet ID, author handle, text, language, timestamp, and engagement counts (favorites, retweets, replies, quotes, bookmarks, views). Use data.next_cursor as the next cursor while has_more is true. Costs 1 credit. Use when the user asks to find tweets or accounts about a topic.`, {
5
+ server.tool("search_x", `Search X tweets and people. Paginate with next_cursor/has_more. 1 credit.`, {
5
6
  search: z.string().min(1).max(500)
6
- .describe("X search query."),
7
+ .describe("Search query."),
7
8
  search_type: z.enum(["Top", "Latest", "People", "Photos", "Videos"]).optional()
8
- .describe("Result category. 'Top' (default), 'Latest', 'People', 'Photos', or 'Videos'."),
9
+ .describe("Top (default), Latest, People, Photos, Videos."),
9
10
  cursor: z.string().optional()
10
- .describe("Pagination cursor (next_cursor) from a previous response."),
11
+ .describe("next_cursor from previous response."),
11
12
  }, async (params) => {
12
13
  try {
13
14
  const data = await getClient().post("/api/v1/x/search", params);
14
- return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
15
+ return trimResponse(data);
15
16
  }
16
17
  catch (err) {
17
18
  return handleApiError(err);
18
19
  }
19
20
  });
20
- server.tool("get_tweet", `Get full details for a single tweet as JSON. Returns the tweet ID, text, display text, timestamp, language, engagement counts (favorites, retweets, replies, quotes, bookmarks, views), source, and reply-to reference. Accepts a tweet ID. Costs 1 credit.`, {
21
+ server.tool("get_tweet", `Get a single tweet's full details. 1 credit.`, {
21
22
  tweet_id: z.string().min(1)
22
- .describe("Tweet ID, e.g. '1808168603721650364'."),
23
+ .describe("Tweet ID."),
23
24
  }, async (params) => {
24
25
  try {
25
26
  const data = await getClient().post("/api/v1/x/tweet", params);
26
- return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
27
+ return trimResponse(data);
27
28
  }
28
29
  catch (err) {
29
30
  return handleApiError(err);
30
31
  }
31
32
  });
32
- server.tool("get_tweet_comments", `Get replies to a tweet as JSON, ranked or chronological. Each reply includes the tweet ID, author handle, text, timestamp, and engagement counts. Accepts a tweet ID. Use data.next_cursor as the next cursor while has_more is true. Costs 1 credit.`, {
33
+ server.tool("get_tweet_comments", `Get replies to a tweet. Paginate with next_cursor/has_more. 1 credit.`, {
33
34
  tweet_id: z.string().min(1)
34
- .describe("Tweet ID, e.g. '1808168603721650364'."),
35
+ .describe("Tweet ID."),
35
36
  rank: z.enum(["top", "latest"]).optional()
36
- .describe("'top' for ranked replies (default), 'latest' for chronological."),
37
+ .describe("'top' (default) or 'latest'."),
37
38
  cursor: z.string().optional()
38
- .describe("Pagination cursor (next_cursor) from a previous response."),
39
+ .describe("next_cursor from previous response."),
39
40
  }, async (params) => {
40
41
  try {
41
42
  const data = await getClient().post("/api/v1/x/tweet/comments", params);
42
- return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
43
+ return trimResponse(data);
43
44
  }
44
45
  catch (err) {
45
46
  return handleApiError(err);
46
47
  }
47
48
  });
48
- server.tool("get_tweet_retweeters", `Get the users who retweeted a tweet as JSON. Each user includes the user ID, handle, name, description, follower/friends/statuses/media counts, and profile image. Accepts a tweet ID. Use data.next_cursor as the next cursor while has_more is true. Costs 1 credit.`, {
49
+ server.tool("get_tweet_retweeters", `Get users who retweeted a tweet. Paginate with next_cursor/has_more. 1 credit.`, {
49
50
  tweet_id: z.string().min(1)
50
- .describe("Tweet ID, e.g. '1808168603721650364'."),
51
+ .describe("Tweet ID."),
51
52
  cursor: z.string().optional()
52
- .describe("Pagination cursor (next_cursor) from a previous response."),
53
+ .describe("next_cursor from previous response."),
53
54
  }, async (params) => {
54
55
  try {
55
56
  const data = await getClient().post("/api/v1/x/tweet/retweeters", params);
56
- return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
57
+ return trimResponse(data);
57
58
  }
58
59
  catch (err) {
59
60
  return handleApiError(err);
60
61
  }
61
62
  });
62
- server.tool("get_x_user", `Get an X user's profile as JSON. Returns the rest ID, handle, name, description, follower/friends/statuses/media counts, verified flag, avatar, header image, location, website, and creation date. Accepts a handle (without @). Costs 1 credit.`, {
63
+ server.tool("get_x_user", `Get an X user's profile. 1 credit.`, {
63
64
  screen_name: z.string().min(1)
64
- .describe("An X handle without the @, e.g. 'elonmusk'."),
65
+ .describe("Handle without @, e.g. 'elonmusk'."),
65
66
  }, async (params) => {
66
67
  try {
67
68
  const data = await getClient().post("/api/v1/x/user", params);
68
- return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
69
+ return trimResponse(data);
69
70
  }
70
71
  catch (err) {
71
72
  return handleApiError(err);
72
73
  }
73
74
  });
74
- server.tool("get_x_user_tweets", `List an X user's tweets as JSON in data.timeline, plus data.pinned (a pinned tweet or null) and data.user (the author's profile). Each tweet includes the tweet ID, text, timestamp, engagement counts, and conversation ID. Accepts a handle (without @). Use data.next_cursor as the next cursor; this endpoint returns no has_more, so stop when next_cursor is absent or the timeline comes back empty. Costs 1 credit.`, {
75
+ server.tool("get_x_user_tweets", `List an X user's tweets. No has_more; stop when next_cursor absent or timeline empty. 1 credit.`, {
75
76
  screen_name: z.string().min(1)
76
- .describe("An X handle without the @, e.g. 'elonmusk'."),
77
+ .describe("Handle without @."),
77
78
  cursor: z.string().optional()
78
- .describe("Pagination cursor (next_cursor) from a previous response."),
79
+ .describe("next_cursor from previous response."),
79
80
  }, async (params) => {
80
81
  try {
81
82
  const data = await getClient().post("/api/v1/x/user/tweets", params);
82
- return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
83
+ return trimResponse(data);
83
84
  }
84
85
  catch (err) {
85
86
  return handleApiError(err);
86
87
  }
87
88
  });
88
- server.tool("get_x_user_replies", `List an X user's tweets and replies as JSON in data.timeline, plus data.user (the author's profile). Each entry includes the tweet ID, text, timestamp, and engagement counts. Accepts a handle (without @). Use data.next_cursor as the next cursor; this endpoint returns no has_more, so stop when next_cursor is absent or the timeline comes back empty. Costs 1 credit.`, {
89
+ server.tool("get_x_user_replies", `List an X user's tweets and replies. No has_more; stop when next_cursor absent or timeline empty. 1 credit.`, {
89
90
  screen_name: z.string().min(1)
90
- .describe("An X handle without the @, e.g. 'elonmusk'."),
91
+ .describe("Handle without @."),
91
92
  cursor: z.string().optional()
92
- .describe("Pagination cursor (next_cursor) from a previous response."),
93
+ .describe("next_cursor from previous response."),
93
94
  }, async (params) => {
94
95
  try {
95
96
  const data = await getClient().post("/api/v1/x/user/replies", params);
96
- return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
97
+ return trimResponse(data);
97
98
  }
98
99
  catch (err) {
99
100
  return handleApiError(err);
100
101
  }
101
102
  });
102
- server.tool("get_x_user_media", `List an X user's media tweets (posts with photos or videos) as JSON in data.timeline, plus data.user (the author's profile). Each entry includes the tweet ID, text, timestamp, and engagement counts. Accepts a handle (without @). Use data.next_cursor as the next cursor; this endpoint returns no has_more, so stop when next_cursor is absent or the timeline comes back empty. Costs 1 credit.`, {
103
+ server.tool("get_x_user_media", `List an X user's media tweets. No has_more; stop when next_cursor absent or timeline empty. 1 credit.`, {
103
104
  screen_name: z.string().min(1)
104
- .describe("An X handle without the @, e.g. 'elonmusk'."),
105
+ .describe("Handle without @."),
105
106
  cursor: z.string().optional()
106
- .describe("Pagination cursor (next_cursor) from a previous response."),
107
+ .describe("next_cursor from previous response."),
107
108
  }, async (params) => {
108
109
  try {
109
110
  const data = await getClient().post("/api/v1/x/user/media", params);
110
- return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
111
+ return trimResponse(data);
111
112
  }
112
113
  catch (err) {
113
114
  return handleApiError(err);
114
115
  }
115
116
  });
116
- server.tool("get_x_user_followers", `List an X user's followers as JSON. Each follower includes the user ID, handle, name, description, follower count, verified flag, and location. Accepts a handle (without @). Use data.next_cursor as the next cursor while has_more is true. Costs 1 credit.`, {
117
+ server.tool("get_x_user_followers", `List an X user's followers. Paginate with next_cursor/has_more. 1 credit.`, {
117
118
  screen_name: z.string().min(1)
118
- .describe("An X handle without the @, e.g. 'elonmusk'."),
119
+ .describe("Handle without @."),
119
120
  cursor: z.string().optional()
120
- .describe("Pagination cursor (next_cursor) from a previous response."),
121
+ .describe("next_cursor from previous response."),
121
122
  }, async (params) => {
122
123
  try {
123
124
  const data = await getClient().post("/api/v1/x/user/followers", params);
124
- return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
125
+ return trimResponse(data);
125
126
  }
126
127
  catch (err) {
127
128
  return handleApiError(err);
128
129
  }
129
130
  });
130
- server.tool("get_x_user_followings", `List the accounts an X user follows as JSON, under data.following (singular, unlike the tool name). Each account includes the user ID, handle, name, description, follower count, verified flag, and location. Accepts a handle (without @). Use data.next_cursor as the next cursor while has_more is true. Costs 1 credit.`, {
131
+ server.tool("get_x_user_followings", `List accounts an X user follows (data.following). Paginate with next_cursor/has_more. 1 credit.`, {
131
132
  screen_name: z.string().min(1)
132
- .describe("An X handle without the @, e.g. 'elonmusk'."),
133
+ .describe("Handle without @."),
133
134
  cursor: z.string().optional()
134
- .describe("Pagination cursor (next_cursor) from a previous response."),
135
+ .describe("next_cursor from previous response."),
135
136
  }, async (params) => {
136
137
  try {
137
138
  const data = await getClient().post("/api/v1/x/user/followings", params);
138
- return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
139
+ return trimResponse(data);
139
140
  }
140
141
  catch (err) {
141
142
  return handleApiError(err);
142
143
  }
143
144
  });
144
- server.tool("get_x_trending", `Get trending topics on X for a country as JSON. Each trend includes its name, description, and context. Costs 1 credit.`, {
145
+ server.tool("get_x_trending", `Get trending topics on X for a country. 1 credit.`, {
145
146
  country: z.string().optional()
146
- .describe("Country name, e.g. 'UnitedStates' (default), 'UnitedKingdom', 'Japan'."),
147
+ .describe("e.g. 'UnitedStates' (default), 'UnitedKingdom', 'Japan'."),
147
148
  }, async (params) => {
148
149
  try {
149
150
  const data = await getClient().post("/api/v1/x/trending", params);
150
- return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
151
+ return trimResponse(data);
151
152
  }
152
153
  catch (err) {
153
154
  return handleApiError(err);