@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,49 +1,50 @@
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 registerCapterraTools(server, getClient) {
4
- server.tool("search_capterra_software", `Capterra, the B2B software review site. Search it for business software and get 20 ranked products back as JSON: name, vendor description, star rating, review count, logo and a paid-placement flag. Every row carries the product_id and slug that get_capterra_product and get_capterra_reviews take, so this is the entry point when you only have a product name or a category. THIS SEARCH DOES NOT PAGINATE AND CANNOT RETURN MORE THAN 20 PRODUCTS: Capterra fixes the result set at 20 and serves identical rows for ?page=2, so there is deliberately no page parameter - narrow the query instead of trying to page. A query (or a url that carries one) is REQUIRED: a term-less Capterra search serves a fixed popular-products list that has nothing to do with what you asked for. Costs 2 credits.`, {
5
+ server.tool("search_capterra_software", `Search Capterra for B2B software. Max 20 results, no pagination. query or url required. 2 credits.`, {
5
6
  query: z.string().min(1).max(200).optional()
6
- .describe("Software search term, e.g. 'help desk' or 'notion'. Either this or url is required - without one, Capterra serves an unrelated popular-products list."),
7
+ .describe("Software search term. Either this or url required."),
7
8
  url: z.string().min(1).max(1000).optional()
8
- .describe("Full Capterra search URL to run verbatim (capterra.com, capterra.co.uk and capterra.com.br are accepted). Either this or query is required."),
9
+ .describe("Capterra search URL. Either this or query required."),
9
10
  }, async (params) => {
10
11
  try {
11
12
  const data = await getClient().post("/api/v1/capterra/search", params);
12
- return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
13
+ return trimResponse(data);
13
14
  }
14
15
  catch (err) {
15
16
  return handleApiError(err);
16
17
  }
17
18
  });
18
- server.tool("get_capterra_product", `Capterra, the B2B software review site. Get one software product's full Capterra profile as JSON: overall rating with the per-star histogram and the four scored criteria, likelihood to recommend, review sentiment and topics, the complete pricing table with every plan and its features, every rated feature, every integration, AI-derived pros and cons with the review each was quoted from, FAQs, screenshots, badges and awards, competitor comparisons and alternatives, and the buyer profile broken down by company size, industry and job function. THE 25 MOST RECENT REVIEWS RIDE ALONG AT NO EXTRA COST - only call get_capterra_reviews when you need to page past them. The vendor field IS ALWAYS NULL here: Capterra does not publish it as structured data on the product page (the individual reviews name the vendor instead). product_id MUST BE A STRING - a JSON number is rejected - and it is the number in a /p/186596/Notion/ URL. The slug parameter is cosmetic on this endpoint. No pagination. Pass product_id or url - at least one is required. Costs 2 credits.`, {
19
+ server.tool("get_capterra_product", `Get full Capterra product profile with 25 most recent reviews included. Use get_capterra_reviews only to page past them. product_id (string, not number) or url required. 2 credits.`, {
19
20
  product_id: z.string().min(1).max(50).optional()
20
- .describe("Capterra product id as a STRING - the number in /p/186596/Notion/, so '186596'. A JSON number is rejected. Either this or url is required."),
21
+ .describe("Product id as string, e.g. '186596'. Either this or url required."),
21
22
  slug: z.string().min(1).max(200).optional()
22
- .describe("Product slug. COSMETIC on this endpoint - /p/186596/Zzzjunk/ returns the same profile byte-for-byte. It is load-bearing on get_capterra_reviews."),
23
+ .describe("Product slug. Cosmetic here, load-bearing on get_capterra_reviews."),
23
24
  url: z.string().min(1).max(1000).optional()
24
- .describe("Full Capterra product URL, e.g. 'https://www.capterra.com/p/186596/Notion/'. Either this or product_id is required."),
25
+ .describe("Capterra product URL. Either this or product_id required."),
25
26
  }, async (params) => {
26
27
  try {
27
28
  const data = await getClient().post("/api/v1/capterra/product", params);
28
- return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
29
+ return trimResponse(data);
29
30
  }
30
31
  catch (err) {
31
32
  return handleApiError(err);
32
33
  }
33
34
  });
34
- server.tool("get_capterra_reviews", `Capterra, the B2B software review site. Get one page of written reviews for a software product as JSON: the overall score plus five per-criterion scores, title, pros, cons, advice to others, how long the reviewer used it, the incentivized flag, alternatives they considered and what they switched from, reviewer job title, industry and company size, and the vendor's response. It also carries a richer competitor list than the profile page does, each alternative with its own rating histogram and starting price. USE THIS ONLY TO PAGE PAST THE FIRST 25 REVIEWS - get_capterra_product already returns the 25 most recent at no extra cost. 25 reviews per page, HARD-CAPPED AT PAGE 100 no matter how many reviews the product has; past page 100 Capterra answers with page one. The slug parameter is LOAD-BEARING here, unlike on the product endpoint: it is case-sensitive upstream and a wrong one silently serves PAGE ONE under a billed success, so pass back the slug or reviews_url you got from search_capterra_software or get_capterra_product. Pass product_id or url - at least one is required. Costs 2 credits per page.`, {
35
+ server.tool("get_capterra_reviews", `Page past the 25 reviews in get_capterra_product. 25/page, max page 100. slug is LOAD-BEARING here (case-sensitive; wrong slug silently returns page 1). product_id or url required. 2 credits/page.`, {
35
36
  product_id: z.string().min(1).max(50).optional()
36
- .describe("Capterra product id as a STRING, e.g. '186596'. Either this or url is required."),
37
+ .describe("Product id as string. Either this or url required."),
37
38
  slug: z.string().min(1).max(200).optional()
38
- .describe("Product slug. LOAD-BEARING here: case-sensitive upstream, and a wrong one silently serves page one under a billed success. Pass back the slug from search_capterra_software or get_capterra_product."),
39
+ .describe("Product slug. LOAD-BEARING, case-sensitive. Use slug from search/product."),
39
40
  url: z.string().min(1).max(1000).optional()
40
- .describe("Full Capterra reviews URL. Passing back reviews_url from get_capterra_product is the most reliable way to page. Either this or product_id is required."),
41
+ .describe("Capterra reviews URL. Prefer reviews_url from get_capterra_product."),
41
42
  page: z.number().int().min(1).max(100).optional()
42
- .describe("Page number, 1-100. 25 reviews per page. 100 is a hard cap whatever the review count says - past it Capterra serves page one again."),
43
+ .describe("Page 1-100. 25/page. Past 100 returns page 1."),
43
44
  }, async (params) => {
44
45
  try {
45
46
  const data = await getClient().post("/api/v1/capterra/reviews", params);
46
- return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
47
+ return trimResponse(data);
47
48
  }
48
49
  catch (err) {
49
50
  return handleApiError(err);
@@ -1 +1 @@
1
- {"version":3,"file":"capterra.js","sourceRoot":"","sources":["../../src/tools/capterra.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"capterra.js","sourceRoot":"","sources":["../../src/tools/capterra.ts"],"names":[],"mappings":"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"}
@@ -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
  // Companies House - the official UK company register. Four tools, 1 credit
4
5
  // each, flat.
5
6
  //
@@ -21,36 +22,36 @@ import { handleApiError } from "../lib/tool-error.js";
21
22
  // every call. The backend applies its own defaults when a field is absent;
22
23
  // they are documented in the .describe() text instead.
23
24
  const companyNumber = z.string().min(1).max(20)
24
- .describe("UK company number, from search_companies_house. Zero-padded and upper-cased for you, so '445790', '00445790' and 'sc090312' all resolve. Registry prefixes are supported: SC (Scotland), NI (Northern Ireland), OC/SO/NC (LLPs), FC (overseas), BR (UK establishment), CE (charitable incorporated organisation).");
25
+ .describe("UK company number, e.g. '00445790'. Auto zero-padded/upper-cased.");
25
26
  export function registerCompaniesHouseTools(server, getClient) {
26
27
  const call = (path) => async (params) => {
27
28
  try {
28
29
  const data = await getClient().post(path, params);
29
- return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
30
+ return trimResponse(data);
30
31
  }
31
32
  catch (err) {
32
33
  return handleApiError(err);
33
34
  }
34
35
  };
35
- server.tool("search_companies_house", `START HERE for Companies House, the official UK company register. Search it by company name or number and get back, as JSON, the company_number that every other Companies House tool is keyed by, plus company name, status (active, dissolved, liquidation), incorporation or dissolution date, registered office address and any matched former names. Search matches CURRENT AND FORMER names, so a company that rebranded is still findable under its old one. Paginated with page at 20 results per page and CAPPED AT PAGE 50: the register serves only a 1000-result window per term however many matches it claims (it will report 10,000 for a broad term and then answer page 51 with an HTTP 416), so narrow the query rather than paging further. UK register only - it holds nothing about US or other non-UK companies. Costs 1 credit.`, {
36
+ server.tool("search_companies_house", `Search UK Companies House by name or number. Returns company_number needed by other Companies House tools. UK only, max page 50. 1 credit.`, {
36
37
  query: z.string().min(1).max(200)
37
- .describe("Company name or number to search for, e.g. 'tesco'. Must not be blank. Matches current AND former names."),
38
+ .describe("Company name or number, e.g. 'tesco'."),
38
39
  page: z.number().int().min(1).max(50)
39
40
  .optional()
40
- .describe("Results page, 1-based, 20 per page. Backend default is 1. Hard cap of 50 - the register only serves the first 1000 matches for a term."),
41
+ .describe("Page, 1-based, 20/page. Max 50."),
41
42
  }, call("/api/v1/companieshouse/search"));
42
- server.tool("get_companies_house_company", `Get a UK company's full entry on the Companies House register as JSON: status, company type, incorporation and dissolution dates, registered office address, SIC industry codes, previous names, accounts and confirmation-statement due dates with their overdue flags, and whether it has charges, insolvency history, officers or UK establishments. Overseas companies (FC) also return home registry, legal form and governing law; UK establishments (BR) return the parent company; charitable incorporated organisations (CE) return the charity number. Keyed by company_number - call search_companies_house first if you only have a name. Not paginated. Costs 1 credit.`, {
43
+ server.tool("get_companies_house_company", `Get a UK company's full Companies House record: status, type, dates, address, SIC codes, previous names, accounts. 1 credit.`, {
43
44
  company_number: companyNumber,
44
45
  }, call("/api/v1/companieshouse/company"));
45
- server.tool("get_companies_house_officers", `List a UK company's officers, current and resigned, from the Companies House register as JSON: name, officer role (director, secretary, LLP member), appointment and resignation dates, correspondence address, nationality, country of residence, month-and-year date of birth, and identity-verification status. There is NO server-side active/resigned filter - the register's own is client-side, so filter on each officer's \`status\` in the response. officers_count is every appointment ever made and resignations_count how many ended, so active officers = the difference. Paginated with page at 35 per page with NO upper page bound: past the last page the register returns an ordinary 200 with an empty list, identical to a company that has no officers, so stop when a page comes back empty. Keyed by company_number from search_companies_house. Costs 1 credit.`, {
46
+ server.tool("get_companies_house_officers", `List a UK company's officers (current and resigned). No server-side active filter; check status in response. 35/page, stop on empty page. 1 credit.`, {
46
47
  company_number: companyNumber,
47
48
  page: z.number().int().min(1).optional()
48
- .describe("Results page, 1-based, 35 officers per page. Backend default is 1. No upper bound - a page past the end is a 200 with an empty list, not an error."),
49
+ .describe("Page, 1-based, 35/page. Empty page = no more."),
49
50
  }, call("/api/v1/companieshouse/officers"));
50
- server.tool("get_companies_house_filing_history", `List a UK company's filings from the Companies House register as JSON, most recent first: filing date, filing type code (AA annual accounts, CS01 confirmation statement, SH03 share buyback), description, register annotations and child documents, and a link to the filed PDF with its page count. A filing the register has not finished processing carries a processing_note instead of a document link. Paginated with page and NO upper page bound: past the last page it is an ordinary 200 with an empty list, so stop when a page comes back empty. Keyed by company_number from search_companies_house. Costs 1 credit.`, {
51
+ server.tool("get_companies_house_filing_history", `List a UK company's filing history (most recent first) with PDF links. Stop on empty page. 1 credit.`, {
51
52
  company_number: companyNumber,
52
53
  page: z.number().int().min(1).optional()
53
- .describe("Results page, 1-based. Backend default is 1. No upper bound - a page past the end is a 200 with an empty list, not an error."),
54
+ .describe("Page, 1-based. Empty page = no more."),
54
55
  }, call("/api/v1/companieshouse/filing-history"));
55
56
  }
56
57
  //# sourceMappingURL=companieshouse.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"companieshouse.js","sourceRoot":"","sources":["../../src/tools/companieshouse.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEtD,2EAA2E;AAC3E,cAAc;AACd,EAAE;AACF,4EAA4E;AAC5E,sEAAsE;AACtE,4EAA4E;AAC5E,4EAA4E;AAC5E,iBAAiB;AACjB,EAAE;AACF,8EAA8E;AAC9E,gFAAgF;AAChF,yEAAyE;AACzE,0EAA0E;AAC1E,6EAA6E;AAC7E,+EAA+E;AAC/E,EAAE;AACF,+EAA+E;AAC/E,4EAA4E;AAC5E,2EAA2E;AAC3E,uDAAuD;AAEvD,MAAM,aAAa,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC;KAC5C,QAAQ,CAAC,mTAAmT,CAAC,CAAC;AAEjU,MAAM,UAAU,2BAA2B,CAAC,MAAiB,EAAE,SAA6B;IAC1F,MAAM,IAAI,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,KAAK,EAAE,MAA+B,EAAE,EAAE;QACvE,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,SAAS,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;YAClD,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;QACvF,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,cAAc,CAAC,GAAG,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,wBAAwB,EACxB,wzBAAwzB,EACxzB;QACE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;aAC9B,QAAQ,CAAC,0GAA0G,CAAC;QACvH,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC;aAClC,QAAQ,EAAE;aACV,QAAQ,CAAC,wIAAwI,CAAC;KACtJ,EACD,IAAI,CAAC,+BAA+B,CAAC,CACtC,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,6BAA6B,EAC7B,spBAAspB,EACtpB;QACE,cAAc,EAAE,aAAa;KAC9B,EACD,IAAI,CAAC,gCAAgC,CAAC,CACvC,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,8BAA8B,EAC9B,21BAA21B,EAC31B;QACE,cAAc,EAAE,aAAa;QAC7B,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;aACrC,QAAQ,CAAC,oJAAoJ,CAAC;KAClK,EACD,IAAI,CAAC,iCAAiC,CAAC,CACxC,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,oCAAoC,EACpC,qmBAAqmB,EACrmB;QACE,cAAc,EAAE,aAAa;QAC7B,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;aACrC,QAAQ,CAAC,8HAA8H,CAAC;KAC5I,EACD,IAAI,CAAC,uCAAuC,CAAC,CAC9C,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"companieshouse.js","sourceRoot":"","sources":["../../src/tools/companieshouse.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAEvD,2EAA2E;AAC3E,cAAc;AACd,EAAE;AACF,4EAA4E;AAC5E,sEAAsE;AACtE,4EAA4E;AAC5E,4EAA4E;AAC5E,iBAAiB;AACjB,EAAE;AACF,8EAA8E;AAC9E,gFAAgF;AAChF,yEAAyE;AACzE,0EAA0E;AAC1E,6EAA6E;AAC7E,+EAA+E;AAC/E,EAAE;AACF,+EAA+E;AAC/E,4EAA4E;AAC5E,2EAA2E;AAC3E,uDAAuD;AAEvD,MAAM,aAAa,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC;KAC5C,QAAQ,CAAC,mEAAmE,CAAC,CAAC;AAEjF,MAAM,UAAU,2BAA2B,CAAC,MAAiB,EAAE,SAA6B;IAC1F,MAAM,IAAI,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,KAAK,EAAE,MAA+B,EAAE,EAAE;QACvE,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,SAAS,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;YAClD,OAAO,YAAY,CAAC,IAAI,CAAC,CAAC;QAC5B,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,cAAc,CAAC,GAAG,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,wBAAwB,EACxB,4IAA4I,EAC5I;QACE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;aAC9B,QAAQ,CAAC,uCAAuC,CAAC;QACpD,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC;aAClC,QAAQ,EAAE;aACV,QAAQ,CAAC,iCAAiC,CAAC;KAC/C,EACD,IAAI,CAAC,+BAA+B,CAAC,CACtC,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,6BAA6B,EAC7B,8HAA8H,EAC9H;QACE,cAAc,EAAE,aAAa;KAC9B,EACD,IAAI,CAAC,gCAAgC,CAAC,CACvC,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,8BAA8B,EAC9B,qJAAqJ,EACrJ;QACE,cAAc,EAAE,aAAa;QAC7B,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;aACrC,QAAQ,CAAC,+CAA+C,CAAC;KAC7D,EACD,IAAI,CAAC,iCAAiC,CAAC,CACxC,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,oCAAoC,EACpC,sGAAsG,EACtG;QACE,cAAc,EAAE,aAAa;QAC7B,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;aACrC,QAAQ,CAAC,sCAAsC,CAAC;KACpD,EACD,IAAI,CAAC,uCAAuC,CAAC,CAC9C,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
  // 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,69 +8,59 @@ 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
  export function registerEbayTools(server, getClient) {
10
- server.tool("search_ebay", `Search live or SOLD eBay listings and return them as JSON. Each result carries the item id and URL, title, price and currency, condition, buying format, bid count and time left for auctions, shipping cost and free-shipping flag, seller username with feedback score, image and position, alongside count and total_results.
11
-
12
- Set sold=true to search COMPLETED listings that actually sold. That is the price-research view and the reason to reach for eBay rather than a retail catalogue: it shows what buyers really paid, not what sellers are asking. On the sold view eBay publishes no headline count, so total_results is NULL — count still tells you how many rows came back.
13
-
14
- Either query or seller is required. Passing seller ALONE with no keyword pages that seller's entire catalogue, and this is the only way to enumerate a seller's inventory — get_ebay_seller is a profile card and cannot list items.
15
-
16
- Paginate with page. per_page accepts ONLY 60, 120 or 240; eBay silently falls back to 60 for any other value rather than erroring. category_id must be numeric — an unrecognised id returns the UNFILTERED result set under a 200, so verify the filter took effect. condition 'refurbished' is eBay's parent condition, not one of its three graded tiers. Costs 1 credit per page.`, {
11
+ server.tool("search_ebay", `Search eBay live or sold listings. sold=true for completed-sale price research. Either query or seller required; seller alone pages their catalogue. per_page only 60/120/240. 1 credit/page.`, {
17
12
  query: z.string().min(1).max(500).optional()
18
- .describe("Keyword search, e.g. 'nikon d750 body'. Either this or seller is required; omit it and pass seller alone to page a seller's whole catalogue."),
13
+ .describe("Search keywords. Either this or seller required."),
19
14
  seller: z.string().min(1).max(64).optional()
20
- .describe("Scope results to one eBay seller username. Usable with NO query to page that seller's entire inventory. Either this or query is required."),
15
+ .describe("Seller username. Alone (no query) pages their catalogue."),
21
16
  page: z.number().int().min(1).optional()
22
- .describe("Results page, 1-based. One page per call, 1 credit each."),
17
+ .describe("Page, 1-based."),
23
18
  sort_by: z.enum(["best_match", "ending_soonest", "newly_listed", "price_low", "price_high"]).optional()
24
- .describe("Sort order. Upstream default is 'best_match'. 'Distance: nearest first' is deliberately unavailable — it would rank against our proxy exit, not your location."),
19
+ .describe("Sort order."),
25
20
  min_price: z.number().min(0).optional()
26
- .describe("Minimum price filter, in the listing currency."),
21
+ .describe("Min price."),
27
22
  max_price: z.number().min(0).optional()
28
- .describe("Maximum price filter, in the listing currency."),
23
+ .describe("Max price."),
29
24
  condition: z.enum(["new", "open_box", "refurbished", "used", "for_parts"]).optional()
30
- .describe("Item condition filter. 'refurbished' is eBay's PARENT condition and covers all three graded refurbished tiers; it does not select one of them."),
25
+ .describe("Condition filter."),
31
26
  buying_format: z.enum(["auction", "buy_it_now", "best_offer"]).optional()
32
- .describe("Listing format filter: timed auction, fixed price, or accepts-best-offer."),
27
+ .describe("Listing format."),
33
28
  free_shipping: z.boolean().optional()
34
- .describe("Restrict to listings with free shipping."),
29
+ .describe("Free shipping only."),
35
30
  sold: z.boolean().optional()
36
- .describe("Search COMPLETED listings that sold, instead of live inventory — the price-research view. On this view total_results is NULL because eBay publishes no headline count for it."),
31
+ .describe("Completed sold listings for price research."),
37
32
  category_id: z.string().optional()
38
- .describe("eBay numeric category id (the _sacat value in a browse URL). MUST be numeric — an unrecognised id returns the UNFILTERED set under a 200 rather than an error."),
33
+ .describe("Numeric eBay category id."),
39
34
  per_page: z.union([z.literal(60), z.literal(120), z.literal(240)]).optional()
40
- .describe("Results per page. ONLY 60, 120 or 240 are accepted; eBay silently downgrades anything else to 60. Upstream default is 60."),
35
+ .describe("Results per page. Only 60, 120, 240."),
41
36
  }, async (params) => {
42
37
  try {
43
38
  const data = await getClient().post("/api/v1/ebay/search", params);
44
- return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
39
+ return trimResponse(data);
45
40
  }
46
41
  catch (err) {
47
42
  return handleApiError(err);
48
43
  }
49
44
  });
50
- server.tool("get_ebay_product", `Get one eBay listing in full as JSON: item id and URL, title, price and currency, condition, item specifics (the seller's own spec table), every image, shipping and handling options, the return policy, auction state (bid count, time left, buy-it-now availability, quantity sold and available), and the seller with feedback score and positive-feedback percentage.
51
-
52
- Accepts an eBay item number or a full ebay.com/itm/... URL — tracking query params are discarded for you. This is a single-listing lookup with no pagination. Costs 1 credit.`, {
45
+ server.tool("get_ebay_product", `Get full eBay listing details: specs, images, shipping, auction state, seller info. 1 credit.`, {
53
46
  item_id: z.string().min(1)
54
- .describe("eBay item number, e.g. '335678901234', or a full ebay.com/itm/... URL. Tracking params are stripped."),
47
+ .describe("Item number or ebay.com/itm/ URL."),
55
48
  }, async (params) => {
56
49
  try {
57
50
  const data = await getClient().post("/api/v1/ebay/product", params);
58
- return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
51
+ return trimResponse(data);
59
52
  }
60
53
  catch (err) {
61
54
  return handleApiError(err);
62
55
  }
63
56
  });
64
- server.tool("get_ebay_seller", `Get an eBay seller's profile card as JSON: store name and username, feedback score, positive-feedback percentage, items sold, follower count, location, member-since date and the categories they sell in.
65
-
66
- PROFILE ONLY — this endpoint CANNOT enumerate a catalogue and returns no listings. To read what a seller currently has for sale, call search_ebay with seller set and no query; that path is paginated. Accepts the username exactly as it appears in ebay.com/usr/<name>. No pagination. Costs 1 credit.`, {
57
+ server.tool("get_ebay_seller", `Get eBay seller profile. No listings; use search_ebay with seller param for inventory. 1 credit.`, {
67
58
  seller: z.string().min(1).max(64)
68
- .describe("eBay seller username as it appears in ebay.com/usr/<name>, e.g. 'musicmagpie'."),
59
+ .describe("Seller username."),
69
60
  }, async (params) => {
70
61
  try {
71
62
  const data = await getClient().post("/api/v1/ebay/seller", params);
72
- return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
63
+ return trimResponse(data);
73
64
  }
74
65
  catch (err) {
75
66
  return handleApiError(err);
@@ -1 +1 @@
1
- {"version":3,"file":"ebay.js","sourceRoot":"","sources":["../../src/tools/ebay.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ebay.js","sourceRoot":"","sources":["../../src/tools/ebay.ts"],"names":[],"mappings":"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"}
@@ -1,17 +1,18 @@
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 registerExtractTool(server, getClient) {
4
- server.tool("extract_url", `Read any web page. Returns the page as clean Markdown, plain text, or raw HTML. This is the general read-a-page primitive: point it at any http(s) URL - an article, a docs page, a product page, a changelog, a competitor's pricing page - and get the body back as text you can reason over. Returns { url, format, mode, content, content_length }. Formats: 'markdown' (readability extraction, the default and the best choice for reading), 'text' (that Markdown flattened to plain prose), 'html' (the raw unprocessed page). COST IS TIER-PRICED BY THE mode PARAMETER, NOT FLAT: mode='normal' (plain fetch) costs 1 credit, mode='advanced' (full JavaScript rendering, for React/Vue pages that are empty without it) costs 1 credit, mode='ultra' (residential proxy, for hard bot walls and heavy protection) costs 2 credits. Start at 'normal' and escalate only when the content comes back empty or blocked. Billing happens ONLY on a successful extraction - a dead link, a bot wall or a timeout costs nothing. http(s) URLs only; a bare host like 'example.com' is upgraded to https, and loopback, private, link-local and cloud-metadata hosts are rejected with a 400. Returns the whole page in one call - there is no pagination.`, {
5
+ server.tool("extract_url", `Read any web page as Markdown, text, or HTML. Tier-priced: normal=1cr, advanced(JS render)=1cr, ultra(residential proxy)=2cr. Start normal, escalate on empty/blocked. Only billed on success.`, {
5
6
  url: z.string().min(1).max(2048)
6
- .describe("The page to read. http(s) only; a bare host such as 'example.com' is upgraded to https. Internal, loopback and private-network hosts are rejected with a 400."),
7
+ .describe("http(s) URL. Bare hosts upgraded to https. Private/loopback rejected."),
7
8
  format: z.enum(["html", "markdown", "text"]).optional()
8
- .describe("Output format. 'markdown' = readability extraction of the main content (default, best for reading). 'text' = that Markdown flattened to plain prose. 'html' = the raw unprocessed page."),
9
+ .describe("'markdown' (default), 'text', or 'html'."),
9
10
  mode: z.enum(["normal", "advanced", "ultra"]).optional()
10
- .describe("THE PRICE-BEARING PARAMETER. 'normal' = plain fetch, 1 credit (default). 'advanced' = full JavaScript rendering for pages that are empty without it, 1 credit. 'ultra' = residential proxy for hard bot walls, 2 credits. Escalate only when a cheaper mode returns empty or blocked content."),
11
+ .describe("PRICE-BEARING. 'normal'=1cr (default), 'advanced'=JS render 1cr, 'ultra'=residential 2cr."),
11
12
  }, async (params) => {
12
13
  try {
13
14
  const data = await getClient().post("/api/v1/extract", 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);
@@ -1 +1 @@
1
- {"version":3,"file":"extract.js","sourceRoot":"","sources":["../../src/tools/extract.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEtD,MAAM,UAAU,mBAAmB,CAAC,MAAiB,EAAE,SAA6B;IAClF,MAAM,CAAC,IAAI,CACT,aAAa,EACb,gsCAAgsC,EAChsC;QACE,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC;aAC7B,QAAQ,CAAC,+JAA+J,CAAC;QAC5K,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC,QAAQ,EAAE;aACpD,QAAQ,CAAC,yLAAyL,CAAC;QACtM,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC,QAAQ,EAAE;aACrD,QAAQ,CAAC,+RAA+R,CAAC;KAC7S,EACD,KAAK,EAAE,MAAM,EAAE,EAAE;QACf,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,SAAS,EAAE,CAAC,IAAI,CAAC,iBAAiB,EAAE,MAAM,CAAC,CAAC;YAC/D,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":"extract.js","sourceRoot":"","sources":["../../src/tools/extract.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAEvD,MAAM,UAAU,mBAAmB,CAAC,MAAiB,EAAE,SAA6B;IAClF,MAAM,CAAC,IAAI,CACT,aAAa,EACb,gMAAgM,EAChM;QACE,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC;aAC7B,QAAQ,CAAC,uEAAuE,CAAC;QACpF,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC,QAAQ,EAAE;aACpD,QAAQ,CAAC,0CAA0C,CAAC;QACvD,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC,QAAQ,EAAE;aACrD,QAAQ,CAAC,2FAA2F,CAAC;KACzG,EACD,KAAK,EAAE,MAAM,EAAE,EAAE;QACf,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,SAAS,EAAE,CAAC,IAAI,CAAC,iBAAiB,EAAE,MAAM,CAAC,CAAC;YAC/D,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"}
package/dist/tools/g2.js CHANGED
@@ -1,65 +1,66 @@
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 registerG2Tools(server, getClient) {
4
- server.tool("search_g2_software", `G2, the B2B software review site. Search it for business software products and get ranked rows back as JSON: product name, star rating, review count, vendor, categories, seller description and logo. Every row carries the product_id and slug that get_g2_product and get_g2_reviews take, so this is the entry point when you only have a product name or a category ("CRM", "project management"). Also returns total_results - G2's Products-tab headline, capped at 10000 - and total_by_type, which breaks the same query across products, sellers, categories and discussions. Paginate with the page parameter; limit is capped at 100 results per request. Pass query or url - at least one is required. COSTS 5 CREDITS PER CALL: G2 is the most expensive platform Scavio serves, so search once with a good query rather than probing. A G2 bot wall comes back as an error that was still billed upstream, so retry sparingly.`, {
5
+ server.tool("search_g2_software", `Search G2 B2B software products. 5 credits/call (most expensive platform). Query or url required.`, {
5
6
  query: z.string().min(1).max(200).optional()
6
- .describe("Software search term, e.g. 'project management' or 'notion'. Either this or url is required."),
7
+ .describe("Search term, e.g. 'project management'."),
7
8
  url: z.string().min(1).max(1000).optional()
8
- .describe("Full g2.com search URL to run verbatim, e.g. 'https://www.g2.com/search?query=crm'. Either this or query is required."),
9
+ .describe("g2.com search URL instead of query."),
9
10
  page: z.number().int().min(1).optional()
10
- .describe("Page number (1-indexed). 20 results per page unless limit says otherwise."),
11
+ .describe("Page, 1-based."),
11
12
  limit: z.number().int().min(1).max(100).optional()
12
- .describe("Results per page, 1-100 (default 20). 100 is our hard cap so a single request cannot ask for a multi-megabyte page; G2 itself keeps paginating at any size, so use page to go deeper."),
13
+ .describe("Per page, 1-100. Default 20."),
13
14
  sort: z.enum(["relevance", "popular", "alphabetical", "rating"]).optional()
14
- .describe("Sort order (default 'relevance'). Closed enum on purpose: G2 silently accepts an unknown sort and answers 200 in some unstated order, so an invalid value would look like it worked."),
15
+ .describe("Sort order."),
15
16
  rating: z.number().int().min(1).max(5).optional()
16
- .describe("Only products at or above this star rating (1-5)."),
17
+ .describe("Min star rating."),
17
18
  }, async (params) => {
18
19
  try {
19
20
  const data = await getClient().post("/api/v1/g2/search", params);
20
- return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
21
+ return trimResponse(data);
21
22
  }
22
23
  catch (err) {
23
24
  return handleApiError(err);
24
25
  }
25
26
  });
26
- server.tool("get_g2_product", `G2, the B2B software review site. Get one software product's full G2 profile as JSON: overall rating with the per-star histogram, review count, vendor, description and seller website, pricing editions with parsed amounts, feature groups, categories and breadcrumbs, supported languages, integrations, alternatives, head-to-head comparisons, media, community discussions, and G2's AI-derived pros and cons. THIS ENDPOINT CARRIES NO REVIEW TEXT AT ALL - G2 loads review bodies in a separate frame, so call get_g2_reviews for the actual written reviews. No pagination: one call returns the whole profile. product_id accepts either the slug ('notion') or the numeric G2 id ('82623') as a string; both resolve. Pass product_id or url - at least one is required. COSTS 5 CREDITS PER CALL, the most expensive platform Scavio serves. A G2 bot wall comes back as an error that was still billed upstream, so retry sparingly.`, {
27
+ server.tool("get_g2_product", `Get G2 product profile: ratings, pricing, features, alternatives. No review text; use get_g2_reviews. 5 credits.`, {
27
28
  product_id: z.string().min(1).max(200).optional()
28
- .describe("G2 product slug ('notion') or numeric G2 id as a string ('82623') - both resolve on the same upstream path. Either this or url is required."),
29
+ .describe("Product slug ('notion') or numeric id ('82623')."),
29
30
  url: z.string().min(1).max(1000).optional()
30
- .describe("Full g2.com product URL, e.g. 'https://www.g2.com/products/notion/reviews'. Either this or product_id is required."),
31
+ .describe("g2.com product URL instead of product_id."),
31
32
  }, async (params) => {
32
33
  try {
33
34
  const data = await getClient().post("/api/v1/g2/product", params);
34
- return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
35
+ return trimResponse(data);
35
36
  }
36
37
  catch (err) {
37
38
  return handleApiError(err);
38
39
  }
39
40
  });
40
- server.tool("get_g2_reviews", `G2, the B2B software review site. Get one page of written reviews for a software product as JSON: star rating, title, what the reviewer likes and dislikes, problems solved, reviewer job title, industry and company size, and validated/incentivized flags. This is the ONLY G2 tool that returns review text - get_g2_product deliberately has none. It also carries what the profile page has no form of: exact per-star review counts, pros and cons with per-theme counts, and company_size / role / industry / region / category facets with counts. Reviews are FIXED AT 10 PER PAGE and paginate well past the 10 pages G2's own widget links to, so walk page upward. The rating filter is HALF-STAR-INCLUSIVE: rating=1 returns 0, 0.5 and 1-star reviews. Every filter is a closed enum because an unrecognised filter value MATCHES NOTHING upstream and returns "Reviews (0)", which reads like the product genuinely has no such reviews. Pass product_id or url - at least one is required. COSTS 5 CREDITS PER PAGE, the most expensive platform Scavio serves, so filter down rather than paging blindly.`, {
41
+ server.tool("get_g2_reviews", `Get G2 review text for a product. 10 per page. rating filter is half-star-inclusive. 5 credits/page.`, {
41
42
  product_id: z.string().min(1).max(200).optional()
42
- .describe("G2 product slug ('notion') or numeric G2 id as a string ('82623'). Either this or url is required."),
43
+ .describe("Product slug or numeric id."),
43
44
  url: z.string().min(1).max(1000).optional()
44
- .describe("Full g2.com reviews URL. Either this or product_id is required."),
45
+ .describe("g2.com reviews URL instead of product_id."),
45
46
  page: z.number().int().min(1).optional()
46
- .describe("Page number (1-indexed). Fixed at 10 reviews per page; pages continue well past the 10 G2's own widget links to."),
47
+ .describe("Page, 1-based. 10 per page."),
47
48
  sort: z.enum(["relevance", "newest", "most_helpful", "rating_high", "rating_low"]).optional()
48
- .describe("Review sort order (default 'relevance'). Closed enum: G2 silently accepts an unknown sort and returns a full result set in some unstated order."),
49
+ .describe("Sort order."),
49
50
  rating: z.number().int().min(1).max(5).optional()
50
- .describe("Star bucket, 1-5. HALF-STAR-INCLUSIVE: 1 returns 0, 0.5 and 1-star reviews."),
51
+ .describe("Star bucket. Half-star-inclusive: 1 includes 0-1 stars."),
51
52
  company_size: z.enum(["small_business", "mid_market", "enterprise"]).optional()
52
- .describe("Reviewer company size: small_business (<=50 employees), mid_market (51-1000), enterprise (>1000). An unrecognised value would silently match nothing, hence the closed enum."),
53
+ .describe("small_business <=50, mid_market 51-1000, enterprise >1000."),
53
54
  role: z.enum(["user", "administrator", "executive_sponsor", "internal_consultant", "consultant", "agency", "industry_analyst"]).optional()
54
- .describe("Reviewer's relationship to the product."),
55
+ .describe("Reviewer role."),
55
56
  region: z.enum(["north_america", "europe", "asia", "latin_america", "anz", "middle_east", "africa"]).optional()
56
57
  .describe("Reviewer region."),
57
58
  query: z.string().min(1).max(200).optional()
58
- .describe("Full-text search within this product's reviews. Narrows the review list AND every facet count."),
59
+ .describe("Text search within reviews."),
59
60
  }, async (params) => {
60
61
  try {
61
62
  const data = await getClient().post("/api/v1/g2/reviews", params);
62
- return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
63
+ return trimResponse(data);
63
64
  }
64
65
  catch (err) {
65
66
  return handleApiError(err);
@@ -1 +1 @@
1
- {"version":3,"file":"g2.js","sourceRoot":"","sources":["../../src/tools/g2.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"g2.js","sourceRoot":"","sources":["../../src/tools/g2.ts"],"names":[],"mappings":"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"}
@@ -1,68 +1,69 @@
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
  // employer_id / company / url repeat on three of the four endpoints. `company`
4
5
  // is cosmetic on all of them and does NOT satisfy the identifier requirement —
5
6
  // the backend refine takes employer_id or url only.
6
7
  const employerIdField = z.string().min(1).max(50).optional()
7
- .describe("Glassdoor employer id as a STRING, in any form Glassdoor writes it: '1699', 'E1699' or 'IE1699'. A JSON number is rejected. Get one from resolve_glassdoor_company. Either this or url is required.");
8
+ .describe("Employer id as string, e.g. '1699' or 'E1699'. Not a number. Either this or url required.");
8
9
  const companyField = z.string().min(1).max(200).optional()
9
- .describe("Employer name as it appears in a Glassdoor slug, e.g. 'NIKE'. COSMETIC ONLY - the profile resolves on employer_id alone, and this is ignored entirely when url is set. It does NOT satisfy the employer_id-or-url requirement.");
10
+ .describe("Employer slug name, e.g. 'NIKE'. Cosmetic only.");
10
11
  export function registerGlassdoorTools(server, getClient) {
11
- server.tool("resolve_glassdoor_company", `START HERE for Glassdoor. Search Glassdoor for a company by name and resolve it to the employer_id that every other Glassdoor tool requires. Returns data with ranked, de-duplicated employer matches, each carrying its employer_id, name and profile URL. The employer_id lives only inside Glassdoor's /Overview/ URLs, so call this first unless you already hold one. No pagination - one ranked set per query. Glassdoor is slow and flaky: expect seconds to tens of seconds, and an occasional 502 after as long as ~3 minutes; retry once before giving up. Costs 1 credit.`, {
12
+ server.tool("resolve_glassdoor_company", `Resolve a company name to a Glassdoor employer_id. Start here. Slow (seconds-minutes), retry on 502. 1 credit.`, {
12
13
  query: z.string().min(1).max(120)
13
- .describe("Company name to resolve, e.g. 'Nike'."),
14
+ .describe("Company name, e.g. 'Nike'."),
14
15
  }, async (params) => {
15
16
  try {
16
17
  const data = await getClient().post("/api/v1/glassdoor/companies", params);
17
- return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
18
+ return trimResponse(data);
18
19
  }
19
20
  catch (err) {
20
21
  return handleApiError(err);
21
22
  }
22
23
  });
23
- server.tool("get_glassdoor_company", `Get a Glassdoor employer profile as JSON: description, mission, industry, sector, HQ, size band, revenue band, stock symbol, year founded, overall and per-category ratings, star distribution, CEO approval, awards, FAQ, the five server-rendered reviews, plus reviews_url and salaries_url. THE CHAINING STEP: pass reviews_url or salaries_url back as the url parameter of get_glassdoor_reviews / get_glassdoor_salaries to halve the upstream work those calls do. Requires employer_id or url - company alone is NOT an address and is rejected. Use resolve_glassdoor_company to turn a name into an employer_id. No pagination. Slow (roughly 3-47 seconds) and occasionally 502s; retry once. Costs 1 credit.`, {
24
+ server.tool("get_glassdoor_company", `Get Glassdoor employer profile with ratings, reviews, and reviews_url/salaries_url for chaining. employer_id or url required. Slow; retry on 502. 1 credit.`, {
24
25
  employer_id: employerIdField,
25
26
  company: companyField,
26
27
  url: z.string().min(1).max(500).optional()
27
- .describe("Any glassdoor.com employer URL - /Overview/, /Reviews/ or /Salary/, e.g. 'https://www.glassdoor.com/Overview/Working-at-NIKE-EI_IE1699.11,15.htm'. A non-glassdoor.com host is rejected. Either this or employer_id is required."),
28
+ .describe("Glassdoor employer URL. Either this or employer_id required."),
28
29
  }, async (params) => {
29
30
  try {
30
31
  const data = await getClient().post("/api/v1/glassdoor/company", params);
31
- return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
32
+ return trimResponse(data);
32
33
  }
33
34
  catch (err) {
34
35
  return handleApiError(err);
35
36
  }
36
37
  });
37
- server.tool("get_glassdoor_reviews", `Get Glassdoor employee reviews for one employer as JSON: up to THREE full reviews with per-axis scores, pros, cons, advice to management, job title, location, employment status and employer response - plus complete rating statistics, star distribution, aggregate pro/con highlight terms and per-job-title review counts. HARD CAP OF THREE REVIEWS per call (Glassdoor's login wall) and there is deliberately NO page parameter, so do not attempt to paginate. Move the window with category and employment_status instead, and read filtered_review_count on the response to see how many reviews match. Requires employer_id or url - company alone is NOT an address. Passing the reviews_url from get_glassdoor_company as url skips a fetch. Slow (~75 seconds); retry once on a 502. Costs 1 credit.`, {
38
+ server.tool("get_glassdoor_reviews", `Get Glassdoor reviews (max 3 per call, login wall). No pagination. Use category/employment_status to shift window. Pass reviews_url from get_glassdoor_company as url to skip a fetch. Slow (~75s). 1 credit.`, {
38
39
  employer_id: employerIdField,
39
40
  company: companyField,
40
41
  url: z.string().min(1).max(500).optional()
41
- .describe("Any glassdoor.com employer URL. Preferably the reviews_url returned by get_glassdoor_company, which skips the resolve fetch. A non-glassdoor.com host is rejected. Either this or employer_id is required."),
42
+ .describe("Glassdoor URL. Prefer reviews_url from get_glassdoor_company. Either this or employer_id."),
42
43
  category: z.enum(["career_development", "compensation", "culture", "diversity_and_inclusion", "management", "work_life_balance"]).optional()
43
- .describe("Restrict to reviews Glassdoor files under one topic. Closed set: Glassdoor silently IGNORES an unknown value and serves the unfiltered set under a 200."),
44
+ .describe("Review topic filter."),
44
45
  employment_status: z.enum(["full_time", "part_time", "contract", "intern"]).optional()
45
- .describe("Restrict to one kind of employment. Closed set: Glassdoor silently IGNORES an unknown value and serves the unfiltered set under a 200."),
46
+ .describe("Employment type filter."),
46
47
  }, async (params) => {
47
48
  try {
48
49
  const data = await getClient().post("/api/v1/glassdoor/reviews", params);
49
- return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
50
+ return trimResponse(data);
50
51
  }
51
52
  catch (err) {
52
53
  return handleApiError(err);
53
54
  }
54
55
  });
55
- server.tool("get_glassdoor_salaries", `Get Glassdoor salary data for one employer as JSON, broken down by job title: base-pay and total-pay percentiles P10-P90 with medians called out, sample counts, currency, pay period and last-reported date. These are Glassdoor's ESTIMATES for each job title, not individual reported salaries. Ten job titles per page - pass page for the next ten and read page_count on the response for how many pages exist. Requires employer_id or url - company alone is NOT an address. Passing the salaries_url from get_glassdoor_company as url skips a fetch. Slow (~41 seconds); retry once on a 502. Costs 1 credit per page.`, {
56
+ server.tool("get_glassdoor_salaries", `Get Glassdoor salary estimates by job title (P10-P90 percentiles). 10 titles/page. Pass salaries_url from get_glassdoor_company to skip a fetch. Slow (~41s). 1 credit/page.`, {
56
57
  employer_id: employerIdField,
57
58
  company: companyField,
58
59
  url: z.string().min(1).max(500).optional()
59
- .describe("Any glassdoor.com employer URL. Preferably the salaries_url returned by get_glassdoor_company, which skips the resolve fetch. A non-glassdoor.com host is rejected. Either this or employer_id is required."),
60
+ .describe("Glassdoor URL. Prefer salaries_url from get_glassdoor_company. Either this or employer_id."),
60
61
  page: z.number().int().min(1).optional()
61
- .describe("Results page, 1-based. Ten job titles per page; page_count on the response is how many pages there are. Defaults to 1."),
62
+ .describe("Page, 1-based. 10 titles/page."),
62
63
  }, async (params) => {
63
64
  try {
64
65
  const data = await getClient().post("/api/v1/glassdoor/salaries", params);
65
- return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
66
+ return trimResponse(data);
66
67
  }
67
68
  catch (err) {
68
69
  return handleApiError(err);
@@ -1 +1 @@
1
- {"version":3,"file":"glassdoor.js","sourceRoot":"","sources":["../../src/tools/glassdoor.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"glassdoor.js","sourceRoot":"","sources":["../../src/tools/glassdoor.ts"],"names":[],"mappings":"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"}