@scavio/mcp-server 0.13.1 → 0.14.1

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 (98) hide show
  1. package/README.md +23 -10
  2. package/dist/auth/cimd.d.ts +2 -0
  3. package/dist/auth/cimd.js +20 -0
  4. package/dist/auth/cimd.js.map +1 -0
  5. package/dist/auth/provider.d.ts +12 -0
  6. package/dist/auth/provider.js +43 -0
  7. package/dist/auth/provider.js.map +1 -0
  8. package/dist/auth/routes.d.ts +2 -0
  9. package/dist/auth/routes.js +214 -0
  10. package/dist/auth/routes.js.map +1 -0
  11. package/dist/auth/stores.d.ts +33 -0
  12. package/dist/auth/stores.js +69 -0
  13. package/dist/auth/stores.js.map +1 -0
  14. package/dist/index.js +15 -1
  15. package/dist/index.js.map +1 -1
  16. package/dist/lib/client.js +4 -1
  17. package/dist/lib/client.js.map +1 -1
  18. package/dist/lib/env.d.ts +3 -0
  19. package/dist/lib/env.js +4 -0
  20. package/dist/lib/env.js.map +1 -1
  21. package/dist/lib/errors.d.ts +5 -1
  22. package/dist/lib/errors.js +5 -1
  23. package/dist/lib/errors.js.map +1 -1
  24. package/dist/lib/tool-error.js +10 -0
  25. package/dist/lib/tool-error.js.map +1 -1
  26. package/dist/lib/trim-response.d.ts +6 -0
  27. package/dist/lib/trim-response.js +26 -0
  28. package/dist/lib/trim-response.js.map +1 -0
  29. package/dist/tools/airbnb.js +30 -49
  30. package/dist/tools/airbnb.js.map +1 -1
  31. package/dist/tools/amazon.js +11 -18
  32. package/dist/tools/amazon.js.map +1 -1
  33. package/dist/tools/appstore.js +16 -15
  34. package/dist/tools/appstore.js.map +1 -1
  35. package/dist/tools/booking.js +28 -45
  36. package/dist/tools/booking.js.map +1 -1
  37. package/dist/tools/capterra.js +16 -15
  38. package/dist/tools/capterra.js.map +1 -1
  39. package/dist/tools/companieshouse.js +11 -10
  40. package/dist/tools/companieshouse.js.map +1 -1
  41. package/dist/tools/ebay.js +21 -30
  42. package/dist/tools/ebay.js.map +1 -1
  43. package/dist/tools/extract.js +6 -5
  44. package/dist/tools/extract.js.map +1 -1
  45. package/dist/tools/g2.js +23 -22
  46. package/dist/tools/g2.js.map +1 -1
  47. package/dist/tools/glassdoor.js +18 -17
  48. package/dist/tools/glassdoor.js.map +1 -1
  49. package/dist/tools/google.js +154 -153
  50. package/dist/tools/google.js.map +1 -1
  51. package/dist/tools/googleads.js +20 -19
  52. package/dist/tools/googleads.js.map +1 -1
  53. package/dist/tools/googleplay.js +14 -13
  54. package/dist/tools/googleplay.js.map +1 -1
  55. package/dist/tools/homedepot.js +15 -28
  56. package/dist/tools/homedepot.js.map +1 -1
  57. package/dist/tools/indeed.js +20 -39
  58. package/dist/tools/indeed.js.map +1 -1
  59. package/dist/tools/index.d.ts +5 -4
  60. package/dist/tools/index.js +5 -4
  61. package/dist/tools/index.js.map +1 -1
  62. package/dist/tools/instagram.js +59 -58
  63. package/dist/tools/instagram.js.map +1 -1
  64. package/dist/tools/kuaishou.js +47 -46
  65. package/dist/tools/kuaishou.js.map +1 -1
  66. package/dist/tools/linkedin.js +26 -25
  67. package/dist/tools/linkedin.js.map +1 -1
  68. package/dist/tools/metaads.js +21 -20
  69. package/dist/tools/metaads.js.map +1 -1
  70. package/dist/tools/reddit.js +48 -47
  71. package/dist/tools/reddit.js.map +1 -1
  72. package/dist/tools/redfin.js +29 -28
  73. package/dist/tools/redfin.js.map +1 -1
  74. package/dist/tools/sec.js +36 -35
  75. package/dist/tools/sec.js.map +1 -1
  76. package/dist/tools/target.js +19 -40
  77. package/dist/tools/target.js.map +1 -1
  78. package/dist/tools/threads.js +20 -19
  79. package/dist/tools/threads.js.map +1 -1
  80. package/dist/tools/tiktok-shop.js +38 -37
  81. package/dist/tools/tiktok-shop.js.map +1 -1
  82. package/dist/tools/tiktok.js +54 -53
  83. package/dist/tools/tiktok.js.map +1 -1
  84. package/dist/tools/tripadvisor.js +20 -43
  85. package/dist/tools/tripadvisor.js.map +1 -1
  86. package/dist/tools/usage.js +3 -2
  87. package/dist/tools/usage.js.map +1 -1
  88. package/dist/tools/walmart.js +35 -34
  89. package/dist/tools/walmart.js.map +1 -1
  90. package/dist/tools/x.js +44 -43
  91. package/dist/tools/x.js.map +1 -1
  92. package/dist/tools/yelp.js +21 -20
  93. package/dist/tools/yelp.js.map +1 -1
  94. package/dist/tools/youtube.js +77 -76
  95. package/dist/tools/youtube.js.map +1 -1
  96. package/dist/tools/zillow.js +38 -53
  97. package/dist/tools/zillow.js.map +1 -1
  98. 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
  // Redfin - US residential real estate. Three tools, 1 credit each, flat:
4
5
  // property and market read the listing/region PAGE, whose inlined request cache
5
6
  // replaces the ~40 internal calls the page made, which is why a full fact sheet
@@ -22,32 +23,32 @@ import { handleApiError } from "../lib/tool-error.js";
22
23
  /** location OR (region_id AND region_type) - the region halves must travel together. */
23
24
  const regionRef = {
24
25
  location: z.string().min(1).max(500).optional()
25
- .describe("Region to look up: a redfin.com region URL ('https://www.redfin.com/city/30818/TX/Austin', /neighborhood/, /county/, /zipcode/) or a bare 5-digit ZIP ('78701'). CITY NAMES ARE NOT ACCEPTED - 'Austin, TX' will fail. Required unless you pass region_id AND region_type."),
26
+ .describe("Redfin URL or 5-digit ZIP. CITY NAMES NOT ACCEPTED. Required unless region_id+region_type."),
26
27
  region_id: z.number().int().min(1).optional()
27
- .describe("Redfin's internal region id, as returned in region.id by a previous response. NOT a ZIP code - the two are different number spaces, and a ZIP here resolves to another city rather than failing. Must be sent together with region_type."),
28
+ .describe("Redfin region id (NOT a ZIP). Use with region_type."),
28
29
  region_type: z.union([z.literal(1), z.literal(2), z.literal(5), z.literal(6)]).optional()
29
- .describe("Redfin region type: 1 neighborhood, 2 ZIP, 5 county, 6 city. Must be sent together with region_id."),
30
+ .describe("1=neighborhood, 2=ZIP, 5=county, 6=city. Use with region_id."),
30
31
  };
31
32
  export function registerRedfinTools(server, getClient) {
32
33
  const call = (path) => async (params) => {
33
34
  try {
34
35
  const data = await getClient().post(path, params);
35
- return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
36
+ return trimResponse(data);
36
37
  }
37
38
  catch (err) {
38
39
  return handleApiError(err);
39
40
  }
40
41
  };
41
- server.tool("search_redfin", `Search Redfin, the US residential real-estate marketplace, and return listings as JSON: price, price per sqft, beds, baths, living area, lot size, year built, coordinates, listing remarks and full photo galleries. Covers for-sale, sold and for-rent inventory. IMPORTANT: days_on_market is ALWAYS NULL in the response - Redfin does not expose it on this feed, so filter with max_days_on_market / min_days_on_market instead of reading it back. CITY NAMES ARE NOT ACCEPTED: pass \`location\` as a redfin.com region URL (/city/, /neighborhood/, /county/, /zipcode/) or a bare 5-digit ZIP, or pass region_id AND region_type together. Paginated with page + limit, up to 350 listings per page (backend default 100). Every numeric filter is truncated into Redfin's query, so fractional bounds are rejected - 1.5 baths is not expressible. max_days_on_market and min_days_on_market cannot be combined, and sold_within_days is rejected unless listing_status=sold. Costs 1 credit.`, {
42
+ server.tool("search_redfin", `Search Redfin US real estate listings. CITY NAMES NOT ACCEPTED for location. days_on_market is ALWAYS NULL; filter via max/min_days_on_market. sold_within_days only valid with listing_status=sold. 1 credit.`, {
42
43
  ...regionRef,
43
44
  listing_status: z.enum(["for_sale", "sold", "for_rent"]).optional()
44
- .describe("Market to search. Backend default is 'for_sale'."),
45
+ .describe("Default 'for_sale'."),
45
46
  sold_within_days: z.number().int().min(1).optional()
46
- .describe("Sold within the last N days. ONLY valid with listing_status='sold', where the backend defaults it to 90 - sending it on any other listing_status is a 400."),
47
+ .describe("Last N days. ONLY with listing_status=sold, else 400."),
47
48
  page: z.number().int().min(1).optional()
48
- .describe("Results page, 1-based."),
49
+ .describe("Page, 1-based."),
49
50
  limit: z.number().int().min(1).max(350).optional()
50
- .describe("Listings per page, 1-350. Backend default is 100."),
51
+ .describe("Per page, default 100."),
51
52
  sort: z.enum([
52
53
  "recommended",
53
54
  "price_low",
@@ -59,42 +60,42 @@ export function registerRedfinTools(server, getClient) {
59
60
  "price_per_sqft_low",
60
61
  "price_per_sqft_high",
61
62
  ]).optional()
62
- .describe("Result sort order. Backend default is Redfin's own 'recommended' ranking."),
63
+ .describe("Sort order."),
63
64
  min_price: z.number().min(0).optional()
64
- .describe("Minimum price, inclusive. This is monthly rent when listing_status='for_rent'."),
65
+ .describe("Min price (rent if for_rent)."),
65
66
  max_price: z.number().min(0).optional()
66
- .describe("Maximum price, inclusive. This is monthly rent when listing_status='for_rent'."),
67
+ .describe("Max price (rent if for_rent)."),
67
68
  beds_min: z.number().int().min(0).optional()
68
- .describe("Minimum bedrooms. Whole numbers only."),
69
+ .describe("Min bedrooms."),
69
70
  beds_max: z.number().int().min(0).optional()
70
- .describe("Maximum bedrooms. Whole numbers only."),
71
+ .describe("Max bedrooms."),
71
72
  baths_min: z.number().int().min(0).optional()
72
- .describe("Minimum bathrooms, WHOLE baths only - 1.5 is rejected, not rounded."),
73
+ .describe("Min baths, whole only."),
73
74
  sqft_min: z.number().int().min(0).optional()
74
- .describe("Minimum living area in square feet."),
75
+ .describe("Min sqft."),
75
76
  sqft_max: z.number().int().min(0).optional()
76
- .describe("Maximum living area in square feet."),
77
+ .describe("Max sqft."),
77
78
  lot_size_min: z.number().int().min(0).optional()
78
- .describe("Minimum lot size in square feet."),
79
+ .describe("Min lot sqft."),
79
80
  year_built_min: z.number().int().min(0).optional()
80
- .describe("Earliest year built."),
81
+ .describe("Earliest year."),
81
82
  year_built_max: z.number().int().min(0).optional()
82
- .describe("Latest year built."),
83
+ .describe("Latest year."),
83
84
  max_hoa: z.number().min(0).optional()
84
- .describe("Maximum monthly HOA fee in dollars."),
85
+ .describe("Max HOA $/mo."),
85
86
  property_type: z.enum(["house", "condo", "townhouse", "multi_family", "land", "other", "co_op"]).optional()
86
- .describe("Restrict to one property type."),
87
+ .describe("Property type."),
87
88
  has_pool: z.boolean().optional()
88
- .describe("Only listings with a pool."),
89
+ .describe("Pool filter."),
89
90
  max_days_on_market: z.number().int().min(0).optional()
90
- .describe("Listed at most N days ago. Cannot be combined with min_days_on_market - Redfin expresses both through one param, so sending both is a 400."),
91
+ .describe("At most N days. Cannot combine with min."),
91
92
  min_days_on_market: z.number().int().min(0).optional()
92
- .describe("Listed at least N days ago. Cannot be combined with max_days_on_market."),
93
+ .describe("At least N days. Cannot combine with max."),
93
94
  }, call("/api/v1/redfin/search"));
94
- server.tool("get_redfin_property", `Get one Redfin listing (US residential real estate) in full as JSON: price, the Redfin Estimate and rental estimate, the complete MLS fact sheet, price and tax history, listing agents, open houses, schools, climate risk, walkability and location scores, sun exposure, monthly weather, permits, zoning, comparable sales and photos. Takes a Redfin property id or any redfin.com listing URL carrying one - get either from search_redfin. Not paginated. Costs 1 credit, the same as a search page, because it reads the property page's inlined request cache in one fetch.`, {
95
+ server.tool("get_redfin_property", `Full Redfin property detail: estimates, MLS facts, history, schools, comps. 1 credit.`, {
95
96
  property_id: z.string().min(1).max(500)
96
- .describe("Redfin property id ('31295086'), or any redfin.com listing URL carrying one ('https://www.redfin.com/TX/Austin/7644-Parkview-Cir-78731/home/31295086'). Only the id in such a URL is used - Redfin resolves the address itself."),
97
+ .describe("Property id or redfin.com URL."),
97
98
  }, call("/api/v1/redfin/property"));
98
- server.tool("get_redfin_market", `Get Redfin housing-market statistics for a US region as JSON: median list and sale price, median price per sqft, sale-to-list ratio, average number of offers, average days on market, year-over-year movement, Redfin's 0-100 compete score, live inventory broken down by property type, median price and active listings per bedroom count, and Redfin agent presence with aggregate rating. Region-level aggregates only - use search_redfin for individual listings. Addressed exactly like search_redfin: a redfin.com region URL or a bare 5-digit ZIP in \`location\`, or region_id AND region_type together. CITY NAMES ARE NOT ACCEPTED. Not paginated. Costs 1 credit.`, { ...regionRef }, call("/api/v1/redfin/market"));
99
+ server.tool("get_redfin_market", `Redfin housing-market stats for a US region: prices, inventory, compete score. CITY NAMES NOT ACCEPTED. 1 credit.`, { ...regionRef }, call("/api/v1/redfin/market"));
99
100
  }
100
101
  //# sourceMappingURL=redfin.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"redfin.js","sourceRoot":"","sources":["../../src/tools/redfin.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"redfin.js","sourceRoot":"","sources":["../../src/tools/redfin.ts"],"names":[],"mappings":"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"}
package/dist/tools/sec.js CHANGED
@@ -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
  // SEC EDGAR - US Securities and Exchange Commission regulatory filings. Six
4
5
  // tools, 1 credit each, flat: the SEC publishes this data itself and even
5
6
  // include_history, the one call that can buy up to 10 upstream fetches, is
@@ -18,9 +19,9 @@ import { handleApiError } from "../lib/tool-error.js";
18
19
  /** Both spellings are accepted by both fields; one of the two is required. */
19
20
  const filerRef = {
20
21
  cik: z.string().min(1).max(20).optional()
21
- .describe("Filer CIK in any spelling EDGAR uses: '320193', '0000320193' or 'CIK0000320193'. A ticker is accepted here too. Either this or ticker is required."),
22
+ .describe("CIK, e.g. '0000320193'. Ticker also accepted. Either this or ticker required."),
22
23
  ticker: z.string().min(1).max(20).optional()
23
- .describe("Ticker symbol, dotted or dashed ('BRK.B' and 'BRK-B' both resolve). Wins over cik when both are given. Either this or cik is required."),
24
+ .describe("Ticker, e.g. 'AAPL' or 'BRK.B'. Either this or cik required."),
24
25
  };
25
26
  const formItem = z.string().min(1).max(50);
26
27
  const locationCode = z.string().regex(/^[A-Za-z0-9]{2}$/, "must be a 2-character EDGAR location code");
@@ -28,77 +29,77 @@ export function registerSecTools(server, getClient) {
28
29
  const call = (path) => async (params) => {
29
30
  try {
30
31
  const data = await getClient().post(path, 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("resolve_sec_company", `START HERE for SEC EDGAR, the US Securities and Exchange Commission's public filing system. Resolves a ticker ('AAPL') or a company name to the CIK ('0000320193') that every other SEC tool is keyed by. Returns matching filers as JSON: company name, CIK, ticker symbol, listing exchange, and ready-made submissions, company-facts and EDGAR URLs, tiered by how unambiguous the match is (exact symbol, then exact name, then prefix, then substring) with each row carrying its tier as \`match\`. Not paginated - \`limit\` only sizes the response (1-100, default 10). Costs 1 credit.`, {
38
+ server.tool("resolve_sec_company", `Resolve a ticker or company name to a SEC EDGAR CIK. Start here before other SEC tools. 1 credit.`, {
38
39
  query: z.string().min(1).max(200)
39
- .describe("A ticker ('AAPL', 'BRK.B'), a company name, or a fragment of one."),
40
+ .describe("Ticker, company name, or fragment."),
40
41
  limit: z.number().int().min(1).max(100).optional()
41
- .describe("Rows to return, 1-100. Backend default is 10. Sizes the response; this is NOT a page param."),
42
+ .describe("Rows to return (default 10). Not paginated."),
42
43
  exchange: z.enum(["NASDAQ", "NYSE", "OTC", "CBOE"]).optional()
43
- .describe("Restrict to one listing venue. Closed set, matched case-insensitively. Filers the SEC lists with no exchange at all are excluded by ANY value, so omit this to see them."),
44
+ .describe("Filter by exchange. Omit to include filers with no exchange."),
44
45
  }, call("/api/v1/sec/lookup"));
45
- server.tool("get_sec_company", `Get a US SEC EDGAR filer's profile as JSON: legal and former names, SIC industry, filer category, EIN, LEI, state of incorporation, fiscal year end, business and mailing addresses, every ticker with its exchange, which forms it files and how often, plus a preview of its 10 most recent filings. Requires cik or ticker - if you only have a company name, call resolve_sec_company first. Not paginated. Costs 1 credit.`, { ...filerRef }, call("/api/v1/sec/company"));
46
- server.tool("get_sec_filings", `List one US SEC EDGAR filer's filings as JSON: accession number, form and root form, filing and period dates, 8-K item codes, and direct links to the primary document, the filing index and the attachment directory. Paginated with page + limit (1-500 per page, backend default 50). \`form\` matches the form AND its root form here, so '10-K' also returns the 10-K/A amendments - ask for '10-K/A' to get only amendments. EDGAR's "recent" block is not a fixed window (about a decade for a quiet filer, about a year for a prolific one); include_history reaches further back through up to 10 archived shards and is still 1 credit, with \`history_truncated\` set when the filer had more. Requires cik or ticker. Costs 1 credit.`, {
46
+ server.tool("get_sec_company", `Get a SEC EDGAR filer profile: names, industry, addresses, tickers, recent filings. Requires cik or ticker. 1 credit.`, { ...filerRef }, call("/api/v1/sec/company"));
47
+ server.tool("get_sec_filings", `List a SEC EDGAR filer's filings. 'form' matches root too ('10-K' includes 10-K/A). Paginated. include_history reaches archived shards. 1 credit.`, {
47
48
  ...filerRef,
48
49
  form: z.union([formItem, z.array(formItem).min(1).max(25)]).optional()
49
- .describe("Form types to keep: '10-K', ['10-K','10-Q'] or '10-K,8-K'. Matched against the form AND its root form, so '10-K' also returns 10-K/A."),
50
+ .describe("e.g. '10-K', ['10-K','10-Q']. Matches root form too."),
50
51
  date_from: z.string().regex(/^\d{4}-\d{2}-\d{2}$/, "must be YYYY-MM-DD").optional()
51
- .describe("Earliest filing date, inclusive, as YYYY-MM-DD."),
52
+ .describe("Earliest filing date, YYYY-MM-DD."),
52
53
  date_to: z.string().regex(/^\d{4}-\d{2}-\d{2}$/, "must be YYYY-MM-DD").optional()
53
- .describe("Latest filing date, inclusive, as YYYY-MM-DD."),
54
+ .describe("Latest filing date, YYYY-MM-DD."),
54
55
  page: z.number().int().min(1).optional()
55
- .describe("Results page, 1-based."),
56
+ .describe("Page, 1-based."),
56
57
  limit: z.number().int().min(1).max(500).optional()
57
- .describe("Filings per page, 1-500. Backend default is 50."),
58
+ .describe("Per page (default 50)."),
58
59
  include_history: z.boolean().optional()
59
- .describe("Also fetch the archived filing history beyond EDGAR's recent block - up to 10 shards, still 1 credit. Off by default. Check history_truncated in the response to see whether the filer had more."),
60
+ .describe("Fetch archived history beyond the recent block."),
60
61
  }, call("/api/v1/sec/filings"));
61
- server.tool("get_sec_concept", `Get every value a US SEC EDGAR filer reported for one XBRL financial concept as JSON, newest period first, with the form and filing each number came from. XBRL tags are CASE-SENSITIVE: 'netincomeloss' is a 404 upstream, not a match - call get_sec_facts first to list the tags a filer actually reports. Restatements are KEPT, not collapsed, and each row carries the SEC's \`latest\` comparability flag that tells a quarter apart from its year-to-date twin. Here \`form\` is an EXACT match, so '10-K' EXCLUDES 10-K/A - the opposite of get_sec_filings. Not paginated - \`limit\` only sizes the response (1-2000, default 250). Requires cik or ticker. Costs 1 credit.`, {
62
+ server.tool("get_sec_concept", `Get all reported values for one XBRL concept. Tags are CASE-SENSITIVE (use get_sec_facts to discover them). 'form' is EXACT here ('10-K' excludes 10-K/A). 1 credit.`, {
62
63
  ...filerRef,
63
64
  concept: z.string().min(1).max(120).regex(/^[A-Za-z][A-Za-z0-9]*$/, "must be an XBRL tag name, e.g. NetIncomeLoss")
64
- .describe("The XBRL tag to pull, CASE-SENSITIVE: 'NetIncomeLoss', 'Revenues', 'Assets'. Use get_sec_facts to discover valid tags for this filer."),
65
+ .describe("XBRL tag, CASE-SENSITIVE, e.g. 'NetIncomeLoss'."),
65
66
  taxonomy: z.string().min(1).max(40).regex(/^[A-Za-z][A-Za-z0-9-]*$/, "must be an XBRL taxonomy, e.g. us-gaap").optional()
66
- .describe("XBRL taxonomy: 'us-gaap' (backend default), 'dei', 'ifrs-full' or 'srt'."),
67
+ .describe("e.g. 'us-gaap' (default), 'dei', 'ifrs-full'."),
67
68
  unit: z.string().min(1).max(40).optional()
68
- .describe("Keep only facts reported in this unit. A concept can be reported in more than one - per-share figures are 'USD/shares' while the same statement's totals are 'USD'."),
69
+ .describe("Filter by unit, e.g. 'USD' or 'USD/shares'."),
69
70
  form: formItem.optional()
70
- .describe("Keep only facts sourced from this form type. EXACT match here, so '10-K' excludes 10-K/A."),
71
+ .describe("Exact form match ('10-K' excludes 10-K/A)."),
71
72
  limit: z.number().int().min(1).max(2000).optional()
72
- .describe("Facts to return, 1-2000, newest period first. Backend default is 250. Sizes the response; there is no paging."),
73
+ .describe("Facts to return (default 250). Not paginated."),
73
74
  }, call("/api/v1/sec/concept"));
74
- server.tool("get_sec_facts", `Get the index of every XBRL concept a US SEC EDGAR filer reports as JSON - tag, label, description, units and most recent value - across us-gaap, dei and any other taxonomy it uses. This is the discovery step: find the tag here, then pull its full history with get_sec_concept. Not paginated - \`limit\` only sizes the response (1-2000, default 250). Requires cik or ticker. Costs 1 credit.`, {
75
+ server.tool("get_sec_facts", `List all XBRL concepts a filer reports. Discovery step: find tags here, then pull history with get_sec_concept. 1 credit.`, {
75
76
  ...filerRef,
76
77
  taxonomy: z.string().min(1).max(40).optional()
77
- .describe("Restrict to one XBRL taxonomy, e.g. 'us-gaap' or 'dei'. Omit to see every taxonomy the filer uses."),
78
+ .describe("e.g. 'us-gaap', 'dei'. Omit for all."),
78
79
  query: z.string().min(1).max(200).optional()
79
- .describe("Case-insensitive substring match against the tag name and its label, e.g. 'revenue'."),
80
+ .describe("Substring match on tag name/label, e.g. 'revenue'."),
80
81
  limit: z.number().int().min(1).max(2000).optional()
81
- .describe("Concepts to return, 1-2000. Backend default is 250. Sizes the response; there is no paging."),
82
+ .describe("Rows to return (default 250). Not paginated."),
82
83
  }, call("/api/v1/sec/facts"));
83
- server.tool("search_sec_filings", `Full-text search across US SEC EDGAR filing DOCUMENTS. Coverage STARTS IN 2001 - nothing filed earlier is in this index. Each hit comes back as JSON with the document URL, form, filing date and filer identity, plus facets breaking the whole result set down by company, form, industry and state. Accepts NO query at all: a cik, ticker, form or date filter on its own is a valid search. Paginated with page at 100 documents per page and CAPPED AT PAGE 100, because the index refuses a result window past 10,000. Use get_sec_filings instead when you want one known filer's complete filing list rather than a text match. Costs 1 credit.`, {
84
+ server.tool("search_sec_filings", `Full-text search across SEC EDGAR filing documents. Coverage starts 2001. Capped at page 100 (10k docs). Use get_sec_filings for a single filer's list instead. 1 credit.`, {
84
85
  query: z.string().min(1).max(500).optional()
85
- .describe("Full-text query over filing documents. A quoted phrase ('\"climate risk\"') is matched exactly; bare words are matched as a bag of terms. Optional - filters alone are a valid search."),
86
+ .describe("Full-text query. Quoted phrases matched exactly. Optional if filters set."),
86
87
  cik: z.union([z.string().min(1).max(20), z.array(z.string().min(1).max(20)).min(1).max(25)]).optional()
87
- .describe("Restrict to one or more filers by CIK, as a string or an array of up to 25. Tickers are accepted here too."),
88
+ .describe("CIK(s) or ticker(s), string or array up to 25."),
88
89
  ticker: z.union([z.string().min(1).max(20), z.array(z.string().min(1).max(20)).min(1).max(25)]).optional()
89
- .describe("Restrict to one or more filers by ticker symbol, as a string or an array of up to 25."),
90
+ .describe("Ticker(s), string or array up to 25."),
90
91
  form: z.union([formItem, z.array(formItem).min(1).max(25)]).optional()
91
- .describe("Form types to keep: '8-K', ['10-K','10-Q'] or '10-K,10-Q'."),
92
+ .describe("e.g. '8-K' or ['10-K','10-Q']."),
92
93
  date_from: z.string().regex(/^\d{4}-\d{2}-\d{2}$/, "must be YYYY-MM-DD").optional()
93
- .describe("Earliest filing date, inclusive, as YYYY-MM-DD. Full-text coverage starts in 2001."),
94
+ .describe("Earliest filing date, YYYY-MM-DD."),
94
95
  date_to: z.string().regex(/^\d{4}-\d{2}-\d{2}$/, "must be YYYY-MM-DD").optional()
95
- .describe("Latest filing date, inclusive, as YYYY-MM-DD."),
96
+ .describe("Latest filing date, YYYY-MM-DD."),
96
97
  location: z.union([locationCode, z.array(locationCode).min(1).max(25)]).optional()
97
- .describe("Filer business-address locations as EDGAR's own 2-character codes ('CA', 'NY', and its alphanumeric codes for foreign jurisdictions), as a string or an array of up to 25."),
98
+ .describe("EDGAR 2-char location codes, e.g. 'CA', 'NY'."),
98
99
  sort: z.enum(["relevance", "newest", "oldest"]).optional()
99
- .describe("Result ordering. Backend default is the index's own relevance ranking."),
100
+ .describe("Default: relevance."),
100
101
  page: z.number().int().min(1).max(100).optional()
101
- .describe("Results page, 1-based, 100 documents per page. Page 100 is the last page for ANY query - the index refuses a result window past 10,000."),
102
+ .describe("Page, 1-100. 100 docs/page. Max page 100."),
102
103
  }, call("/api/v1/sec/search"));
103
104
  }
104
105
  //# sourceMappingURL=sec.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"sec.js","sourceRoot":"","sources":["../../src/tools/sec.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"sec.js","sourceRoot":"","sources":["../../src/tools/sec.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
  // Every description opens "Target.com, the US retailer" on purpose: read out of
4
5
  // context, a tool called get_target_* is easily taken for "the target of the
5
6
  // operation". The brand has to be established in the first clause, before the
@@ -11,91 +12,69 @@ import { handleApiError } from "../lib/tool-error.js";
11
12
  // text and left for the backend to apply.
12
13
  const SORT_DESCRIPTION = "Sort order. Upstream default is 'relevance'.";
13
14
  const storeIdField = z.string().optional()
14
- .describe("Numeric Target store id. Unlike Walmart, this IS a real request param — it selects the store whose prices, promotions and availability you get back. Upstream default is '3991'.");
15
+ .describe("Target store id for prices/availability. Default '3991'.");
15
16
  export function registerTargetTools(server, getClient) {
16
- server.tool("search_target_products", `Target.com, the US retailer — search its catalogue by keyword and return the product grid as JSON. Each row carries the tcin (Target's product id), title, brand, URL, current price and list price, rating and review count, badges and promotions, image, and seller_id / seller_name.
17
-
18
- seller_id and seller_name are NULL for first-party stock, which is most of Target. NULL means "sold by Target", not missing data — only Target Plus marketplace rows name a third-party vendor.
19
-
20
- Paginate with page. count sets the page size and is capped at 28: Target rejects anything above that outright (upstream default 24). store_id picks the store whose prices and availability you see.
21
-
22
- LATENCY, not price, is the thing to plan around: Target refuses proxy pools and is reached through a headless browser, so a search takes roughly 9 seconds and can hold a concurrency slot much longer under retry. Do not put it in a tight loop. Costs 1 credit per page.`, {
17
+ server.tool("search_target_products", `Search Target.com products. Slow (~9s/call, headless browser). Max 28/page. 1 credit/page.`, {
23
18
  keyword: z.string().min(1).max(500)
24
- .describe("Product search keyword, e.g. 'office chair'."),
19
+ .describe("Search keyword, e.g. 'office chair'."),
25
20
  page: z.number().int().min(1).optional()
26
- .describe("Results page, 1-based. One page per call, 1 credit each."),
21
+ .describe("Page, 1-based."),
27
22
  count: z.number().int().min(1).max(28).optional()
28
- .describe("Products per page, 1-28. Target rejects anything above 28 outright. Upstream default is 24."),
23
+ .describe("Items/page, max 28. Default 24."),
29
24
  sort: z.enum(["relevance", "featured", "price_low", "price_high", "rating_high", "best_seller", "newest"]).optional()
30
25
  .describe(SORT_DESCRIPTION),
31
26
  store_id: storeIdField,
32
27
  }, async (params) => {
33
28
  try {
34
29
  const data = await getClient().post("/api/v1/target/search", params);
35
- return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
30
+ return trimResponse(data);
36
31
  }
37
32
  catch (err) {
38
33
  return handleApiError(err);
39
34
  }
40
35
  });
41
- server.tool("get_target_category", `Target.com, the US retailer — list the products inside one Target category as JSON. Same shape as search_target_products plus the category breadcrumb: tcin, title, brand, URL, price and list price, rating and review count, badges and promotions, image, and seller_id / seller_name.
42
-
43
- seller_id and seller_name are NULL for first-party stock, which is most of Target — NULL means "sold by Target", not missing data.
44
-
45
- category_id is the segment after \`N-\` in a target.com /c/ URL. Paginate with page; count is capped at 28 (upstream default 24). store_id picks the store whose prices and availability you see.
46
-
47
- This is the SLOWEST Target endpoint at roughly 37 seconds per call, with 502-then-retry cases observed near 100 seconds. Use it for catalogue sweeps you can wait on, not for interactive lookups. Costs 1 credit per page.`, {
36
+ server.tool("get_target_category", `List Target.com products in a category. Very slow (~37s/call). Max 28/page. 1 credit/page.`, {
48
37
  category_id: z.string().min(1)
49
- .describe("Target category id — the segment after `N-` in a target.com /c/ URL, e.g. '5xtg6' from /c/office-chairs/-/N-5xtg6."),
38
+ .describe("Segment after N- in target.com /c/ URL, e.g. '5xtg6'."),
50
39
  page: z.number().int().min(1).optional()
51
- .describe("Results page, 1-based. One page per call, 1 credit each."),
40
+ .describe("Page, 1-based."),
52
41
  count: z.number().int().min(1).max(28).optional()
53
- .describe("Products per page, 1-28. Target rejects anything above 28 outright. Upstream default is 24."),
42
+ .describe("Items/page, max 28. Default 24."),
54
43
  sort: z.enum(["relevance", "featured", "price_low", "price_high", "rating_high", "best_seller", "newest"]).optional()
55
44
  .describe(SORT_DESCRIPTION),
56
45
  store_id: storeIdField,
57
46
  }, async (params) => {
58
47
  try {
59
48
  const data = await getClient().post("/api/v1/target/category", params);
60
- return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
49
+ return trimResponse(data);
61
50
  }
62
51
  catch (err) {
63
52
  return handleApiError(err);
64
53
  }
65
54
  });
66
- server.tool("get_target_product", `Target.com, the US retailer — get one product's full detail by TCIN as JSON: title, brand, current price and list price, rating and review count, images, the specification table and feature bullets, variants, the return policy, and fulfillment for the chosen store (ship, order pickup, drive up, same-day delivery).
67
-
68
- Pass a child TCIN and Target answers with its variation PARENT, with the child present in variants — that is the normal response, not a wrong match.
69
-
70
- seller_id / seller_name are NULL for first-party stock, which is most of Target; NULL means "sold by Target". Unlike Walmart, store_id IS a real request param here — prices and availability are your choice.
71
-
72
- Fastest Target endpoint at roughly 4 seconds. Single-product lookup, no pagination. For review bodies call get_target_reviews. Costs 1 credit.`, {
55
+ server.tool("get_target_product", `Get full Target.com product detail by TCIN. Child TCIN returns variation parent. 1 credit.`, {
73
56
  tcin: z.string().min(1)
74
- .describe("Target TCIN, the numeric product id from a target.com /p/ URL, e.g. '54551690'. A child TCIN is answered by its variation parent, with the child listed under variants."),
57
+ .describe("TCIN from target.com /p/ URL, e.g. '54551690'."),
75
58
  store_id: storeIdField,
76
59
  }, async (params) => {
77
60
  try {
78
61
  const data = await getClient().post("/api/v1/target/product", params);
79
- return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
62
+ return trimResponse(data);
80
63
  }
81
64
  catch (err) {
82
65
  return handleApiError(err);
83
66
  }
84
67
  });
85
- server.tool("get_target_reviews", `Target.com, the US retailer — get a product's reviews by TCIN as JSON: the overall rating with its star distribution, per-attribute averages (quality, value, and so on), the recommendation percentage, guest photos, and the review bodies with author, date, rating, title and text.
86
-
87
- HARD CAP: 8 REVIEW BODIES MAXIMUM, no matter how large review_count is. Target publishes no more than that anonymously. There is NO page and NO offset param — \`limit\` only TRIMS the 8 you would already receive, it cannot fetch more. If you need a deep review corpus, this endpoint cannot supply it and no amount of extra calls will change that.
88
-
89
- Roughly 40 seconds per call. Costs 1 credit.`, {
68
+ server.tool("get_target_reviews", `Get Target.com product reviews. HARD CAP: 8 reviews max, no pagination. ~40s/call. 1 credit.`, {
90
69
  tcin: z.string().min(1)
91
- .describe("Target TCIN, the numeric product id from a target.com /p/ URL, e.g. '54551690'."),
70
+ .describe("TCIN, e.g. '54551690'."),
92
71
  limit: z.number().int().min(1).optional()
93
- .describe("TRIMS the returned review bodies only. The ceiling is 8 regardless — Target publishes 8 anonymously and offers no paging, so a limit above 8 changes nothing."),
72
+ .describe("Trim returned reviews. Max 8 regardless."),
94
73
  store_id: storeIdField,
95
74
  }, async (params) => {
96
75
  try {
97
76
  const data = await getClient().post("/api/v1/target/reviews", params);
98
- return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
77
+ return trimResponse(data);
99
78
  }
100
79
  catch (err) {
101
80
  return handleApiError(err);
@@ -1 +1 @@
1
- {"version":3,"file":"target.js","sourceRoot":"","sources":["../../src/tools/target.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"target.js","sourceRoot":"","sources":["../../src/tools/target.ts"],"names":[],"mappings":"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"}
@@ -1,89 +1,90 @@
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
  * The handle surcharge. Threads' upstream handle lookup is dead, so a username
5
6
  * has to be resolved through people search first — a second upstream call, and
6
7
  * 2 extra credits. user_id is always the cheap path.
7
8
  */
8
9
  const usernameField = z.string().min(1).max(60).optional()
9
- .describe("Threads handle without the @, e.g. 'natgeo'. Costs 2 EXTRA credits (4 instead of 2) because the handle must be resolved to a numeric id first. Prefer user_id when you have it. Either username or user_id is required.");
10
+ .describe("Handle without @. Costs 2 EXTRA credits (4 vs 2) due to handle resolution. Prefer user_id. Either username or user_id required.");
10
11
  const userIdField = z.string().min(1).optional()
11
- .describe("Numeric Threads user id, e.g. '63625256886' — the user_id field returned by get_threads_profile or search_threads_users. This is the cheap path: 2 credits. Either username or user_id is required.");
12
+ .describe("Numeric user id from get_threads_profile or search_threads_users. Cheap path: 2 credits. Either username or user_id required.");
12
13
  const cursorField = z.string().optional()
13
- .describe("Pagination cursor. Pass data.next_cursor from the previous response to get the next page.");
14
+ .describe("Cursor from data.next_cursor.");
14
15
  export function registerThreadsTools(server, getClient) {
15
- server.tool("get_threads_profile", `Get a Threads (Meta's text app, threads.net) user profile as JSON. Returns user_id, username, full_name, biography, profile_pic_url, follower_count, is_verified and is_private. Address the user by user_id for 2 credits, or by username for 4 credits — the handle costs 2 extra because Threads' upstream handle lookup is dead and the handle has to be resolved through people search first. Resolve a handle to a user_id once with search_threads_users, then reuse that user_id across calls to stay on the 2-credit path. Pass exactly one of username or user_id: sending neither, or both in conflict, returns 422; an unknown user returns 404. Not paginated.`, {
16
+ server.tool("get_threads_profile", `Get a Threads user profile. 2 credits by user_id, 4 by username (handle resolution surcharge). Pass one of username or user_id.`, {
16
17
  username: usernameField,
17
18
  user_id: userIdField,
18
19
  }, async (params) => {
19
20
  try {
20
21
  const data = await getClient().post("/api/v1/threads/profile", params);
21
- return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
22
+ return trimResponse(data);
22
23
  }
23
24
  catch (err) {
24
25
  return handleApiError(err);
25
26
  }
26
27
  });
27
- server.tool("get_threads_user_posts", `List a Threads user's own posts as JSON. Returns data.posts, each with post_id, code, text, taken_at, like_count, reply_count, repost_count, media_type, cover_url, video_url and the author object (user_id, username, full_name, follower_count, is_verified). Cursor-paginated: pass data.next_cursor back as cursor while data.has_more is true. Costs 2 credits per page when addressed by user_id, or 4 credits per page when addressed by username — the handle costs 2 extra because it has to be resolved to a numeric id first, so resolve once and page by user_id. Pass exactly one of username or user_id (422 otherwise, 404 for an unknown user).`, {
28
+ server.tool("get_threads_user_posts", `List a Threads user's posts. Cursor-paginated. 2 credits/page by user_id, 4 by username.`, {
28
29
  username: usernameField,
29
30
  user_id: userIdField,
30
31
  cursor: cursorField,
31
32
  }, async (params) => {
32
33
  try {
33
34
  const data = await getClient().post("/api/v1/threads/user/posts", 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_threads_user_replies", `List the replies a Threads user has written to other people's posts, as JSON — the "Replies" tab of their profile, not their own posts (use get_threads_user_posts for those). Returns data.posts, each with post_id, code, text, taken_at, like_count, reply_count, repost_count, media_type, cover_url, video_url and the author object. Cursor-paginated: pass data.next_cursor back as cursor while data.has_more is true. Costs 2 credits per page when addressed by user_id, or 4 credits per page when addressed by username — the handle costs 2 extra because it has to be resolved to a numeric id first. Pass exactly one of username or user_id (422 otherwise, 404 for an unknown user).`, {
41
+ server.tool("get_threads_user_replies", `List replies a Threads user wrote to others (the Replies tab, not their own posts). Cursor-paginated. 2 credits/page by user_id, 4 by username.`, {
41
42
  username: usernameField,
42
43
  user_id: userIdField,
43
44
  cursor: cursorField,
44
45
  }, async (params) => {
45
46
  try {
46
47
  const data = await getClient().post("/api/v1/threads/user/replies", params);
47
- return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
48
+ return trimResponse(data);
48
49
  }
49
50
  catch (err) {
50
51
  return handleApiError(err);
51
52
  }
52
53
  });
53
- server.tool("get_threads_post", `Get a single Threads post by its id or its threads.net URL, as JSON. Returns a flat post object: post_id, code, text, taken_at, like_count, reply_count, repost_count, media_type, cover_url, video_url and the author (user_id, username, full_name, biography, follower_count, is_verified, is_private). Does NOT return the replies — call get_threads_post_comments with the post_id for those. Pass exactly one of post_id or url; sending neither returns 422. Always costs 2 credits (there is no handle surcharge on this tool). Not paginated.`, {
54
+ server.tool("get_threads_post", `Get a Threads post by id or URL. Does NOT return replies (use get_threads_post_comments). Pass post_id or url. 2 credits.`, {
54
55
  post_id: z.string().min(1).optional()
55
- .describe("Threads post id, e.g. '3349029093483693129'. Either this or url is required."),
56
+ .describe("Post id. Either this or url required."),
56
57
  url: z.string().url().optional()
57
- .describe("Full threads.net post URL, e.g. 'https://www.threads.net/@natgeo/post/C8xY'. Either this or post_id is required."),
58
+ .describe("threads.net post URL. Either this or post_id required."),
58
59
  }, async (params) => {
59
60
  try {
60
61
  const data = await getClient().post("/api/v1/threads/post", params);
61
- return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
62
+ return trimResponse(data);
62
63
  }
63
64
  catch (err) {
64
65
  return handleApiError(err);
65
66
  }
66
67
  });
67
- server.tool("get_threads_post_comments", `List the replies to a Threads post as JSON. Returns data.comments, each with post_id, code, text, taken_at, like_count, reply_count, repost_count, media_type, cover_url, video_url and the author object (user_id, username, full_name, follower_count, is_verified). Cursor-paginated: pass data.next_cursor back as cursor while data.has_more is true. Takes a post_id only — there is no username or URL form here; get the post_id from get_threads_post, get_threads_user_posts or a threads.net URL. Always costs 2 credits per page.`, {
68
+ server.tool("get_threads_post_comments", `List replies to a Threads post. Cursor-paginated. Takes post_id only (no URL form). 2 credits/page.`, {
68
69
  post_id: z.string().min(1)
69
- .describe("Threads post id, e.g. '3349029093483693129'. Required — this tool does not accept a URL."),
70
+ .describe("Post id (no URL form on this endpoint)."),
70
71
  cursor: cursorField,
71
72
  }, async (params) => {
72
73
  try {
73
74
  const data = await getClient().post("/api/v1/threads/post/comments", params);
74
- return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
75
+ return trimResponse(data);
75
76
  }
76
77
  catch (err) {
77
78
  return handleApiError(err);
78
79
  }
79
80
  });
80
- server.tool("search_threads_users", `Search Threads PROFILES by name or handle, as JSON. Returns data.users, each with user_id, username, full_name, biography, profile_pic_url, follower_count, is_verified and is_private. This is people search and it is the ONLY search Threads exposes — there is no post or content search on Threads, so this tool cannot find posts by keyword, hashtag or topic. Its main use is resolving a handle to a numeric user_id once, so that get_threads_profile, get_threads_user_posts and get_threads_user_replies can be called on the cheap 2-credit user_id path instead of the 4-credit username path. Costs 2 credits. Not paginated — one result set per query.`, {
81
+ server.tool("search_threads_users", `Search Threads profiles by name/handle. People search ONLY (no post/content search on Threads). Use to resolve a handle to user_id for cheaper calls. 2 credits.`, {
81
82
  query: z.string().min(1).max(200)
82
- .describe("Name or handle to search for, e.g. 'national geographic' or 'natgeo'."),
83
+ .describe("Name or handle to search for."),
83
84
  }, async (params) => {
84
85
  try {
85
86
  const data = await getClient().post("/api/v1/threads/search/users", params);
86
- return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
87
+ return trimResponse(data);
87
88
  }
88
89
  catch (err) {
89
90
  return handleApiError(err);