fixparser-plugin-mcp 9.1.7-38cee007 → 9.1.7-3c6fd297

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.
@@ -132,7 +132,7 @@ var toolSchemas = {
132
132
  }
133
133
  },
134
134
  executeOrder: {
135
- description: "Executes a verified order. verifyOrder must be called before executeOrder.",
135
+ description: "Executes a verified order. verifyOrder must be called before executeOrder. user has to explicitly allow executeOrder.",
136
136
  schema: {
137
137
  type: "object",
138
138
  properties: {
@@ -276,330 +276,7 @@ var toolSchemas = {
276
276
  },
277
277
  required: ["symbol"]
278
278
  }
279
- },
280
- technicalAnalysis: {
281
- description: "Performs comprehensive technical analysis on market data for a given symbol, including indicators like SMA, EMA, RSI, Bollinger Bands, and trading signals",
282
- schema: {
283
- type: "object",
284
- properties: {
285
- symbol: {
286
- type: "string",
287
- description: "The trading symbol to analyze (e.g., AAPL, MSFT, EURUSD)"
288
- }
289
- },
290
- required: ["symbol"]
291
- }
292
- }
293
- };
294
-
295
- // src/tools/analytics.ts
296
- function sum(numbers) {
297
- return numbers.reduce((acc, val) => acc + val, 0);
298
- }
299
- var TechnicalAnalyzer = class {
300
- prices;
301
- volumes;
302
- highs;
303
- lows;
304
- constructor(data) {
305
- this.prices = data.map((d) => d.trade > 0 ? d.trade : d.midPrice);
306
- this.volumes = data.map((d) => d.volume);
307
- this.highs = data.map((d) => d.tradingSessionHighPrice > 0 ? d.tradingSessionHighPrice : d.trade);
308
- this.lows = data.map((d) => d.tradingSessionLowPrice > 0 ? d.tradingSessionLowPrice : d.trade);
309
- }
310
- // Calculate Simple Moving Average
311
- calculateSMA(data, period) {
312
- const sma = [];
313
- for (let i = period - 1; i < data.length; i++) {
314
- const sum2 = data.slice(i - period + 1, i + 1).reduce((a, b) => a + b, 0);
315
- sma.push(sum2 / period);
316
- }
317
- return sma;
318
- }
319
- // Calculate Exponential Moving Average
320
- calculateEMA(data, period) {
321
- const multiplier = 2 / (period + 1);
322
- const ema = [data[0]];
323
- for (let i = 1; i < data.length; i++) {
324
- ema.push(data[i] * multiplier + ema[i - 1] * (1 - multiplier));
325
- }
326
- return ema;
327
- }
328
- // Calculate RSI
329
- calculateRSI(data, period = 14) {
330
- if (data.length < period + 1) return [];
331
- const changes = [];
332
- for (let i = 1; i < data.length; i++) {
333
- changes.push(data[i] - data[i - 1]);
334
- }
335
- const gains = changes.map((change) => change > 0 ? change : 0);
336
- const losses = changes.map((change) => change < 0 ? Math.abs(change) : 0);
337
- let avgGain = gains.slice(0, period).reduce((a, b) => a + b, 0) / period;
338
- let avgLoss = losses.slice(0, period).reduce((a, b) => a + b, 0) / period;
339
- const rsi = [];
340
- for (let i = period; i < changes.length; i++) {
341
- const rs = avgGain / avgLoss;
342
- rsi.push(100 - 100 / (1 + rs));
343
- avgGain = (avgGain * (period - 1) + gains[i]) / period;
344
- avgLoss = (avgLoss * (period - 1) + losses[i]) / period;
345
- }
346
- return rsi;
347
- }
348
- // Calculate Bollinger Bands
349
- calculateBollingerBands(data, period = 20, stdDev = 2) {
350
- if (data.length < period) return [];
351
- const sma = this.calculateSMA(data, period);
352
- const bands = [];
353
- for (let i = 0; i < sma.length; i++) {
354
- const dataSlice = data.slice(i, i + period);
355
- const mean = sma[i];
356
- const variance = dataSlice.reduce((sum2, price) => sum2 + (price - mean) ** 2, 0) / period;
357
- const standardDeviation = Math.sqrt(variance);
358
- bands.push({
359
- upper: mean + standardDeviation * stdDev,
360
- middle: mean,
361
- lower: mean - standardDeviation * stdDev
362
- });
363
- }
364
- return bands;
365
- }
366
- // Calculate maximum drawdown
367
- calculateMaxDrawdown(prices) {
368
- let maxPrice = prices[0];
369
- let maxDrawdown = 0;
370
- for (let i = 1; i < prices.length; i++) {
371
- if (prices[i] > maxPrice) {
372
- maxPrice = prices[i];
373
- }
374
- const drawdown = (maxPrice - prices[i]) / maxPrice;
375
- if (drawdown > maxDrawdown) {
376
- maxDrawdown = drawdown;
377
- }
378
- }
379
- return maxDrawdown;
380
- }
381
- // Calculate price changes for volatility
382
- calculatePriceChanges() {
383
- const changes = [];
384
- for (let i = 1; i < this.prices.length; i++) {
385
- changes.push((this.prices[i] - this.prices[i - 1]) / this.prices[i - 1]);
386
- }
387
- return changes;
388
- }
389
- // Generate comprehensive market analysis
390
- analyze() {
391
- const currentPrice = this.prices[this.prices.length - 1];
392
- const startPrice = this.prices[0];
393
- const sessionHigh = Math.max(...this.highs);
394
- const sessionLow = Math.min(...this.lows);
395
- const totalVolume = sum(this.volumes);
396
- const avgVolume = totalVolume / this.volumes.length;
397
- const priceChanges = this.calculatePriceChanges();
398
- const volatility = priceChanges.length > 0 ? Math.sqrt(
399
- priceChanges.reduce((sum2, change) => sum2 + change ** 2, 0) / priceChanges.length
400
- ) * Math.sqrt(252) * 100 : 0;
401
- const sessionReturn = (currentPrice - startPrice) / startPrice * 100;
402
- const pricePosition = (currentPrice - sessionLow) / (sessionHigh - sessionLow) * 100;
403
- const trueVWAP = this.prices.reduce((sum2, price, i) => sum2 + price * this.volumes[i], 0) / totalVolume;
404
- const momentum5 = this.prices.length > 5 ? (currentPrice - this.prices[Math.max(0, this.prices.length - 6)]) / this.prices[Math.max(0, this.prices.length - 6)] * 100 : 0;
405
- const momentum10 = this.prices.length > 10 ? (currentPrice - this.prices[Math.max(0, this.prices.length - 11)]) / this.prices[Math.max(0, this.prices.length - 11)] * 100 : 0;
406
- const maxDrawdown = this.calculateMaxDrawdown(this.prices);
407
- return {
408
- currentPrice,
409
- startPrice,
410
- sessionHigh,
411
- sessionLow,
412
- totalVolume,
413
- avgVolume,
414
- volatility,
415
- sessionReturn,
416
- pricePosition,
417
- trueVWAP,
418
- momentum5,
419
- momentum10,
420
- maxDrawdown
421
- };
422
- }
423
- // Generate technical indicators
424
- getTechnicalIndicators() {
425
- return {
426
- sma5: this.calculateSMA(this.prices, 5),
427
- sma10: this.calculateSMA(this.prices, 10),
428
- ema8: this.calculateEMA(this.prices, 8),
429
- ema21: this.calculateEMA(this.prices, 21),
430
- rsi: this.calculateRSI(this.prices, 14),
431
- bollinger: this.calculateBollingerBands(this.prices, 20, 2)
432
- };
433
- }
434
- // Generate trading signals
435
- generateSignals() {
436
- const analysis = this.analyze();
437
- let bullishSignals = 0;
438
- let bearishSignals = 0;
439
- const signals = [];
440
- if (analysis.currentPrice > analysis.trueVWAP) {
441
- signals.push(
442
- `\u2713 BULLISH: Price above VWAP (+${((analysis.currentPrice - analysis.trueVWAP) / analysis.trueVWAP * 100).toFixed(2)}%)`
443
- );
444
- bullishSignals++;
445
- } else {
446
- signals.push(
447
- `\u2717 BEARISH: Price below VWAP (${((analysis.currentPrice - analysis.trueVWAP) / analysis.trueVWAP * 100).toFixed(2)}%)`
448
- );
449
- bearishSignals++;
450
- }
451
- if (analysis.momentum5 > 0 && analysis.momentum10 > 0) {
452
- signals.push("\u2713 BULLISH: Positive momentum on both timeframes");
453
- bullishSignals++;
454
- } else if (analysis.momentum5 < 0 && analysis.momentum10 < 0) {
455
- signals.push("\u2717 BEARISH: Negative momentum on both timeframes");
456
- bearishSignals++;
457
- } else {
458
- signals.push("\u25D0 MIXED: Conflicting momentum signals");
459
- }
460
- const currentVolume = this.volumes[this.volumes.length - 1];
461
- const volumeRatio = currentVolume / analysis.avgVolume;
462
- if (volumeRatio > 1.2 && analysis.sessionReturn > 0) {
463
- signals.push("\u2713 BULLISH: Above-average volume supporting upward move");
464
- bullishSignals++;
465
- } else if (volumeRatio > 1.2 && analysis.sessionReturn < 0) {
466
- signals.push("\u2717 BEARISH: Above-average volume supporting downward move");
467
- bearishSignals++;
468
- } else {
469
- signals.push("\u25D0 NEUTRAL: Volume not providing clear direction");
470
- }
471
- if (analysis.pricePosition > 65 && analysis.volatility > 30) {
472
- signals.push("\u2717 BEARISH: High in range with elevated volatility - reversal risk");
473
- bearishSignals++;
474
- } else if (analysis.pricePosition < 35 && analysis.volatility > 30) {
475
- signals.push("\u2713 BULLISH: Low in range with volatility - potential bounce");
476
- bullishSignals++;
477
- } else {
478
- signals.push("\u25D0 NEUTRAL: Price position and volatility not extreme");
479
- }
480
- return { bullishSignals, bearishSignals, signals };
481
279
  }
482
- // Generate comprehensive JSON analysis
483
- generateJSONAnalysis(symbol) {
484
- const analysis = this.analyze();
485
- const indicators = this.getTechnicalIndicators();
486
- const signals = this.generateSignals();
487
- const currentSMA5 = indicators.sma5.length > 0 ? indicators.sma5[indicators.sma5.length - 1] : null;
488
- const currentSMA10 = indicators.sma10.length > 0 ? indicators.sma10[indicators.sma10.length - 1] : null;
489
- const currentEMA8 = indicators.ema8[indicators.ema8.length - 1];
490
- const currentEMA21 = indicators.ema21[indicators.ema21.length - 1];
491
- const currentRSI = indicators.rsi.length > 0 ? indicators.rsi[indicators.rsi.length - 1] : null;
492
- const currentBB = indicators.bollinger.length > 0 ? indicators.bollinger[indicators.bollinger.length - 1] : null;
493
- const currentVolume = this.volumes[this.volumes.length - 1];
494
- const volumeRatio = currentVolume / analysis.avgVolume;
495
- const currentDrawdown = (analysis.sessionHigh - analysis.currentPrice) / analysis.sessionHigh * 100;
496
- const rangeWidth = (analysis.sessionHigh - analysis.sessionLow) / analysis.sessionLow * 100;
497
- const priceVsVWAP = (analysis.currentPrice - analysis.trueVWAP) / analysis.trueVWAP * 100;
498
- const totalScore = signals.bullishSignals - signals.bearishSignals;
499
- const overallSignal = totalScore > 0 ? "BULLISH_BIAS" : totalScore < 0 ? "BEARISH_BIAS" : "NEUTRAL";
500
- const targetEntry = Math.max(analysis.sessionLow * 1.005, analysis.trueVWAP * 0.998);
501
- const stopLoss = analysis.sessionLow * 0.995;
502
- const profitTarget = analysis.sessionHigh * 0.995;
503
- const riskRewardRatio = (profitTarget - analysis.currentPrice) / (analysis.currentPrice - stopLoss);
504
- return {
505
- symbol,
506
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
507
- marketStructure: {
508
- currentPrice: analysis.currentPrice,
509
- startPrice: analysis.startPrice,
510
- sessionHigh: analysis.sessionHigh,
511
- sessionLow: analysis.sessionLow,
512
- rangeWidth,
513
- totalVolume: analysis.totalVolume,
514
- sessionPerformance: analysis.sessionReturn,
515
- positionInRange: analysis.pricePosition
516
- },
517
- volatility: {
518
- impliedVolatility: analysis.volatility,
519
- maxDrawdown: analysis.maxDrawdown * 100,
520
- currentDrawdown
521
- },
522
- technicalIndicators: {
523
- sma5: currentSMA5,
524
- sma10: currentSMA10,
525
- ema8: currentEMA8,
526
- ema21: currentEMA21,
527
- rsi: currentRSI,
528
- bollingerBands: currentBB ? {
529
- upper: currentBB.upper,
530
- middle: currentBB.middle,
531
- lower: currentBB.lower,
532
- position: (analysis.currentPrice - currentBB.lower) / (currentBB.upper - currentBB.lower) * 100
533
- } : null
534
- },
535
- volumeAnalysis: {
536
- currentVolume,
537
- averageVolume: Math.round(analysis.avgVolume),
538
- volumeRatio,
539
- trueVWAP: analysis.trueVWAP,
540
- priceVsVWAP
541
- },
542
- momentum: {
543
- momentum5: analysis.momentum5,
544
- momentum10: analysis.momentum10,
545
- sessionROC: analysis.sessionReturn
546
- },
547
- tradingSignals: {
548
- ...signals,
549
- overallSignal,
550
- signalScore: totalScore
551
- },
552
- riskManagement: {
553
- targetEntry,
554
- stopLoss,
555
- profitTarget,
556
- riskRewardRatio
557
- }
558
- };
559
- }
560
- };
561
- var createTechnicalAnalysisHandler = (marketDataPrices) => {
562
- return async (args) => {
563
- try {
564
- const symbol = args.symbol;
565
- const priceHistory = marketDataPrices.get(symbol) || [];
566
- if (priceHistory.length === 0) {
567
- return {
568
- content: [
569
- {
570
- type: "text",
571
- text: `No price data available for ${symbol}. Please request market data first.`,
572
- uri: "technicalAnalysis"
573
- }
574
- ]
575
- };
576
- }
577
- const analyzer = new TechnicalAnalyzer(priceHistory);
578
- const analysis = analyzer.generateJSONAnalysis(symbol);
579
- return {
580
- content: [
581
- {
582
- type: "text",
583
- text: `Technical Analysis for ${symbol}:
584
-
585
- ${JSON.stringify(analysis, null, 2)}`,
586
- uri: "technicalAnalysis"
587
- }
588
- ]
589
- };
590
- } catch (error) {
591
- return {
592
- content: [
593
- {
594
- type: "text",
595
- text: `Error performing technical analysis: ${error instanceof Error ? error.message : "Unknown error"}`,
596
- uri: "technicalAnalysis"
597
- }
598
- ],
599
- isError: true
600
- };
601
- }
602
- };
603
280
  };
604
281
 
605
282
  // src/tools/marketData.ts
@@ -608,63 +285,10 @@ import QuickChart from "quickchart-js";
608
285
  var createMarketDataRequestHandler = (parser, pendingRequests) => {
609
286
  return async (args) => {
610
287
  try {
611
- parser.logger.log({
612
- level: "info",
613
- message: `Sending market data request for symbols: ${args.symbols.join(", ")}`
614
- });
615
288
  const response = new Promise((resolve) => {
616
289
  pendingRequests.set(args.mdReqID, resolve);
617
- parser.logger.log({
618
- level: "info",
619
- message: `Registered callback for market data request ID: ${args.mdReqID}`
620
- });
621
290
  });
622
- const entryTypes = args.mdEntryTypes || [
623
- MDEntryType.Bid,
624
- MDEntryType.Offer,
625
- MDEntryType.Trade,
626
- MDEntryType.IndexValue,
627
- MDEntryType.OpeningPrice,
628
- MDEntryType.ClosingPrice,
629
- MDEntryType.SettlementPrice,
630
- MDEntryType.TradingSessionHighPrice,
631
- MDEntryType.TradingSessionLowPrice,
632
- MDEntryType.VWAP,
633
- MDEntryType.Imbalance,
634
- MDEntryType.TradeVolume,
635
- MDEntryType.OpenInterest,
636
- MDEntryType.CompositeUnderlyingPrice,
637
- MDEntryType.SimulatedSellPrice,
638
- MDEntryType.SimulatedBuyPrice,
639
- MDEntryType.MarginRate,
640
- MDEntryType.MidPrice,
641
- MDEntryType.EmptyBook,
642
- MDEntryType.SettleHighPrice,
643
- MDEntryType.SettleLowPrice,
644
- MDEntryType.PriorSettlePrice,
645
- MDEntryType.SessionHighBid,
646
- MDEntryType.SessionLowOffer,
647
- MDEntryType.EarlyPrices,
648
- MDEntryType.AuctionClearingPrice,
649
- MDEntryType.SwapValueFactor,
650
- MDEntryType.DailyValueAdjustmentForLongPositions,
651
- MDEntryType.CumulativeValueAdjustmentForLongPositions,
652
- MDEntryType.DailyValueAdjustmentForShortPositions,
653
- MDEntryType.CumulativeValueAdjustmentForShortPositions,
654
- MDEntryType.FixingPrice,
655
- MDEntryType.CashRate,
656
- MDEntryType.RecoveryRate,
657
- MDEntryType.RecoveryRateForLong,
658
- MDEntryType.RecoveryRateForShort,
659
- MDEntryType.MarketBid,
660
- MDEntryType.MarketOffer,
661
- MDEntryType.ShortSaleMinPrice,
662
- MDEntryType.PreviousClosingPrice,
663
- MDEntryType.ThresholdLimitPriceBanding,
664
- MDEntryType.DailyFinancingValue,
665
- MDEntryType.AccruedFinancingValue,
666
- MDEntryType.TWAP
667
- ];
291
+ const entryTypes = args.mdEntryTypes || [MDEntryType.Bid, MDEntryType.Offer, MDEntryType.TradeVolume];
668
292
  const messageFields = [
669
293
  new Field(Fields.MsgType, Messages.MarketDataRequest),
670
294
  new Field(Fields.SenderCompID, parser.sender),
@@ -686,10 +310,6 @@ var createMarketDataRequestHandler = (parser, pendingRequests) => {
686
310
  });
687
311
  const mdr = parser.createMessage(...messageFields);
688
312
  if (!parser.connected) {
689
- parser.logger.log({
690
- level: "error",
691
- message: "Not connected. Cannot send market data request."
692
- });
693
313
  return {
694
314
  content: [
695
315
  {
@@ -701,16 +321,8 @@ var createMarketDataRequestHandler = (parser, pendingRequests) => {
701
321
  isError: true
702
322
  };
703
323
  }
704
- parser.logger.log({
705
- level: "info",
706
- message: `Sending market data request message: ${JSON.stringify(mdr?.toFIXJSON())}`
707
- });
708
324
  parser.send(mdr);
709
325
  const fixData = await response;
710
- parser.logger.log({
711
- level: "info",
712
- message: `Received market data response for request ID: ${args.mdReqID}`
713
- });
714
326
  return {
715
327
  content: [
716
328
  {
@@ -759,9 +371,6 @@ var createGetStockGraphHandler = (marketDataPrices) => {
759
371
  const offerData = priceHistory.map((point) => point.offer);
760
372
  const spreadData = priceHistory.map((point) => point.spread);
761
373
  const volumeData = priceHistory.map((point) => point.volume);
762
- const tradeData = priceHistory.map((point) => point.trade);
763
- const vwapData = priceHistory.map((point) => point.vwap);
764
- const twapData = priceHistory.map((point) => point.twap);
765
374
  const config = {
766
375
  type: "line",
767
376
  data: {
@@ -791,30 +400,6 @@ var createGetStockGraphHandler = (marketDataPrices) => {
791
400
  fill: false,
792
401
  tension: 0.4
793
402
  },
794
- {
795
- label: "Trade",
796
- data: tradeData,
797
- borderColor: "#ffc107",
798
- backgroundColor: "rgba(255, 193, 7, 0.1)",
799
- fill: false,
800
- tension: 0.4
801
- },
802
- {
803
- label: "VWAP",
804
- data: vwapData,
805
- borderColor: "#17a2b8",
806
- backgroundColor: "rgba(23, 162, 184, 0.1)",
807
- fill: false,
808
- tension: 0.4
809
- },
810
- {
811
- label: "TWAP",
812
- data: twapData,
813
- borderColor: "#6610f2",
814
- backgroundColor: "rgba(102, 16, 242, 0.1)",
815
- fill: false,
816
- tension: 0.4
817
- },
818
403
  {
819
404
  label: "Volume",
820
405
  data: volumeData,
@@ -860,7 +445,7 @@ var createGetStockGraphHandler = (marketDataPrices) => {
860
445
  content: [
861
446
  {
862
447
  type: "text",
863
- text: `Error: ${error instanceof Error ? error.message : "Failed to generate graph"}`,
448
+ text: `Error: ${error instanceof Error ? error.message : "Failed to generate chart"}`,
864
449
  uri: "getStockGraph"
865
450
  }
866
451
  ],
@@ -898,48 +483,7 @@ var createGetStockPriceHistoryHandler = (marketDataPrices) => {
898
483
  bid: point.bid,
899
484
  offer: point.offer,
900
485
  spread: point.spread,
901
- volume: point.volume,
902
- trade: point.trade,
903
- indexValue: point.indexValue,
904
- openingPrice: point.openingPrice,
905
- closingPrice: point.closingPrice,
906
- settlementPrice: point.settlementPrice,
907
- tradingSessionHighPrice: point.tradingSessionHighPrice,
908
- tradingSessionLowPrice: point.tradingSessionLowPrice,
909
- vwap: point.vwap,
910
- imbalance: point.imbalance,
911
- openInterest: point.openInterest,
912
- compositeUnderlyingPrice: point.compositeUnderlyingPrice,
913
- simulatedSellPrice: point.simulatedSellPrice,
914
- simulatedBuyPrice: point.simulatedBuyPrice,
915
- marginRate: point.marginRate,
916
- midPrice: point.midPrice,
917
- emptyBook: point.emptyBook,
918
- settleHighPrice: point.settleHighPrice,
919
- settleLowPrice: point.settleLowPrice,
920
- priorSettlePrice: point.priorSettlePrice,
921
- sessionHighBid: point.sessionHighBid,
922
- sessionLowOffer: point.sessionLowOffer,
923
- earlyPrices: point.earlyPrices,
924
- auctionClearingPrice: point.auctionClearingPrice,
925
- swapValueFactor: point.swapValueFactor,
926
- dailyValueAdjustmentForLongPositions: point.dailyValueAdjustmentForLongPositions,
927
- cumulativeValueAdjustmentForLongPositions: point.cumulativeValueAdjustmentForLongPositions,
928
- dailyValueAdjustmentForShortPositions: point.dailyValueAdjustmentForShortPositions,
929
- cumulativeValueAdjustmentForShortPositions: point.cumulativeValueAdjustmentForShortPositions,
930
- fixingPrice: point.fixingPrice,
931
- cashRate: point.cashRate,
932
- recoveryRate: point.recoveryRate,
933
- recoveryRateForLong: point.recoveryRateForLong,
934
- recoveryRateForShort: point.recoveryRateForShort,
935
- marketBid: point.marketBid,
936
- marketOffer: point.marketOffer,
937
- shortSaleMinPrice: point.shortSaleMinPrice,
938
- previousClosingPrice: point.previousClosingPrice,
939
- thresholdLimitPriceBanding: point.thresholdLimitPriceBanding,
940
- dailyFinancingValue: point.dailyFinancingValue,
941
- accruedFinancingValue: point.accruedFinancingValue,
942
- twap: point.twap
486
+ volume: point.volume
943
487
  }))
944
488
  },
945
489
  null,
@@ -954,7 +498,7 @@ var createGetStockPriceHistoryHandler = (marketDataPrices) => {
954
498
  content: [
955
499
  {
956
500
  type: "text",
957
- text: `Error: ${error instanceof Error ? error.message : "Failed to get price history"}`,
501
+ text: `Error: ${error instanceof Error ? error.message : "Failed to get stock price history"}`,
958
502
  uri: "getStockPriceHistory"
959
503
  }
960
504
  ],
@@ -1062,7 +606,7 @@ Parameters verified:
1062
606
  - Symbol: ${args.symbol}
1063
607
  - TimeInForce: ${args.timeInForce} (${timeInForceNames[args.timeInForce]})
1064
608
 
1065
- To execute this order, call the executeOrder tool with these exact same parameters. Important: The user has to explicitly confirm before executeOrder is called!`,
609
+ To execute this order, call the executeOrder tool with these exact same parameters.`,
1066
610
  uri: "verifyOrder"
1067
611
  }
1068
612
  ]
@@ -1258,210 +802,48 @@ var createToolHandlers = (parser, verifiedOrders, pendingRequests, marketDataPri
1258
802
  executeOrder: createExecuteOrderHandler(parser, verifiedOrders, pendingRequests),
1259
803
  marketDataRequest: createMarketDataRequestHandler(parser, pendingRequests),
1260
804
  getStockGraph: createGetStockGraphHandler(marketDataPrices),
1261
- getStockPriceHistory: createGetStockPriceHistoryHandler(marketDataPrices),
1262
- technicalAnalysis: createTechnicalAnalysisHandler(marketDataPrices)
805
+ getStockPriceHistory: createGetStockPriceHistoryHandler(marketDataPrices)
1263
806
  });
1264
807
 
1265
808
  // src/utils/messageHandler.ts
1266
809
  import { Fields as Fields3, MDEntryType as MDEntryType2, Messages as Messages3 } from "fixparser";
1267
- function getEnumValue(enumObj, name) {
1268
- return enumObj[name] || name;
1269
- }
1270
810
  function handleMessage(message, parser, pendingRequests, marketDataPrices, maxPriceHistory, onPriceUpdate) {
811
+ parser.logger.log({
812
+ level: "info",
813
+ message: `MCP Server received message: ${message.messageType}: ${message.description}`
814
+ });
1271
815
  const msgType = message.messageType;
1272
- if (msgType === Messages3.MarketDataSnapshotFullRefresh || msgType === Messages3.MarketDataIncrementalRefresh) {
816
+ if (msgType === Messages3.MarketDataSnapshotFullRefresh) {
1273
817
  const symbol = message.getField(Fields3.Symbol)?.value;
1274
- const fixJson = message.toFIXJSON();
1275
- const entries = fixJson.Body?.NoMDEntries || [];
1276
- const data = {
1277
- timestamp: Date.now(),
1278
- bid: 0,
1279
- offer: 0,
1280
- spread: 0,
1281
- volume: 0,
1282
- trade: 0,
1283
- indexValue: 0,
1284
- openingPrice: 0,
1285
- closingPrice: 0,
1286
- settlementPrice: 0,
1287
- tradingSessionHighPrice: 0,
1288
- tradingSessionLowPrice: 0,
1289
- vwap: 0,
1290
- imbalance: 0,
1291
- openInterest: 0,
1292
- compositeUnderlyingPrice: 0,
1293
- simulatedSellPrice: 0,
1294
- simulatedBuyPrice: 0,
1295
- marginRate: 0,
1296
- midPrice: 0,
1297
- emptyBook: 0,
1298
- settleHighPrice: 0,
1299
- settleLowPrice: 0,
1300
- priorSettlePrice: 0,
1301
- sessionHighBid: 0,
1302
- sessionLowOffer: 0,
1303
- earlyPrices: 0,
1304
- auctionClearingPrice: 0,
1305
- swapValueFactor: 0,
1306
- dailyValueAdjustmentForLongPositions: 0,
1307
- cumulativeValueAdjustmentForLongPositions: 0,
1308
- dailyValueAdjustmentForShortPositions: 0,
1309
- cumulativeValueAdjustmentForShortPositions: 0,
1310
- fixingPrice: 0,
1311
- cashRate: 0,
1312
- recoveryRate: 0,
1313
- recoveryRateForLong: 0,
1314
- recoveryRateForShort: 0,
1315
- marketBid: 0,
1316
- marketOffer: 0,
1317
- shortSaleMinPrice: 0,
1318
- previousClosingPrice: 0,
1319
- thresholdLimitPriceBanding: 0,
1320
- dailyFinancingValue: 0,
1321
- accruedFinancingValue: 0,
1322
- twap: 0
1323
- };
1324
- for (const entry of entries) {
1325
- const entryType = entry.MDEntryType;
1326
- const price = entry.MDEntryPx ? Number.parseFloat(entry.MDEntryPx) : 0;
1327
- const size = entry.MDEntrySize ? Number.parseFloat(entry.MDEntrySize) : 0;
1328
- const enumValue = getEnumValue(MDEntryType2, entryType);
1329
- switch (enumValue) {
1330
- case MDEntryType2.Bid:
1331
- data.bid = price;
1332
- break;
1333
- case MDEntryType2.Offer:
1334
- data.offer = price;
1335
- break;
1336
- case MDEntryType2.Trade:
1337
- data.trade = price;
1338
- break;
1339
- case MDEntryType2.IndexValue:
1340
- data.indexValue = price;
1341
- break;
1342
- case MDEntryType2.OpeningPrice:
1343
- data.openingPrice = price;
1344
- break;
1345
- case MDEntryType2.ClosingPrice:
1346
- data.closingPrice = price;
1347
- break;
1348
- case MDEntryType2.SettlementPrice:
1349
- data.settlementPrice = price;
1350
- break;
1351
- case MDEntryType2.TradingSessionHighPrice:
1352
- data.tradingSessionHighPrice = price;
1353
- break;
1354
- case MDEntryType2.TradingSessionLowPrice:
1355
- data.tradingSessionLowPrice = price;
1356
- break;
1357
- case MDEntryType2.VWAP:
1358
- data.vwap = price;
1359
- break;
1360
- case MDEntryType2.Imbalance:
1361
- data.imbalance = size;
1362
- break;
1363
- case MDEntryType2.TradeVolume:
1364
- data.volume = size;
1365
- break;
1366
- case MDEntryType2.OpenInterest:
1367
- data.openInterest = size;
1368
- break;
1369
- case MDEntryType2.CompositeUnderlyingPrice:
1370
- data.compositeUnderlyingPrice = price;
1371
- break;
1372
- case MDEntryType2.SimulatedSellPrice:
1373
- data.simulatedSellPrice = price;
1374
- break;
1375
- case MDEntryType2.SimulatedBuyPrice:
1376
- data.simulatedBuyPrice = price;
1377
- break;
1378
- case MDEntryType2.MarginRate:
1379
- data.marginRate = price;
1380
- break;
1381
- case MDEntryType2.MidPrice:
1382
- data.midPrice = price;
1383
- break;
1384
- case MDEntryType2.EmptyBook:
1385
- data.emptyBook = 1;
1386
- break;
1387
- case MDEntryType2.SettleHighPrice:
1388
- data.settleHighPrice = price;
1389
- break;
1390
- case MDEntryType2.SettleLowPrice:
1391
- data.settleLowPrice = price;
1392
- break;
1393
- case MDEntryType2.PriorSettlePrice:
1394
- data.priorSettlePrice = price;
1395
- break;
1396
- case MDEntryType2.SessionHighBid:
1397
- data.sessionHighBid = price;
1398
- break;
1399
- case MDEntryType2.SessionLowOffer:
1400
- data.sessionLowOffer = price;
1401
- break;
1402
- case MDEntryType2.EarlyPrices:
1403
- data.earlyPrices = price;
1404
- break;
1405
- case MDEntryType2.AuctionClearingPrice:
1406
- data.auctionClearingPrice = price;
1407
- break;
1408
- case MDEntryType2.SwapValueFactor:
1409
- data.swapValueFactor = price;
1410
- break;
1411
- case MDEntryType2.DailyValueAdjustmentForLongPositions:
1412
- data.dailyValueAdjustmentForLongPositions = price;
1413
- break;
1414
- case MDEntryType2.CumulativeValueAdjustmentForLongPositions:
1415
- data.cumulativeValueAdjustmentForLongPositions = price;
1416
- break;
1417
- case MDEntryType2.DailyValueAdjustmentForShortPositions:
1418
- data.dailyValueAdjustmentForShortPositions = price;
1419
- break;
1420
- case MDEntryType2.CumulativeValueAdjustmentForShortPositions:
1421
- data.cumulativeValueAdjustmentForShortPositions = price;
1422
- break;
1423
- case MDEntryType2.FixingPrice:
1424
- data.fixingPrice = price;
1425
- break;
1426
- case MDEntryType2.CashRate:
1427
- data.cashRate = price;
1428
- break;
1429
- case MDEntryType2.RecoveryRate:
1430
- data.recoveryRate = price;
1431
- break;
1432
- case MDEntryType2.RecoveryRateForLong:
1433
- data.recoveryRateForLong = price;
1434
- break;
1435
- case MDEntryType2.RecoveryRateForShort:
1436
- data.recoveryRateForShort = price;
1437
- break;
1438
- case MDEntryType2.MarketBid:
1439
- data.marketBid = price;
1440
- break;
1441
- case MDEntryType2.MarketOffer:
1442
- data.marketOffer = price;
1443
- break;
1444
- case MDEntryType2.ShortSaleMinPrice:
1445
- data.shortSaleMinPrice = price;
1446
- break;
1447
- case MDEntryType2.PreviousClosingPrice:
1448
- data.previousClosingPrice = price;
1449
- break;
1450
- case MDEntryType2.ThresholdLimitPriceBanding:
1451
- data.thresholdLimitPriceBanding = price;
1452
- break;
1453
- case MDEntryType2.DailyFinancingValue:
1454
- data.dailyFinancingValue = price;
1455
- break;
1456
- case MDEntryType2.AccruedFinancingValue:
1457
- data.accruedFinancingValue = price;
1458
- break;
1459
- case MDEntryType2.TWAP:
1460
- data.twap = price;
1461
- break;
818
+ const entries = message.getField(Fields3.NoMDEntries)?.value;
819
+ let bid = 0;
820
+ let offer = 0;
821
+ let volume = 0;
822
+ const entryTypes = message.getFields(Fields3.MDEntryType);
823
+ const entryPrices = message.getFields(Fields3.MDEntryPx);
824
+ const entrySizes = message.getFields(Fields3.MDEntrySize);
825
+ if (entryTypes && entryPrices && entrySizes) {
826
+ for (let i = 0; i < entries; i++) {
827
+ const entryType = entryTypes[i]?.value;
828
+ const entryPrice = Number.parseFloat(entryPrices[i]?.value);
829
+ const entrySize = Number.parseFloat(entrySizes[i]?.value);
830
+ if (entryType === MDEntryType2.Bid) {
831
+ bid = entryPrice;
832
+ } else if (entryType === MDEntryType2.Offer) {
833
+ offer = entryPrice;
834
+ }
835
+ volume += entrySize;
1462
836
  }
1463
837
  }
1464
- data.spread = data.offer - data.bid;
838
+ const spread = offer - bid;
839
+ const timestamp = Date.now();
840
+ const data = {
841
+ timestamp,
842
+ bid,
843
+ offer,
844
+ spread,
845
+ volume
846
+ };
1465
847
  if (!marketDataPrices.has(symbol)) {
1466
848
  marketDataPrices.set(symbol, []);
1467
849
  }
@@ -1471,14 +853,6 @@ function handleMessage(message, parser, pendingRequests, marketDataPrices, maxPr
1471
853
  prices.splice(0, prices.length - maxPriceHistory);
1472
854
  }
1473
855
  onPriceUpdate?.(symbol, data);
1474
- const mdReqID = message.getField(Fields3.MDReqID)?.value;
1475
- if (mdReqID) {
1476
- const callback = pendingRequests.get(mdReqID);
1477
- if (callback) {
1478
- callback(message);
1479
- pendingRequests.delete(mdReqID);
1480
- }
1481
- }
1482
856
  } else if (msgType === Messages3.ExecutionReport) {
1483
857
  const reqId = message.getField(Fields3.ClOrdID)?.value;
1484
858
  const callback = pendingRequests.get(reqId);
@@ -1491,39 +865,6 @@ function handleMessage(message, parser, pendingRequests, marketDataPrices, maxPr
1491
865
 
1492
866
  // src/MCPRemote.ts
1493
867
  var transports = {};
1494
- function jsonSchemaToZod(schema) {
1495
- if (schema.type === "object") {
1496
- const shape = {};
1497
- for (const [key, prop] of Object.entries(schema.properties || {})) {
1498
- const propSchema = prop;
1499
- if (propSchema.type === "string") {
1500
- if (propSchema.enum) {
1501
- shape[key] = z.enum(propSchema.enum);
1502
- } else {
1503
- shape[key] = z.string();
1504
- }
1505
- } else if (propSchema.type === "number") {
1506
- shape[key] = z.number();
1507
- } else if (propSchema.type === "boolean") {
1508
- shape[key] = z.boolean();
1509
- } else if (propSchema.type === "array") {
1510
- if (propSchema.items.type === "string") {
1511
- shape[key] = z.array(z.string());
1512
- } else if (propSchema.items.type === "number") {
1513
- shape[key] = z.array(z.number());
1514
- } else if (propSchema.items.type === "boolean") {
1515
- shape[key] = z.array(z.boolean());
1516
- } else {
1517
- shape[key] = z.array(z.any());
1518
- }
1519
- } else {
1520
- shape[key] = z.any();
1521
- }
1522
- }
1523
- return shape;
1524
- }
1525
- return {};
1526
- }
1527
868
  var MCPRemote = class extends MCPBase {
1528
869
  /**
1529
870
  * Port number the server will listen on.
@@ -1566,7 +907,7 @@ var MCPRemote = class extends MCPBase {
1566
907
  */
1567
908
  marketDataPrices = /* @__PURE__ */ new Map();
1568
909
  /**
1569
- * Maximum number of price history entries to keep per symbol
910
+ * Maximum number of price points to store per symbol
1570
911
  * @private
1571
912
  */
1572
913
  MAX_PRICE_HISTORY = 1e5;
@@ -1588,7 +929,31 @@ var MCPRemote = class extends MCPBase {
1588
929
  this.parser,
1589
930
  this.pendingRequests,
1590
931
  this.marketDataPrices,
1591
- this.MAX_PRICE_HISTORY
932
+ this.MAX_PRICE_HISTORY,
933
+ (symbol, data) => {
934
+ this.mcpServer?.tool(
935
+ "priceUpdate",
936
+ {
937
+ description: "Price update notification",
938
+ schema: z.object({
939
+ symbol: z.string(),
940
+ timestamp: z.number(),
941
+ bid: z.number(),
942
+ offer: z.number(),
943
+ spread: z.number(),
944
+ volume: z.number()
945
+ })
946
+ },
947
+ () => ({
948
+ content: [
949
+ {
950
+ type: "text",
951
+ text: JSON.stringify({ symbol, ...data })
952
+ }
953
+ ]
954
+ })
955
+ );
956
+ }
1592
957
  );
1593
958
  }
1594
959
  });
@@ -1650,15 +1015,7 @@ var MCPRemote = class extends MCPBase {
1650
1015
  );
1651
1016
  return;
1652
1017
  }
1653
- try {
1654
- await transport.handleRequest(req, res, parsed);
1655
- } catch (error) {
1656
- this.logger?.log({
1657
- level: "error",
1658
- message: `Error handling request: ${error}`
1659
- });
1660
- throw error;
1661
- }
1018
+ await transport.handleRequest(req, res, parsed);
1662
1019
  });
1663
1020
  } else if (req.method === "GET" || req.method === "DELETE") {
1664
1021
  if (!sessionId || !transports[sessionId]) {
@@ -1667,20 +1024,8 @@ var MCPRemote = class extends MCPBase {
1667
1024
  return;
1668
1025
  }
1669
1026
  const transport = transports[sessionId];
1670
- try {
1671
- await transport.handleRequest(req, res);
1672
- } catch (error) {
1673
- this.logger?.log({
1674
- level: "error",
1675
- message: `Error handling ${req.method} request: ${error}`
1676
- });
1677
- throw error;
1678
- }
1027
+ await transport.handleRequest(req, res);
1679
1028
  } else {
1680
- this.logger?.log({
1681
- level: "error",
1682
- message: `Method not allowed: ${req.method}`
1683
- });
1684
1029
  res.writeHead(405);
1685
1030
  res.end("Method Not Allowed");
1686
1031
  }
@@ -1714,40 +1059,69 @@ var MCPRemote = class extends MCPBase {
1714
1059
  });
1715
1060
  return;
1716
1061
  }
1717
- const toolHandlers = createToolHandlers(
1718
- this.parser,
1719
- this.verifiedOrders,
1720
- this.pendingRequests,
1721
- this.marketDataPrices
1062
+ this.mcpServer.tool(
1063
+ "tools/list",
1064
+ {
1065
+ description: "List available tools",
1066
+ schema: z.object({})
1067
+ },
1068
+ async () => {
1069
+ return {
1070
+ content: [
1071
+ {
1072
+ type: "text",
1073
+ text: JSON.stringify(
1074
+ Object.entries(toolSchemas).map(([name, { description, schema }]) => ({
1075
+ name,
1076
+ description,
1077
+ inputSchema: schema
1078
+ }))
1079
+ )
1080
+ }
1081
+ ]
1082
+ };
1083
+ }
1722
1084
  );
1723
- Object.entries(toolSchemas).forEach(([name, { description, schema }]) => {
1724
- this.mcpServer?.registerTool(
1725
- name,
1726
- {
1727
- description,
1728
- inputSchema: jsonSchemaToZod(schema)
1729
- },
1730
- async (args) => {
1731
- const handler = toolHandlers[name];
1732
- if (!handler) {
1733
- return {
1734
- content: [
1735
- {
1736
- type: "text",
1737
- text: `Tool not found: ${name}`
1738
- }
1739
- ],
1740
- isError: true
1741
- };
1742
- }
1743
- const result = await handler(args);
1085
+ this.mcpServer.tool(
1086
+ "tools/call",
1087
+ {
1088
+ description: "Call a tool",
1089
+ schema: z.object({
1090
+ name: z.string(),
1091
+ arguments: z.any(),
1092
+ _meta: z.object({
1093
+ progressToken: z.number()
1094
+ }).optional()
1095
+ })
1096
+ },
1097
+ async (request) => {
1098
+ const { name, arguments: args } = request;
1099
+ const toolHandlers = createToolHandlers(
1100
+ this.parser,
1101
+ this.verifiedOrders,
1102
+ this.pendingRequests,
1103
+ this.marketDataPrices
1104
+ );
1105
+ const handler = toolHandlers[name];
1106
+ if (!handler) {
1744
1107
  return {
1745
- content: result.content,
1746
- isError: result.isError
1108
+ content: [
1109
+ {
1110
+ type: "text",
1111
+ text: `Tool not found: ${name}`,
1112
+ uri: name
1113
+ }
1114
+ ],
1115
+ isError: true
1747
1116
  };
1748
1117
  }
1749
- );
1750
- });
1118
+ const result = await handler(args);
1119
+ return {
1120
+ content: result.content,
1121
+ isError: result.isError
1122
+ };
1123
+ }
1124
+ );
1751
1125
  }
1752
1126
  };
1753
1127
  export {