fmp-ai-tools 0.2.4-beta.0 → 0.2.4-beta.2

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.
@@ -190,6 +190,25 @@ function toToolResponse(res) {
190
190
  }
191
191
  return JSON.stringify(res.data, null, 2);
192
192
  }
193
+ function limitRows(res, limit2, compare) {
194
+ if (res.success === false || !Array.isArray(res.data)) return res;
195
+ const rows = compare ? [...res.data].sort(compare) : res.data;
196
+ return { ...res, data: rows.slice(0, limit2) };
197
+ }
198
+ function toCappedToolResponse(res, limit2, options = {}) {
199
+ const total = res.success !== false && Array.isArray(res.data) ? res.data.length : 0;
200
+ const capped = limitRows(res, limit2, options.compare);
201
+ if (total <= limit2) return toToolResponse(capped);
202
+ return JSON.stringify(
203
+ {
204
+ data: capped.data,
205
+ truncated: true,
206
+ note: `Showing ${limit2} of ${total} rows. ${options.hint ?? "Increase `limit` to see more."}`
207
+ },
208
+ null,
209
+ 2
210
+ );
211
+ }
193
212
  function toToolError(error) {
194
213
  const message = error instanceof Error ? error.message : String(error);
195
214
  let type = "unknown";
@@ -271,7 +290,7 @@ var quoteDefinitions = [
271
290
  to: z.string().optional().nullable().describe("End date in YYYY-MM-DD format (optional)"),
272
291
  limit: z.number().int().positive().default(30).describe("Max number of most-recent days to return (default 30)")
273
292
  }),
274
- execute: async ({ symbol: symbol2, from, to, limit: limit2 = 30 }) => {
293
+ execute: async ({ symbol: symbol2, from, to, limit: limit2 }) => {
275
294
  const res = await getFMPClient().quote.getHistoricalPrice({
276
295
  symbol: symbol2,
277
296
  from: from ?? void 0,
@@ -281,7 +300,7 @@ var quoteDefinitions = [
281
300
  if (res.success && data && Array.isArray(data.historical)) {
282
301
  return toToolResponse({
283
302
  ...res,
284
- data: { ...data, historical: data.historical.slice(0, limit2) }
303
+ data: { ...data, historical: data.historical.slice(0, limit2 ?? 30) }
285
304
  });
286
305
  }
287
306
  return toToolResponse(res);
@@ -297,7 +316,7 @@ var quoteDefinitions = [
297
316
  to: z.string().optional().nullable().describe("End date in YYYY-MM-DD format (optional)"),
298
317
  limit: z.number().int().positive().default(50).describe("Max number of most-recent bars to return (default 50)")
299
318
  }),
300
- execute: async ({ symbol: symbol2, interval = "5min", from, to, limit: limit2 = 50 }) => {
319
+ execute: async ({ symbol: symbol2, interval = "5min", from, to, limit: limit2 }) => {
301
320
  const res = await getFMPClient().quote.getIntraday({
302
321
  symbol: symbol2,
303
322
  interval,
@@ -305,7 +324,7 @@ var quoteDefinitions = [
305
324
  to: to ?? void 0
306
325
  });
307
326
  if (res.success && Array.isArray(res.data)) {
308
- return toToolResponse({ ...res, data: res.data.slice(0, limit2) });
327
+ return toToolResponse({ ...res, data: res.data.slice(0, limit2 ?? 50) });
309
328
  }
310
329
  return toToolResponse(res);
311
330
  }
@@ -329,9 +348,11 @@ var companyDefinitions = [
329
348
  }),
330
349
  defineTool({
331
350
  name: "getCompanyExecutiveCompensation",
332
- description: "Get the company executive compensation",
333
- inputSchema: symbolSchema,
334
- execute: async ({ symbol: symbol2 }) => toToolResponse(await getFMPClient().company.getExecutiveCompensation(symbol2))
351
+ description: "Get the company executive compensation (at most `limit` records)",
352
+ inputSchema: symbolSchema.extend({
353
+ limit: z.number().int().positive().default(20).describe("Max number of compensation records to return (default 20)")
354
+ }),
355
+ execute: async ({ symbol: symbol2, limit: limit2 }) => toCappedToolResponse(await getFMPClient().company.getExecutiveCompensation(symbol2), limit2 ?? 20)
335
356
  }),
336
357
  defineTool({
337
358
  name: "getStockPeers",
@@ -347,7 +368,7 @@ var statementTool = (name, description, what, call) => defineTool({
347
368
  name,
348
369
  description,
349
370
  inputSchema: z.object({ symbol: symbol(what), period, limit }),
350
- execute: async ({ symbol: symbol2, period: period2, limit: limit2 }) => toToolResponse(await call({ symbol: symbol2, period: period2, limit: limit2 }))
371
+ execute: async ({ symbol: symbol2, period: period2, limit: limit2 }) => toToolResponse(await call({ symbol: symbol2, period: period2, limit: limit2 ?? void 0 }))
351
372
  });
352
373
  var financialDefinitions = [
353
374
  statementTool(
@@ -376,7 +397,7 @@ var financialDefinitions = [
376
397
  ),
377
398
  statementTool(
378
399
  "getFinancialRatios",
379
- "Get financial ratios for a company including profitability, liquidity, and efficiency metrics",
400
+ "Get financial ratios for a company by period: valuation (P/E incl. diluted P/E, PEG, P/B, P/S, P/FCF, EV multiple), profitability margins, liquidity, leverage, efficiency, and per-share metrics",
380
401
  "financial ratios",
381
402
  (args) => getFMPClient().financial.getFinancialRatios(args)
382
403
  ),
@@ -417,7 +438,9 @@ var financialDefinitions = [
417
438
  symbol: symbol("earnings historical"),
418
439
  limit: z.number().default(10).describe("The number of periods to retrieve")
419
440
  }),
420
- execute: async ({ symbol: symbol2, limit: limit2 }) => toToolResponse(await getFMPClient().financial.getEarningsHistorical({ symbol: symbol2, limit: limit2 }))
441
+ execute: async ({ symbol: symbol2, limit: limit2 }) => toToolResponse(
442
+ await getFMPClient().financial.getEarningsHistorical({ symbol: symbol2, limit: limit2 ?? 10 })
443
+ )
421
444
  }),
422
445
  defineTool({
423
446
  name: "getFinancialScores",
@@ -433,7 +456,7 @@ var financialDefinitions = [
433
456
  }),
434
457
  defineTool({
435
458
  name: "getFinancialRatiosTTM",
436
- description: "Get current trailing-twelve-month (TTM) financial ratios for a company (margins, returns, liquidity)",
459
+ description: "Get current trailing-twelve-month (TTM) financial ratios for a company (one snapshot row): valuation (P/E incl. diluted P/E, PEG, P/B, P/S, P/FCF, EV multiple), margins, liquidity, leverage, and per-share metrics",
437
460
  inputSchema: z.object({ symbol: symbol("TTM financial ratios") }),
438
461
  execute: async ({ symbol: symbol2 }) => toToolResponse(await getFMPClient().financial.getFinancialRatiosTTM({ symbol: symbol2 }))
439
462
  }),
@@ -456,29 +479,39 @@ var financialDefinitions = [
456
479
  ];
457
480
  var dateRangeSchema = z.object({
458
481
  from: z.string().optional().nullable().describe("Start date in YYYY-MM-DD format (optional)"),
459
- to: z.string().optional().nullable().describe("End date in YYYY-MM-DD format (optional)")
482
+ to: z.string().optional().nullable().describe("End date in YYYY-MM-DD format (optional)"),
483
+ limit: z.number().int().positive().default(50).describe("Max number of entries to return (default 50)")
460
484
  });
461
485
  var calendarDefinitions = [
462
486
  defineTool({
463
487
  name: "getEarningsCalendar",
464
- description: "Get earnings calendar showing upcoming and recent earnings announcements",
465
- inputSchema: dateRangeSchema,
466
- execute: async ({ from, to }) => toToolResponse(
467
- await getFMPClient().calendar.getEarningsCalendar({
488
+ description: "Get earnings calendar showing upcoming and recent earnings announcements, in date order. A week can hold ~2,000 companies worldwide, so pass `symbols` to look up specific companies (e.g. mega-cap tech) instead of scanning the whole calendar.",
489
+ inputSchema: dateRangeSchema.extend({
490
+ symbols: z.array(z.string().min(1)).optional().nullable().describe('Only return these symbols (e.g., ["AAPL", "MSFT", "NVDA"])')
491
+ }),
492
+ execute: async ({ from, to, symbols, limit: limit2 }) => {
493
+ const res = await getFMPClient().calendar.getEarningsCalendar({
468
494
  from: from ?? void 0,
469
495
  to: to ?? void 0
470
- })
471
- )
496
+ });
497
+ const wanted = symbols?.length ? new Set(symbols.map((s) => s.toUpperCase())) : null;
498
+ const filtered = wanted && res.success !== false && Array.isArray(res.data) ? { ...res, data: res.data.filter((row) => wanted.has(row.symbol.toUpperCase())) } : res;
499
+ return toCappedToolResponse(filtered, limit2 ?? 50, {
500
+ hint: "Rows are in date order. Pass `symbols` to find specific companies, or narrow the date range."
501
+ });
502
+ }
472
503
  }),
473
504
  defineTool({
474
505
  name: "getEconomicCalendar",
475
- description: "Get economic calendar showing upcoming and recent economic events and indicators",
506
+ description: "Get economic calendar showing upcoming and recent economic events and indicators, in date order (at most `limit` entries; narrow the date range for full coverage)",
476
507
  inputSchema: dateRangeSchema,
477
- execute: async ({ from, to }) => toToolResponse(
508
+ execute: async ({ from, to, limit: limit2 }) => toCappedToolResponse(
478
509
  await getFMPClient().calendar.getEconomicsCalendar({
479
510
  from: from ?? void 0,
480
511
  to: to ?? void 0
481
- })
512
+ }),
513
+ limit2 ?? 50,
514
+ { hint: "Rows are in date order; narrow the date range to see the rest." }
482
515
  )
483
516
  })
484
517
  ];
@@ -542,17 +575,32 @@ var economicDefinitions = [
542
575
  var etfDefinitions = [
543
576
  defineTool({
544
577
  name: "getETFHoldings",
545
- description: "Get ETF holdings for a specific ETF symbol, showing the underlying assets and their weights",
578
+ description: "Get the largest holdings of an ETF (by portfolio weight), showing the underlying assets and their weights",
546
579
  inputSchema: z.object({
547
580
  symbol: z.string().min(1, "ETF symbol is required").describe("ETF symbol (e.g., SPY, QQQ, VTI)"),
548
- date: z.string().optional().nullable().describe("Date for holdings in YYYY-MM-DD format (optional)")
581
+ date: z.string().optional().nullable().describe("Holdings date in YYYY-MM-DD format (optional; defaults to the latest filing)"),
582
+ limit: z.number().int().positive().default(50).describe("Max number of holdings to return, largest weight first (default 50)")
549
583
  }),
550
- execute: async ({ symbol: symbol2, date }) => {
584
+ execute: async ({ symbol: symbol2, date, limit: limit2 }) => {
585
+ const client = getFMPClient();
586
+ let holdingsDate = date ?? void 0;
587
+ if (!holdingsDate) {
588
+ const dates = await client.etf.getHoldingDates(symbol2);
589
+ if (dates.success !== false && Array.isArray(dates.data)) {
590
+ holdingsDate = dates.data.reduce(
591
+ (latest, d) => !latest || d.date > latest ? d.date : latest,
592
+ void 0
593
+ );
594
+ }
595
+ }
551
596
  const params = { symbol: symbol2 };
552
- if (date) {
553
- params.date = date;
597
+ if (holdingsDate) {
598
+ params.date = holdingsDate;
554
599
  }
555
- return toToolResponse(await getFMPClient().etf.getHoldings(params));
600
+ return toCappedToolResponse(await client.etf.getHoldings(params), limit2 ?? 50, {
601
+ compare: (a, b) => b.pctVal - a.pctVal,
602
+ hint: `Largest positions first, as of ${holdingsDate ?? "the requested date"}.`
603
+ });
556
604
  }
557
605
  }),
558
606
  defineTool({
@@ -575,14 +623,36 @@ var insiderDefinitions = [
575
623
  execute: async ({ symbol: symbol2, page }) => toToolResponse(await getFMPClient().insider.getInsiderTradesBySymbol(symbol2, page))
576
624
  })
577
625
  ];
626
+ var YEAR_MS = 365 * 24 * 60 * 60 * 1e3;
627
+ var holderKey = (name) => name.toLowerCase().replace(/[^a-z0-9]+/g, " ").replace(/\b(inc|corp|corporation|co|llc|ltd|lp|plc|the)\b/g, " ").replace(/\s+/g, " ").trim();
628
+ function currentHolders(rows) {
629
+ const newest = rows.reduce((max, r) => Math.max(max, Date.parse(r.dateReported) || 0), 0);
630
+ const latest = /* @__PURE__ */ new Map();
631
+ for (const row of rows) {
632
+ const reported = Date.parse(row.dateReported);
633
+ if (!(reported >= newest - YEAR_MS)) continue;
634
+ const key = holderKey(row.holder);
635
+ const prev = latest.get(key);
636
+ if (!prev || reported > Date.parse(prev.dateReported)) latest.set(key, row);
637
+ }
638
+ return [...latest.values()];
639
+ }
578
640
  var institutionalDefinitions = [
579
641
  defineTool({
580
642
  name: "getInstitutionalHolders",
581
- description: "Get institutional holders for a specific stock symbol showing which institutions own shares and their holdings",
643
+ description: "Get a stock's largest current institutional holders by shares held (each holder's latest 13F filing from the past year)",
582
644
  inputSchema: z.object({
583
- symbol: z.string().min(1, "Stock symbol is required").describe("Stock symbol (e.g., AAPL, MSFT, GOOGL)")
645
+ symbol: z.string().min(1, "Stock symbol is required").describe("Stock symbol (e.g., AAPL, MSFT, GOOGL)"),
646
+ limit: z.number().int().positive().default(20).describe("Max number of holders to return, largest first (default 20)")
584
647
  }),
585
- execute: async ({ symbol: symbol2 }) => toToolResponse(await getFMPClient().institutional.getInstitutionalHolders({ symbol: symbol2 }))
648
+ execute: async ({ symbol: symbol2, limit: limit2 }) => {
649
+ const res = await getFMPClient().institutional.getInstitutionalHolders({ symbol: symbol2 });
650
+ const current = res.success !== false && Array.isArray(res.data) ? { ...res, data: currentHolders(res.data) } : res;
651
+ return toCappedToolResponse(current, limit2 ?? 20, {
652
+ compare: (a, b) => b.shares - a.shares,
653
+ hint: "Holders are ordered by shares held, largest first."
654
+ });
655
+ }
586
656
  })
587
657
  ];
588
658
  var empty = z.object({});
@@ -593,9 +663,11 @@ var snapshotDateSchema = z.object({
593
663
  var marketDefinitions = [
594
664
  defineTool({
595
665
  name: "getMarketPerformance",
596
- description: "Get overall market performance data including major indices performance",
597
- inputSchema: empty,
598
- execute: async () => toToolResponse(await getFMPClient().market.getMarketPerformance())
666
+ description: "Get overall market performance data including major indices performance (at most `limit` indices)",
667
+ inputSchema: z.object({
668
+ limit: z.number().int().positive().default(50).describe("Max number of indices to return (default 50)")
669
+ }),
670
+ execute: async ({ limit: limit2 }) => toCappedToolResponse(await getFMPClient().market.getMarketPerformance(), limit2 ?? 50)
599
671
  }),
600
672
  defineTool({
601
673
  name: "getSectorPerformance",
@@ -647,11 +719,11 @@ var newsDefinitions = [
647
719
  to: z.string().optional().nullable().describe("End date in YYYY-MM-DD format (optional)"),
648
720
  limit: z.number().int().positive().default(20).describe("Max number of articles to return (default 20)")
649
721
  }),
650
- execute: async ({ from, to, limit: limit2 = 20 }) => toToolResponse(
722
+ execute: async ({ from, to, limit: limit2 }) => toToolResponse(
651
723
  await getFMPClient().news.getStockNews({
652
724
  from: from ?? void 0,
653
725
  to: to ?? void 0,
654
- limit: limit2
726
+ limit: limit2 ?? 20
655
727
  })
656
728
  )
657
729
  }),
@@ -664,12 +736,12 @@ var newsDefinitions = [
664
736
  to: z.string().optional().nullable().describe("End date in YYYY-MM-DD format (optional)"),
665
737
  limit: z.number().int().positive().default(20).describe("Max number of articles to return (default 20)")
666
738
  }),
667
- execute: async ({ symbols, from, to, limit: limit2 = 20 }) => toToolResponse(
739
+ execute: async ({ symbols, from, to, limit: limit2 }) => toToolResponse(
668
740
  await getFMPClient().news.getStockNewsBySymbol({
669
741
  symbols,
670
742
  from: from ?? void 0,
671
743
  to: to ?? void 0,
672
- limit: limit2
744
+ limit: limit2 ?? 20
673
745
  })
674
746
  )
675
747
  })
@@ -691,8 +763,8 @@ var screenerDefinitions = [
691
763
  isActivelyTrading: z.boolean().optional().nullable().describe("Restrict to actively trading"),
692
764
  limit: z.number().int().positive().default(50).describe("Max number of results to return (default 50)")
693
765
  }),
694
- execute: async ({ limit: limit2 = 50, ...filters }) => {
695
- const params = { limit: limit2 };
766
+ execute: async ({ limit: limit2, ...filters }) => {
767
+ const params = { limit: limit2 ?? 50 };
696
768
  for (const [key, value] of Object.entries(filters)) {
697
769
  if (value !== null && value !== void 0) params[key] = value;
698
770
  }
@@ -709,8 +781,12 @@ var searchDefinitions = [
709
781
  limit: z.number().int().positive().default(10).describe("Max number of results to return (default 10)"),
710
782
  exchange: z.string().optional().nullable().describe('Restrict to a specific exchange (optional, e.g., "NASDAQ")')
711
783
  }),
712
- execute: async ({ query, limit: limit2 = 10, exchange }) => toToolResponse(
713
- await getFMPClient().search.search({ query, limit: limit2, exchange: exchange ?? void 0 })
784
+ execute: async ({ query, limit: limit2, exchange }) => toToolResponse(
785
+ await getFMPClient().search.search({
786
+ query,
787
+ limit: limit2 ?? 10,
788
+ exchange: exchange ?? void 0
789
+ })
714
790
  )
715
791
  })
716
792
  ];
@@ -723,7 +799,9 @@ var analystDefinitions = [
723
799
  period: z.enum(["annual", "quarter"]).default("annual").describe("The period type (annual or quarter)"),
724
800
  limit: z.number().int().positive().default(10).describe("Max number of periods to return (default 10)")
725
801
  }),
726
- execute: async ({ symbol: symbol2, period: period2 = "annual", limit: limit2 = 10 }) => toToolResponse(await getFMPClient().analyst.getEstimates({ symbol: symbol2, period: period2, limit: limit2 }))
802
+ execute: async ({ symbol: symbol2, period: period2 = "annual", limit: limit2 }) => toToolResponse(
803
+ await getFMPClient().analyst.getEstimates({ symbol: symbol2, period: period2, limit: limit2 ?? 10 })
804
+ )
727
805
  }),
728
806
  defineTool({
729
807
  name: "getPriceTargetConsensus",
@@ -740,10 +818,10 @@ var analystDefinitions = [
740
818
  symbol: z.string().min(1).describe("The stock symbol (e.g., AAPL)"),
741
819
  limit: z.number().int().positive().default(20).describe("Max number of grade entries to return (default 20)")
742
820
  }),
743
- execute: async ({ symbol: symbol2, limit: limit2 = 20 }) => {
821
+ execute: async ({ symbol: symbol2, limit: limit2 }) => {
744
822
  const res = await getFMPClient().analyst.getGrades({ symbol: symbol2 });
745
823
  if (res.success && Array.isArray(res.data)) {
746
- return toToolResponse({ ...res, data: res.data.slice(0, limit2) });
824
+ return toToolResponse({ ...res, data: res.data.slice(0, limit2 ?? 20) });
747
825
  }
748
826
  return toToolResponse(res);
749
827
  }
@@ -785,7 +863,7 @@ var technicalDefinitions = [
785
863
  timeframe: z.enum(["1min", "5min", "15min", "30min", "1hour", "4hour", "1day", "1week", "1month"]).default("1day").describe("Bar timeframe"),
786
864
  limit: z.number().int().positive().default(50).describe("Max number of most-recent bars to return (default 50)")
787
865
  }),
788
- execute: async ({ symbol: symbol2, type, periodLength = 10, timeframe = "1day", limit: limit2 = 50 }) => {
866
+ execute: async ({ symbol: symbol2, type, periodLength = 10, timeframe = "1day", limit: limit2 }) => {
789
867
  const res = await getFMPClient().technical.getTechnicalIndicator({
790
868
  symbol: symbol2,
791
869
  type,
@@ -793,12 +871,13 @@ var technicalDefinitions = [
793
871
  timeframe
794
872
  });
795
873
  if (res.success && Array.isArray(res.data)) {
796
- return toToolResponse({ ...res, data: res.data.slice(0, limit2) });
874
+ return toToolResponse({ ...res, data: res.data.slice(0, limit2 ?? 50) });
797
875
  }
798
876
  return toToolResponse(res);
799
877
  }
800
878
  })
801
879
  ];
880
+ var byNameLimit = z.number().int().positive().default(50).describe("Max number of trades to return (default 50)");
802
881
  var symbolSchema3 = z.object({
803
882
  symbol: z.string().min(1, "Stock symbol is required").describe("Stock symbol (e.g., AAPL, MSFT, GOOGL)")
804
883
  });
@@ -820,19 +899,27 @@ var senateHouseDefinitions = [
820
899
  }),
821
900
  defineTool({
822
901
  name: "getSenateTradingByName",
823
- description: "Get senate trading data for a specific senator by name showing their trading activity",
902
+ description: "Get senate trading data for a specific senator by name showing their trading activity (at most `limit` trades)",
824
903
  inputSchema: z.object({
825
- name: z.string().min(1, "Name is required").describe("The name of the senator to get trading data for")
904
+ name: z.string().min(1, "Name is required").describe("The name of the senator to get trading data for"),
905
+ limit: byNameLimit
826
906
  }),
827
- execute: async ({ name }) => toToolResponse(await getFMPClient().senateHouse.getSenateTradingByName({ name }))
907
+ execute: async ({ name, limit: limit2 }) => toCappedToolResponse(
908
+ await getFMPClient().senateHouse.getSenateTradingByName({ name }),
909
+ limit2 ?? 50
910
+ )
828
911
  }),
829
912
  defineTool({
830
913
  name: "getHouseTradingByName",
831
- description: "Get house trading data for a specific representative by name showing their trading activity",
914
+ description: "Get house trading data for a specific representative by name showing their trading activity (at most `limit` trades)",
832
915
  inputSchema: z.object({
833
- name: z.string().min(1, "Name is required").describe("The name of the representative to get trading data for")
916
+ name: z.string().min(1, "Name is required").describe("The name of the representative to get trading data for"),
917
+ limit: byNameLimit
834
918
  }),
835
- execute: async ({ name }) => toToolResponse(await getFMPClient().senateHouse.getHouseTradingByName({ name }))
919
+ execute: async ({ name, limit: limit2 }) => toCappedToolResponse(
920
+ await getFMPClient().senateHouse.getHouseTradingByName({ name }),
921
+ limit2 ?? 50
922
+ )
836
923
  }),
837
924
  defineTool({
838
925
  name: "getSenateTradingRSSFeed",