fixparser-plugin-mcp 9.1.7-eb1de32a → 9.1.7-edd9ee17

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.
@@ -1,9 +1,51 @@
1
1
  // src/MCPLocal.ts
2
2
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
3
3
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
- import { Fields as Fields3, Messages as Messages3 } from "fixparser";
5
4
  import { z } from "zod";
6
5
 
6
+ // src/MCPBase.ts
7
+ var MCPBase = class {
8
+ /**
9
+ * Optional logger instance for diagnostics and output.
10
+ * @protected
11
+ */
12
+ logger;
13
+ /**
14
+ * FIXParser instance, set during plugin register().
15
+ * @protected
16
+ */
17
+ parser;
18
+ /**
19
+ * Called when server is setup and listening.
20
+ * @protected
21
+ */
22
+ onReady = void 0;
23
+ /**
24
+ * Map to store verified orders before execution
25
+ * @protected
26
+ */
27
+ verifiedOrders = /* @__PURE__ */ new Map();
28
+ /**
29
+ * Map to store pending market data requests
30
+ * @protected
31
+ */
32
+ pendingRequests = /* @__PURE__ */ new Map();
33
+ /**
34
+ * Map to store market data prices
35
+ * @protected
36
+ */
37
+ marketDataPrices = /* @__PURE__ */ new Map();
38
+ /**
39
+ * Maximum number of price history entries to keep per symbol
40
+ * @protected
41
+ */
42
+ MAX_PRICE_HISTORY = 1e5;
43
+ constructor({ logger, onReady }) {
44
+ this.logger = logger;
45
+ this.onReady = onReady;
46
+ }
47
+ };
48
+
7
49
  // src/schemas/schemas.ts
8
50
  var toolSchemas = {
9
51
  parse: {
@@ -87,7 +129,7 @@ var toolSchemas = {
87
129
  }
88
130
  },
89
131
  executeOrder: {
90
- description: "Executes a verified order. verifyOrder must be called before executeOrder. user has to explicitly allow executeOrder.",
132
+ description: "Executes a verified order. verifyOrder must be called before executeOrder.",
91
133
  schema: {
92
134
  type: "object",
93
135
  properties: {
@@ -204,12 +246,12 @@ var toolSchemas = {
204
246
  "X",
205
247
  "Y",
206
248
  "Z"
207
- ],
208
- description: "Market Data Entry Types: 0=Bid, 1=Offer, 2=Trade, 3=Index Value, 4=Opening Price, 5=Closing Price, 6=Settlement Price, 7=High Price, 8=Low Price, 9=Trade Volume, A=Open Interest, B=Simulated Sell Price, C=Simulated Buy Price, D=Empty Book, E=Session High Bid, F=Session Low Offer, G=Fixing Price, H=Electronic Volume, I=Threshold Limits and Price Band Variation, J=Clearing Price, K=Open Interest Change, L=Last Trade Price, M=Last Trade Volume, N=Last Trade Time, O=Last Trade Tick, P=Last Trade Exchange, Q=Last Trade ID, R=Last Trade Side, S=Last Trade Price Change, T=Last Trade Price Change Percent, U=Last Trade Price Change Basis Points, V=Last Trade Price Change Points, W=Last Trade Price Change Ticks, X=Last Trade Price Change Ticks Percent, Y=Last Trade Price Change Ticks Basis Points, Z=Last Trade Price Change Ticks Points"
209
- }
249
+ ]
250
+ },
251
+ description: "Market Data Entry Types: 0=Bid, 1=Offer, 2=Trade, 3=Index Value, 4=Opening Price, 5=Closing Price, 6=Settlement Price, 7=High Price, 8=Low Price, 9=Trade Volume, A=Open Interest, B=Simulated Sell Price, C=Simulated Buy Price, D=Empty Book, E=Session High Bid, F=Session Low Offer, G=Fixing Price, H=Electronic Volume, I=Threshold Limits and Price Band Variation, J=Clearing Price, K=Open Interest Change, L=Last Trade Price, M=Last Trade Volume, N=Last Trade Time, O=Last Trade Tick, P=Last Trade Exchange, Q=Last Trade ID, R=Last Trade Side, S=Last Trade Price Change, T=Last Trade Price Change Percent, U=Last Trade Price Change Basis Points, V=Last Trade Price Change Points, W=Last Trade Price Change Ticks, X=Last Trade Price Change Ticks Percent, Y=Last Trade Price Change Ticks Basis Points, Z=Last Trade Price Change Ticks Points"
210
252
  }
211
253
  },
212
- required: ["mdUpdateType", "symbols", "mdReqID", "subscriptionRequestType", "mdEntryTypes"]
254
+ required: ["mdUpdateType", "symbols", "mdReqID", "subscriptionRequestType"]
213
255
  }
214
256
  },
215
257
  getStockGraph: {
@@ -235,14 +277,68 @@ var toolSchemas = {
235
277
  };
236
278
 
237
279
  // src/tools/marketData.ts
238
- import { Field, Fields, Messages } from "fixparser";
280
+ import { Field, Fields, MDEntryType, Messages } from "fixparser";
239
281
  import QuickChart from "quickchart-js";
240
282
  var createMarketDataRequestHandler = (parser, pendingRequests) => {
241
283
  return async (args) => {
242
284
  try {
285
+ parser.logger.log({
286
+ level: "info",
287
+ message: `Sending market data request for symbols: ${args.symbols.join(", ")}`
288
+ });
243
289
  const response = new Promise((resolve) => {
244
290
  pendingRequests.set(args.mdReqID, resolve);
291
+ parser.logger.log({
292
+ level: "info",
293
+ message: `Registered callback for market data request ID: ${args.mdReqID}`
294
+ });
245
295
  });
296
+ const entryTypes = args.mdEntryTypes || [
297
+ MDEntryType.Bid,
298
+ MDEntryType.Offer,
299
+ MDEntryType.Trade,
300
+ MDEntryType.IndexValue,
301
+ MDEntryType.OpeningPrice,
302
+ MDEntryType.ClosingPrice,
303
+ MDEntryType.SettlementPrice,
304
+ MDEntryType.TradingSessionHighPrice,
305
+ MDEntryType.TradingSessionLowPrice,
306
+ MDEntryType.VWAP,
307
+ MDEntryType.Imbalance,
308
+ MDEntryType.TradeVolume,
309
+ MDEntryType.OpenInterest,
310
+ MDEntryType.CompositeUnderlyingPrice,
311
+ MDEntryType.SimulatedSellPrice,
312
+ MDEntryType.SimulatedBuyPrice,
313
+ MDEntryType.MarginRate,
314
+ MDEntryType.MidPrice,
315
+ MDEntryType.EmptyBook,
316
+ MDEntryType.SettleHighPrice,
317
+ MDEntryType.SettleLowPrice,
318
+ MDEntryType.PriorSettlePrice,
319
+ MDEntryType.SessionHighBid,
320
+ MDEntryType.SessionLowOffer,
321
+ MDEntryType.EarlyPrices,
322
+ MDEntryType.AuctionClearingPrice,
323
+ MDEntryType.SwapValueFactor,
324
+ MDEntryType.DailyValueAdjustmentForLongPositions,
325
+ MDEntryType.CumulativeValueAdjustmentForLongPositions,
326
+ MDEntryType.DailyValueAdjustmentForShortPositions,
327
+ MDEntryType.CumulativeValueAdjustmentForShortPositions,
328
+ MDEntryType.FixingPrice,
329
+ MDEntryType.CashRate,
330
+ MDEntryType.RecoveryRate,
331
+ MDEntryType.RecoveryRateForLong,
332
+ MDEntryType.RecoveryRateForShort,
333
+ MDEntryType.MarketBid,
334
+ MDEntryType.MarketOffer,
335
+ MDEntryType.ShortSaleMinPrice,
336
+ MDEntryType.PreviousClosingPrice,
337
+ MDEntryType.ThresholdLimitPriceBanding,
338
+ MDEntryType.DailyFinancingValue,
339
+ MDEntryType.AccruedFinancingValue,
340
+ MDEntryType.TWAP
341
+ ];
246
342
  const messageFields = [
247
343
  new Field(Fields.MsgType, Messages.MarketDataRequest),
248
344
  new Field(Fields.SenderCompID, parser.sender),
@@ -258,12 +354,16 @@ var createMarketDataRequestHandler = (parser, pendingRequests) => {
258
354
  args.symbols.forEach((symbol) => {
259
355
  messageFields.push(new Field(Fields.Symbol, symbol));
260
356
  });
261
- messageFields.push(new Field(Fields.NoMDEntryTypes, args.mdEntryTypes.length));
262
- args.mdEntryTypes.forEach((entryType) => {
357
+ messageFields.push(new Field(Fields.NoMDEntryTypes, entryTypes.length));
358
+ entryTypes.forEach((entryType) => {
263
359
  messageFields.push(new Field(Fields.MDEntryType, entryType));
264
360
  });
265
361
  const mdr = parser.createMessage(...messageFields);
266
362
  if (!parser.connected) {
363
+ parser.logger.log({
364
+ level: "error",
365
+ message: "Not connected. Cannot send market data request."
366
+ });
267
367
  return {
268
368
  content: [
269
369
  {
@@ -275,8 +375,16 @@ var createMarketDataRequestHandler = (parser, pendingRequests) => {
275
375
  isError: true
276
376
  };
277
377
  }
378
+ parser.logger.log({
379
+ level: "info",
380
+ message: `Sending market data request message: ${JSON.stringify(mdr?.toFIXJSON())}`
381
+ });
278
382
  parser.send(mdr);
279
383
  const fixData = await response;
384
+ parser.logger.log({
385
+ level: "info",
386
+ message: `Received market data response for request ID: ${args.mdReqID}`
387
+ });
280
388
  return {
281
389
  content: [
282
390
  {
@@ -317,18 +425,73 @@ var createGetStockGraphHandler = (marketDataPrices) => {
317
425
  };
318
426
  }
319
427
  const chart = new QuickChart();
320
- chart.setWidth(600);
321
- chart.setHeight(300);
428
+ chart.setWidth(1200);
429
+ chart.setHeight(600);
430
+ chart.setBackgroundColor("transparent");
322
431
  const labels = priceHistory.map((point) => new Date(point.timestamp).toLocaleTimeString());
323
- const data = priceHistory.map((point) => point.price);
324
- chart.setConfig({
432
+ const bidData = priceHistory.map((point) => point.bid);
433
+ const offerData = priceHistory.map((point) => point.offer);
434
+ const spreadData = priceHistory.map((point) => point.spread);
435
+ const volumeData = priceHistory.map((point) => point.volume);
436
+ const tradeData = priceHistory.map((point) => point.trade);
437
+ const vwapData = priceHistory.map((point) => point.vwap);
438
+ const twapData = priceHistory.map((point) => point.twap);
439
+ const config = {
325
440
  type: "line",
326
441
  data: {
327
442
  labels,
328
443
  datasets: [
329
444
  {
330
- label: symbol,
331
- data,
445
+ label: "Bid",
446
+ data: bidData,
447
+ borderColor: "#28a745",
448
+ backgroundColor: "rgba(40, 167, 69, 0.1)",
449
+ fill: false,
450
+ tension: 0.4
451
+ },
452
+ {
453
+ label: "Offer",
454
+ data: offerData,
455
+ borderColor: "#dc3545",
456
+ backgroundColor: "rgba(220, 53, 69, 0.1)",
457
+ fill: false,
458
+ tension: 0.4
459
+ },
460
+ {
461
+ label: "Spread",
462
+ data: spreadData,
463
+ borderColor: "#6c757d",
464
+ backgroundColor: "rgba(108, 117, 125, 0.1)",
465
+ fill: false,
466
+ tension: 0.4
467
+ },
468
+ {
469
+ label: "Trade",
470
+ data: tradeData,
471
+ borderColor: "#ffc107",
472
+ backgroundColor: "rgba(255, 193, 7, 0.1)",
473
+ fill: false,
474
+ tension: 0.4
475
+ },
476
+ {
477
+ label: "VWAP",
478
+ data: vwapData,
479
+ borderColor: "#17a2b8",
480
+ backgroundColor: "rgba(23, 162, 184, 0.1)",
481
+ fill: false,
482
+ tension: 0.4
483
+ },
484
+ {
485
+ label: "TWAP",
486
+ data: twapData,
487
+ borderColor: "#6610f2",
488
+ backgroundColor: "rgba(102, 16, 242, 0.1)",
489
+ fill: false,
490
+ tension: 0.4
491
+ },
492
+ {
493
+ label: "Volume",
494
+ data: volumeData,
332
495
  borderColor: "#007bff",
333
496
  backgroundColor: "rgba(0, 123, 255, 0.1)",
334
497
  fill: true,
@@ -337,46 +500,32 @@ var createGetStockGraphHandler = (marketDataPrices) => {
337
500
  ]
338
501
  },
339
502
  options: {
503
+ responsive: true,
340
504
  plugins: {
341
505
  title: {
342
506
  display: true,
343
- text: `${symbol} Price History`,
344
- font: {
345
- size: 16,
346
- weight: "bold"
347
- }
348
- },
349
- legend: {
350
- display: true
507
+ text: `${symbol} Market Data`
351
508
  }
352
509
  },
353
510
  scales: {
354
511
  y: {
355
- beginAtZero: false,
356
- grid: {
357
- color: "#e9ecef"
358
- }
359
- },
360
- x: {
361
- grid: {
362
- display: false
363
- }
512
+ beginAtZero: false
364
513
  }
365
514
  }
366
515
  }
367
- });
516
+ };
517
+ chart.setConfig(config);
368
518
  const imageBuffer = await chart.toBinary();
369
- const base64Image = imageBuffer.toString("base64");
519
+ const base64 = imageBuffer.toString("base64");
370
520
  return {
371
521
  content: [
372
522
  {
373
- type: "image",
374
- text: base64Image,
375
- source: {
376
- data: base64Image
377
- },
378
- uri: "getStockGraph",
379
- mimeType: "image/png"
523
+ type: "resource",
524
+ resource: {
525
+ uri: "resource://graph",
526
+ mimeType: "image/png",
527
+ blob: base64
528
+ }
380
529
  }
381
530
  ]
382
531
  };
@@ -385,7 +534,7 @@ var createGetStockGraphHandler = (marketDataPrices) => {
385
534
  content: [
386
535
  {
387
536
  type: "text",
388
- text: `Error: ${error instanceof Error ? error.message : "Failed to generate stock graph"}`,
537
+ text: `Error: ${error instanceof Error ? error.message : "Failed to generate graph"}`,
389
538
  uri: "getStockGraph"
390
539
  }
391
540
  ],
@@ -418,9 +567,53 @@ var createGetStockPriceHistoryHandler = (marketDataPrices) => {
418
567
  {
419
568
  symbol,
420
569
  count: priceHistory.length,
421
- prices: priceHistory.map((point) => ({
570
+ data: priceHistory.map((point) => ({
422
571
  timestamp: new Date(point.timestamp).toISOString(),
423
- price: point.price
572
+ bid: point.bid,
573
+ offer: point.offer,
574
+ spread: point.spread,
575
+ volume: point.volume,
576
+ trade: point.trade,
577
+ indexValue: point.indexValue,
578
+ openingPrice: point.openingPrice,
579
+ closingPrice: point.closingPrice,
580
+ settlementPrice: point.settlementPrice,
581
+ tradingSessionHighPrice: point.tradingSessionHighPrice,
582
+ tradingSessionLowPrice: point.tradingSessionLowPrice,
583
+ vwap: point.vwap,
584
+ imbalance: point.imbalance,
585
+ openInterest: point.openInterest,
586
+ compositeUnderlyingPrice: point.compositeUnderlyingPrice,
587
+ simulatedSellPrice: point.simulatedSellPrice,
588
+ simulatedBuyPrice: point.simulatedBuyPrice,
589
+ marginRate: point.marginRate,
590
+ midPrice: point.midPrice,
591
+ emptyBook: point.emptyBook,
592
+ settleHighPrice: point.settleHighPrice,
593
+ settleLowPrice: point.settleLowPrice,
594
+ priorSettlePrice: point.priorSettlePrice,
595
+ sessionHighBid: point.sessionHighBid,
596
+ sessionLowOffer: point.sessionLowOffer,
597
+ earlyPrices: point.earlyPrices,
598
+ auctionClearingPrice: point.auctionClearingPrice,
599
+ swapValueFactor: point.swapValueFactor,
600
+ dailyValueAdjustmentForLongPositions: point.dailyValueAdjustmentForLongPositions,
601
+ cumulativeValueAdjustmentForLongPositions: point.cumulativeValueAdjustmentForLongPositions,
602
+ dailyValueAdjustmentForShortPositions: point.dailyValueAdjustmentForShortPositions,
603
+ cumulativeValueAdjustmentForShortPositions: point.cumulativeValueAdjustmentForShortPositions,
604
+ fixingPrice: point.fixingPrice,
605
+ cashRate: point.cashRate,
606
+ recoveryRate: point.recoveryRate,
607
+ recoveryRateForLong: point.recoveryRateForLong,
608
+ recoveryRateForShort: point.recoveryRateForShort,
609
+ marketBid: point.marketBid,
610
+ marketOffer: point.marketOffer,
611
+ shortSaleMinPrice: point.shortSaleMinPrice,
612
+ previousClosingPrice: point.previousClosingPrice,
613
+ thresholdLimitPriceBanding: point.thresholdLimitPriceBanding,
614
+ dailyFinancingValue: point.dailyFinancingValue,
615
+ accruedFinancingValue: point.accruedFinancingValue,
616
+ twap: point.twap
424
617
  }))
425
618
  },
426
619
  null,
@@ -435,7 +628,7 @@ var createGetStockPriceHistoryHandler = (marketDataPrices) => {
435
628
  content: [
436
629
  {
437
630
  type: "text",
438
- text: `Error: ${error instanceof Error ? error.message : "Failed to get stock price history"}`,
631
+ text: `Error: ${error instanceof Error ? error.message : "Failed to get price history"}`,
439
632
  uri: "getStockPriceHistory"
440
633
  }
441
634
  ],
@@ -543,7 +736,7 @@ Parameters verified:
543
736
  - Symbol: ${args.symbol}
544
737
  - TimeInForce: ${args.timeInForce} (${timeInForceNames[args.timeInForce]})
545
738
 
546
- To execute this order, call the executeOrder tool with these exact same parameters.`,
739
+ To execute this order, call the executeOrder tool with these exact same parameters. Important: The user has to explicitly confirm before executeOrder is called!`,
547
740
  uri: "verifyOrder"
548
741
  }
549
742
  ]
@@ -742,9 +935,285 @@ var createToolHandlers = (parser, verifiedOrders, pendingRequests, marketDataPri
742
935
  getStockPriceHistory: createGetStockPriceHistoryHandler(marketDataPrices)
743
936
  });
744
937
 
938
+ // src/utils/messageHandler.ts
939
+ import { Fields as Fields3, MDEntryType as MDEntryType2, Messages as Messages3 } from "fixparser";
940
+ function handleMessage(message, parser, pendingRequests, marketDataPrices, maxPriceHistory, onPriceUpdate) {
941
+ parser.logger.log({
942
+ level: "info",
943
+ message: `MCP Server received message: ${message.messageType}: ${message.description}`
944
+ });
945
+ const msgType = message.messageType;
946
+ if (msgType === Messages3.MarketDataSnapshotFullRefresh || msgType === Messages3.MarketDataIncrementalRefresh) {
947
+ const symbol = message.getField(Fields3.Symbol)?.value;
948
+ parser.logger.log({
949
+ level: "info",
950
+ message: `Processing market data for symbol: ${symbol}`
951
+ });
952
+ const fixJson = message.toFIXJSON();
953
+ const entries = fixJson.Body?.NoMDEntries || [];
954
+ parser.logger.log({
955
+ level: "info",
956
+ message: `Found ${entries.length} market data entries`
957
+ });
958
+ const data = {
959
+ timestamp: Date.now(),
960
+ bid: 0,
961
+ offer: 0,
962
+ spread: 0,
963
+ volume: 0,
964
+ trade: 0,
965
+ indexValue: 0,
966
+ openingPrice: 0,
967
+ closingPrice: 0,
968
+ settlementPrice: 0,
969
+ tradingSessionHighPrice: 0,
970
+ tradingSessionLowPrice: 0,
971
+ vwap: 0,
972
+ imbalance: 0,
973
+ openInterest: 0,
974
+ compositeUnderlyingPrice: 0,
975
+ simulatedSellPrice: 0,
976
+ simulatedBuyPrice: 0,
977
+ marginRate: 0,
978
+ midPrice: 0,
979
+ emptyBook: 0,
980
+ settleHighPrice: 0,
981
+ settleLowPrice: 0,
982
+ priorSettlePrice: 0,
983
+ sessionHighBid: 0,
984
+ sessionLowOffer: 0,
985
+ earlyPrices: 0,
986
+ auctionClearingPrice: 0,
987
+ swapValueFactor: 0,
988
+ dailyValueAdjustmentForLongPositions: 0,
989
+ cumulativeValueAdjustmentForLongPositions: 0,
990
+ dailyValueAdjustmentForShortPositions: 0,
991
+ cumulativeValueAdjustmentForShortPositions: 0,
992
+ fixingPrice: 0,
993
+ cashRate: 0,
994
+ recoveryRate: 0,
995
+ recoveryRateForLong: 0,
996
+ recoveryRateForShort: 0,
997
+ marketBid: 0,
998
+ marketOffer: 0,
999
+ shortSaleMinPrice: 0,
1000
+ previousClosingPrice: 0,
1001
+ thresholdLimitPriceBanding: 0,
1002
+ dailyFinancingValue: 0,
1003
+ accruedFinancingValue: 0,
1004
+ twap: 0
1005
+ };
1006
+ for (const entry of entries) {
1007
+ const entryType = entry.MDEntryType;
1008
+ const price = entry.MDEntryPx ? Number.parseFloat(entry.MDEntryPx) : 0;
1009
+ const size = entry.MDEntrySize ? Number.parseFloat(entry.MDEntrySize) : 0;
1010
+ if (entryType === MDEntryType2.Bid || entryType === MDEntryType2.Offer || entryType === MDEntryType2.TradeVolume) {
1011
+ parser.logger.log({
1012
+ level: "info",
1013
+ message: `Market Data Entry - Type: ${entryType}, Price: ${price}, Size: ${size}`
1014
+ });
1015
+ }
1016
+ switch (entryType) {
1017
+ case MDEntryType2.Bid:
1018
+ data.bid = price;
1019
+ break;
1020
+ case MDEntryType2.Offer:
1021
+ data.offer = price;
1022
+ break;
1023
+ case MDEntryType2.Trade:
1024
+ data.trade = price;
1025
+ break;
1026
+ case MDEntryType2.IndexValue:
1027
+ data.indexValue = price;
1028
+ break;
1029
+ case MDEntryType2.OpeningPrice:
1030
+ data.openingPrice = price;
1031
+ break;
1032
+ case MDEntryType2.ClosingPrice:
1033
+ data.closingPrice = price;
1034
+ break;
1035
+ case MDEntryType2.SettlementPrice:
1036
+ data.settlementPrice = price;
1037
+ break;
1038
+ case MDEntryType2.TradingSessionHighPrice:
1039
+ data.tradingSessionHighPrice = price;
1040
+ break;
1041
+ case MDEntryType2.TradingSessionLowPrice:
1042
+ data.tradingSessionLowPrice = price;
1043
+ break;
1044
+ case MDEntryType2.VWAP:
1045
+ data.vwap = price;
1046
+ break;
1047
+ case MDEntryType2.Imbalance:
1048
+ data.imbalance = size;
1049
+ break;
1050
+ case MDEntryType2.TradeVolume:
1051
+ data.volume = size;
1052
+ break;
1053
+ case MDEntryType2.OpenInterest:
1054
+ data.openInterest = size;
1055
+ break;
1056
+ case MDEntryType2.CompositeUnderlyingPrice:
1057
+ data.compositeUnderlyingPrice = price;
1058
+ break;
1059
+ case MDEntryType2.SimulatedSellPrice:
1060
+ data.simulatedSellPrice = price;
1061
+ break;
1062
+ case MDEntryType2.SimulatedBuyPrice:
1063
+ data.simulatedBuyPrice = price;
1064
+ break;
1065
+ case MDEntryType2.MarginRate:
1066
+ data.marginRate = price;
1067
+ break;
1068
+ case MDEntryType2.MidPrice:
1069
+ data.midPrice = price;
1070
+ break;
1071
+ case MDEntryType2.EmptyBook:
1072
+ data.emptyBook = 1;
1073
+ break;
1074
+ case MDEntryType2.SettleHighPrice:
1075
+ data.settleHighPrice = price;
1076
+ break;
1077
+ case MDEntryType2.SettleLowPrice:
1078
+ data.settleLowPrice = price;
1079
+ break;
1080
+ case MDEntryType2.PriorSettlePrice:
1081
+ data.priorSettlePrice = price;
1082
+ break;
1083
+ case MDEntryType2.SessionHighBid:
1084
+ data.sessionHighBid = price;
1085
+ break;
1086
+ case MDEntryType2.SessionLowOffer:
1087
+ data.sessionLowOffer = price;
1088
+ break;
1089
+ case MDEntryType2.EarlyPrices:
1090
+ data.earlyPrices = price;
1091
+ break;
1092
+ case MDEntryType2.AuctionClearingPrice:
1093
+ data.auctionClearingPrice = price;
1094
+ break;
1095
+ case MDEntryType2.SwapValueFactor:
1096
+ data.swapValueFactor = price;
1097
+ break;
1098
+ case MDEntryType2.DailyValueAdjustmentForLongPositions:
1099
+ data.dailyValueAdjustmentForLongPositions = price;
1100
+ break;
1101
+ case MDEntryType2.CumulativeValueAdjustmentForLongPositions:
1102
+ data.cumulativeValueAdjustmentForLongPositions = price;
1103
+ break;
1104
+ case MDEntryType2.DailyValueAdjustmentForShortPositions:
1105
+ data.dailyValueAdjustmentForShortPositions = price;
1106
+ break;
1107
+ case MDEntryType2.CumulativeValueAdjustmentForShortPositions:
1108
+ data.cumulativeValueAdjustmentForShortPositions = price;
1109
+ break;
1110
+ case MDEntryType2.FixingPrice:
1111
+ data.fixingPrice = price;
1112
+ break;
1113
+ case MDEntryType2.CashRate:
1114
+ data.cashRate = price;
1115
+ break;
1116
+ case MDEntryType2.RecoveryRate:
1117
+ data.recoveryRate = price;
1118
+ break;
1119
+ case MDEntryType2.RecoveryRateForLong:
1120
+ data.recoveryRateForLong = price;
1121
+ break;
1122
+ case MDEntryType2.RecoveryRateForShort:
1123
+ data.recoveryRateForShort = price;
1124
+ break;
1125
+ case MDEntryType2.MarketBid:
1126
+ data.marketBid = price;
1127
+ break;
1128
+ case MDEntryType2.MarketOffer:
1129
+ data.marketOffer = price;
1130
+ break;
1131
+ case MDEntryType2.ShortSaleMinPrice:
1132
+ data.shortSaleMinPrice = price;
1133
+ break;
1134
+ case MDEntryType2.PreviousClosingPrice:
1135
+ data.previousClosingPrice = price;
1136
+ break;
1137
+ case MDEntryType2.ThresholdLimitPriceBanding:
1138
+ data.thresholdLimitPriceBanding = price;
1139
+ break;
1140
+ case MDEntryType2.DailyFinancingValue:
1141
+ data.dailyFinancingValue = price;
1142
+ break;
1143
+ case MDEntryType2.AccruedFinancingValue:
1144
+ data.accruedFinancingValue = price;
1145
+ break;
1146
+ case MDEntryType2.TWAP:
1147
+ data.twap = price;
1148
+ break;
1149
+ }
1150
+ }
1151
+ data.spread = data.offer - data.bid;
1152
+ if (!marketDataPrices.has(symbol)) {
1153
+ parser.logger.log({
1154
+ level: "info",
1155
+ message: `Creating new price history array for symbol: ${symbol}`
1156
+ });
1157
+ marketDataPrices.set(symbol, []);
1158
+ }
1159
+ const prices = marketDataPrices.get(symbol);
1160
+ prices.push(data);
1161
+ parser.logger.log({
1162
+ level: "info",
1163
+ message: `Updated price history for ${symbol}. Current size: ${prices.length}`
1164
+ });
1165
+ if (prices.length > maxPriceHistory) {
1166
+ prices.splice(0, prices.length - maxPriceHistory);
1167
+ parser.logger.log({
1168
+ level: "info",
1169
+ message: `Trimmed price history for ${symbol} to ${maxPriceHistory} entries`
1170
+ });
1171
+ }
1172
+ onPriceUpdate?.(symbol, data);
1173
+ const mdReqID = message.getField(Fields3.MDReqID)?.value;
1174
+ if (mdReqID) {
1175
+ const callback = pendingRequests.get(mdReqID);
1176
+ if (callback) {
1177
+ callback(message);
1178
+ pendingRequests.delete(mdReqID);
1179
+ parser.logger.log({
1180
+ level: "info",
1181
+ message: `Resolved market data request for ID: ${mdReqID}`
1182
+ });
1183
+ }
1184
+ }
1185
+ } else if (msgType === Messages3.ExecutionReport) {
1186
+ const reqId = message.getField(Fields3.ClOrdID)?.value;
1187
+ const callback = pendingRequests.get(reqId);
1188
+ if (callback) {
1189
+ callback(message);
1190
+ pendingRequests.delete(reqId);
1191
+ }
1192
+ }
1193
+ }
1194
+
745
1195
  // src/MCPLocal.ts
746
- var MCPLocal = class {
747
- parser;
1196
+ var MCPLocal = class extends MCPBase {
1197
+ /**
1198
+ * Map to store verified orders before execution
1199
+ * @private
1200
+ */
1201
+ verifiedOrders = /* @__PURE__ */ new Map();
1202
+ /**
1203
+ * Map to store pending requests and their callbacks
1204
+ * @private
1205
+ */
1206
+ pendingRequests = /* @__PURE__ */ new Map();
1207
+ /**
1208
+ * Map to store market data prices for each symbol
1209
+ * @private
1210
+ */
1211
+ marketDataPrices = /* @__PURE__ */ new Map();
1212
+ /**
1213
+ * Maximum number of price history entries to keep per symbol
1214
+ * @private
1215
+ */
1216
+ MAX_PRICE_HISTORY = 1e5;
748
1217
  server = new Server(
749
1218
  {
750
1219
  name: "fixparser",
@@ -766,77 +1235,13 @@ var MCPLocal = class {
766
1235
  }
767
1236
  );
768
1237
  transport = new StdioServerTransport();
769
- onReady = void 0;
770
- pendingRequests = /* @__PURE__ */ new Map();
771
- verifiedOrders = /* @__PURE__ */ new Map();
772
- marketDataPrices = /* @__PURE__ */ new Map();
773
- MAX_PRICE_HISTORY = 1e5;
774
- // Maximum number of price points to store per symbol
775
1238
  constructor({ logger, onReady }) {
776
- if (onReady) this.onReady = onReady;
1239
+ super({ logger, onReady });
777
1240
  }
778
1241
  async register(parser) {
779
1242
  this.parser = parser;
780
1243
  this.parser.addOnMessageCallback((message) => {
781
- this.parser?.logger.log({
782
- level: "info",
783
- message: `MCP Server received message: ${message.messageType}: ${message.description}`
784
- });
785
- const msgType = message.messageType;
786
- if (msgType === Messages3.MarketDataSnapshotFullRefresh || msgType === Messages3.ExecutionReport || msgType === Messages3.Reject || msgType === Messages3.MarketDataIncrementalRefresh) {
787
- this.parser?.logger.log({
788
- level: "info",
789
- message: `MCP Server handling message type: ${msgType}`
790
- });
791
- let id;
792
- if (msgType === Messages3.MarketDataIncrementalRefresh || msgType === Messages3.MarketDataSnapshotFullRefresh) {
793
- const symbol = message.getField(Fields3.Symbol);
794
- const price = message.getField(Fields3.MDEntryPx);
795
- const timestamp = message.getField(Fields3.MDEntryTime)?.value || Date.now();
796
- if (symbol?.value && price?.value) {
797
- const symbolStr = String(symbol.value);
798
- const priceNum = Number(price.value);
799
- const priceHistory = this.marketDataPrices.get(symbolStr) || [];
800
- priceHistory.push({
801
- timestamp: Number(timestamp),
802
- price: priceNum
803
- });
804
- if (priceHistory.length > this.MAX_PRICE_HISTORY) {
805
- priceHistory.shift();
806
- }
807
- this.marketDataPrices.set(symbolStr, priceHistory);
808
- this.parser?.logger.log({
809
- level: "info",
810
- message: `MCP Server added ${symbol}: ${priceNum}`
811
- });
812
- this.server.notification({
813
- method: "priceUpdate",
814
- params: {
815
- symbol: symbolStr,
816
- price: priceNum,
817
- timestamp: Number(timestamp)
818
- }
819
- });
820
- }
821
- }
822
- if (msgType === Messages3.MarketDataSnapshotFullRefresh) {
823
- const mdReqID = message.getField(Fields3.MDReqID);
824
- if (mdReqID) id = String(mdReqID.value);
825
- } else if (msgType === Messages3.ExecutionReport) {
826
- const clOrdID = message.getField(Fields3.ClOrdID);
827
- if (clOrdID) id = String(clOrdID.value);
828
- } else if (msgType === Messages3.Reject) {
829
- const refSeqNum = message.getField(Fields3.RefSeqNum);
830
- if (refSeqNum) id = String(refSeqNum.value);
831
- }
832
- if (id) {
833
- const callback = this.pendingRequests.get(id);
834
- if (callback) {
835
- callback(message);
836
- this.pendingRequests.delete(id);
837
- }
838
- }
839
- }
1244
+ handleMessage(message, this.parser, this.pendingRequests, this.marketDataPrices, this.MAX_PRICE_HISTORY);
840
1245
  });
841
1246
  this.addWorkflows();
842
1247
  await this.server.connect(this.transport);
@@ -851,18 +1256,15 @@ var MCPLocal = class {
851
1256
  if (!this.server) {
852
1257
  return;
853
1258
  }
854
- this.server.setRequestHandler(
855
- z.object({ method: z.literal("tools/list") }),
856
- async (request, extra) => {
857
- return {
858
- tools: Object.entries(toolSchemas).map(([name, { description, schema }]) => ({
859
- name,
860
- description,
861
- inputSchema: schema
862
- }))
863
- };
864
- }
865
- );
1259
+ this.server.setRequestHandler(z.object({ method: z.literal("tools/list") }), async () => {
1260
+ return {
1261
+ tools: Object.entries(toolSchemas).map(([name, { description, schema }]) => ({
1262
+ name,
1263
+ description,
1264
+ inputSchema: schema
1265
+ }))
1266
+ };
1267
+ });
866
1268
  this.server.setRequestHandler(
867
1269
  z.object({
868
1270
  method: z.literal("tools/call"),
@@ -874,7 +1276,7 @@ var MCPLocal = class {
874
1276
  }).optional()
875
1277
  })
876
1278
  }),
877
- async (request, extra) => {
1279
+ async (request) => {
878
1280
  const { name, arguments: args } = request.params;
879
1281
  const toolHandlers = createToolHandlers(
880
1282
  this.parser,