fixparser-plugin-mcp 9.1.7-81ea0211 → 9.1.7-89ae1451

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.
@@ -3,6 +3,9 @@ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
3
3
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
4
  import { Field, Fields, Messages } from "fixparser";
5
5
  import { z } from "zod";
6
+ var symbolSchema = z.object({
7
+ symbol: z.string()
8
+ });
6
9
  var fixStringSchema = z.object({
7
10
  fixString: z.string()
8
11
  });
@@ -255,11 +258,25 @@ var MCPLocal = class {
255
258
  },
256
259
  stockGraph: {
257
260
  description: "Generates a price chart for a given symbol",
258
- uri: "stockGraph/{symbol}"
261
+ uri: "stockGraph",
262
+ parameters: {
263
+ type: "object",
264
+ properties: {
265
+ symbol: { type: "string" }
266
+ },
267
+ required: ["symbol"]
268
+ }
259
269
  },
260
270
  stockPriceHistory: {
261
271
  description: "Returns price history for a given symbol",
262
- uri: "stockPriceHistory/{symbol}"
272
+ uri: "stockPriceHistory",
273
+ parameters: {
274
+ type: "object",
275
+ properties: {
276
+ symbol: { type: "string" }
277
+ },
278
+ required: ["symbol"]
279
+ }
263
280
  }
264
281
  }
265
282
  }
@@ -353,20 +370,11 @@ var MCPLocal = class {
353
370
  name: "greeting",
354
371
  description: "A simple greeting resource",
355
372
  uri: "greeting-resource"
356
- }
357
- ]
358
- };
359
- }
360
- );
361
- this.server.setRequestHandler(
362
- z.object({ method: z.literal("resources/templates/list") }),
363
- async (request, extra) => {
364
- return {
365
- templates: [
373
+ },
366
374
  {
367
375
  name: "stockGraph",
368
376
  description: "Generates a price chart for a given symbol",
369
- uri: "stockGraph/{symbol}",
377
+ uri: "stockGraph",
370
378
  parameters: {
371
379
  type: "object",
372
380
  properties: {
@@ -378,7 +386,7 @@ var MCPLocal = class {
378
386
  {
379
387
  name: "stockPriceHistory",
380
388
  description: "Returns price history for a given symbol",
381
- uri: "stockPriceHistory/{symbol}",
389
+ uri: "stockPriceHistory",
382
390
  parameters: {
383
391
  type: "object",
384
392
  properties: {
@@ -566,8 +574,7 @@ var MCPLocal = class {
566
574
  contents: [
567
575
  {
568
576
  type: "text",
569
- text: "Hello, world!",
570
- uri: "greeting-resource"
577
+ text: "Hello, world!"
571
578
  }
572
579
  ]
573
580
  };
@@ -576,8 +583,7 @@ var MCPLocal = class {
576
583
  contents: [
577
584
  {
578
585
  type: "text",
579
- text: "This resource requires a symbol parameter. Please use the stockGraph/{symbol} resource.",
580
- uri: "stockGraph"
586
+ text: "This resource requires a symbol parameter. Please use the stockGraph resource with a symbol parameter."
581
587
  }
582
588
  ]
583
589
  };
@@ -586,133 +592,16 @@ var MCPLocal = class {
586
592
  contents: [
587
593
  {
588
594
  type: "text",
589
- text: "This resource requires a symbol parameter. Please use the stockPriceHistory/{symbol} resource.",
590
- uri: "stockPriceHistory"
595
+ text: "This resource requires a symbol parameter. Please use the stockPriceHistory resource with a symbol parameter."
591
596
  }
592
597
  ]
593
598
  };
594
599
  default:
595
- if (uri.startsWith("stockGraph/")) {
596
- const symbol = uri.split("/")[1];
597
- const priceHistory = this.marketDataPrices.get(symbol) || [];
598
- if (priceHistory.length === 0) {
599
- return {
600
- contents: [
601
- {
602
- type: "text",
603
- text: `No price data available for ${symbol}`
604
- }
605
- ]
606
- };
607
- }
608
- const width = 600;
609
- const height = 300;
610
- const padding = 40;
611
- const xScale = (width - 2 * padding) / (priceHistory.length - 1);
612
- const yMin = Math.min(...priceHistory.map((d) => d.price));
613
- const yMax = Math.max(...priceHistory.map((d) => d.price));
614
- const yScale = (height - 2 * padding) / (yMax - yMin);
615
- const points = priceHistory.map((d, i) => {
616
- const x = padding + i * xScale;
617
- const y = height - padding - (d.price - yMin) * yScale;
618
- return `${x},${y}`;
619
- }).join(" L ");
620
- const svg = `<?xml version="1.0" encoding="UTF-8"?>
621
- <svg width="${width}" height="${height}" xmlns="http://www.w3.org/2000/svg">
622
- <!-- Background -->
623
- <rect width="100%" height="100%" fill="#f8f9fa"/>
624
-
625
- <!-- Grid lines -->
626
- <g stroke="#e9ecef" stroke-width="1">
627
- ${Array.from({ length: 5 }, (_, i) => {
628
- const y = padding + (height - 2 * padding) * i / 4;
629
- return `<line x1="${padding}" y1="${y}" x2="${width - padding}" y2="${y}"/>`;
630
- }).join("\n")}
631
- </g>
632
-
633
- <!-- Price line -->
634
- <path d="M ${points}"
635
- fill="none"
636
- stroke="#007bff"
637
- stroke-width="2"/>
638
-
639
- <!-- Data points -->
640
- ${priceHistory.map((d, i) => {
641
- const x = padding + i * xScale;
642
- const y = height - padding - (d.price - yMin) * yScale;
643
- return `<circle cx="${x}" cy="${y}" r="3" fill="#007bff"/>`;
644
- }).join("\n")}
645
-
646
- <!-- Labels -->
647
- <g font-family="Arial" font-size="12" fill="#495057">
648
- ${Array.from({ length: 5 }, (_, i) => {
649
- const x = padding + (width - 2 * padding) * i / 4;
650
- const index = Math.floor((priceHistory.length - 1) * i / 4);
651
- const timestamp = new Date(priceHistory[index].timestamp).toLocaleTimeString();
652
- return `<text x="${x + padding}" y="${height - padding + 20}" text-anchor="middle">${timestamp}</text>`;
653
- }).join("\n")}
654
- ${Array.from({ length: 5 }, (_, i) => {
655
- const y = padding + (height - 2 * padding) * i / 4;
656
- const price = yMax - (yMax - yMin) * i / 4;
657
- return `<text x="${padding - 5}" y="${y + 4}" text-anchor="end">$${price.toFixed(2)}</text>`;
658
- }).join("\n")}
659
- </g>
660
-
661
- <!-- Title -->
662
- <text x="${width / 2}" y="${padding / 2}"
663
- font-family="Arial" font-size="16" font-weight="bold"
664
- text-anchor="middle" fill="#212529">
665
- ${symbol} - Price Chart (${priceHistory.length} points)
666
- </text>
667
- </svg>`;
668
- return {
669
- contents: [
670
- {
671
- type: "text",
672
- text: svg
673
- }
674
- ]
675
- };
676
- }
677
- if (uri.startsWith("stockPriceHistory/")) {
678
- const symbol = uri.split("/")[1];
679
- const priceHistory = this.marketDataPrices.get(symbol) || [];
680
- if (priceHistory.length === 0) {
681
- return {
682
- contents: [
683
- {
684
- type: "text",
685
- text: `No price data available for ${symbol}`
686
- }
687
- ]
688
- };
689
- }
690
- return {
691
- contents: [
692
- {
693
- type: "text",
694
- text: JSON.stringify(
695
- {
696
- symbol,
697
- count: priceHistory.length,
698
- prices: priceHistory.map((point) => ({
699
- timestamp: new Date(point.timestamp).toISOString(),
700
- price: point.price
701
- }))
702
- },
703
- null,
704
- 2
705
- )
706
- }
707
- ]
708
- };
709
- }
710
600
  return {
711
601
  contents: [
712
602
  {
713
603
  type: "text",
714
- text: `Resource not found: ${uri}`,
715
- uri
604
+ text: `Resource not found: ${uri}`
716
605
  }
717
606
  ],
718
607
  isError: true
@@ -731,12 +620,12 @@ var MCPLocal = class {
731
620
  const parsedMessage = this.parser?.parse(args.fixString);
732
621
  if (!parsedMessage || parsedMessage.length === 0) {
733
622
  return {
734
- contents: [{ type: "text", text: "Error: Failed to parse FIX string" }],
623
+ content: [{ type: "text", text: "Error: Failed to parse FIX string" }],
735
624
  isError: true
736
625
  };
737
626
  }
738
627
  return {
739
- contents: [
628
+ content: [
740
629
  {
741
630
  type: "text",
742
631
  text: `${parsedMessage[0].description}
@@ -746,7 +635,7 @@ ${parsedMessage[0].messageTypeDescription}`
746
635
  };
747
636
  } catch (error) {
748
637
  return {
749
- contents: [
638
+ content: [
750
639
  {
751
640
  type: "text",
752
641
  text: `Error: ${error instanceof Error ? error.message : "Failed to parse FIX string"}`
@@ -768,12 +657,12 @@ ${parsedMessage[0].messageTypeDescription}`
768
657
  const parsedMessage = this.parser?.parse(args.fixString);
769
658
  if (!parsedMessage || parsedMessage.length === 0) {
770
659
  return {
771
- contents: [{ type: "text", text: "Error: Failed to parse FIX string" }],
660
+ content: [{ type: "text", text: "Error: Failed to parse FIX string" }],
772
661
  isError: true
773
662
  };
774
663
  }
775
664
  return {
776
- contents: [
665
+ content: [
777
666
  {
778
667
  type: "text",
779
668
  text: `${parsedMessage[0].toFIXJSON()}`
@@ -782,7 +671,7 @@ ${parsedMessage[0].messageTypeDescription}`
782
671
  };
783
672
  } catch (error) {
784
673
  return {
785
- contents: [
674
+ content: [
786
675
  {
787
676
  type: "text",
788
677
  text: `Error: ${error instanceof Error ? error.message : "Failed to parse FIX string"}`
@@ -879,7 +768,7 @@ ${parsedMessage[0].messageTypeDescription}`
879
768
  "3": "ManualOrder"
880
769
  };
881
770
  return {
882
- contents: [
771
+ content: [
883
772
  {
884
773
  type: "text",
885
774
  text: `VERIFICATION: All parameters valid. Ready to proceed with order execution.
@@ -900,7 +789,7 @@ To execute this order, call the executeOrder tool with these exact same paramete
900
789
  };
901
790
  } catch (error) {
902
791
  return {
903
- contents: [
792
+ content: [
904
793
  {
905
794
  type: "text",
906
795
  text: `Error: ${error instanceof Error ? error.message : "Failed to verify order parameters"}`
@@ -922,7 +811,7 @@ To execute this order, call the executeOrder tool with these exact same paramete
922
811
  const verifiedOrder = this.verifiedOrders.get(args.clOrdID);
923
812
  if (!verifiedOrder) {
924
813
  return {
925
- contents: [
814
+ content: [
926
815
  {
927
816
  type: "text",
928
817
  text: `Error: Order ${args.clOrdID} has not been verified. Please call verifyOrder first.`
@@ -933,7 +822,7 @@ To execute this order, call the executeOrder tool with these exact same paramete
933
822
  }
934
823
  if (verifiedOrder.handlInst !== args.handlInst || verifiedOrder.quantity !== Number.parseFloat(args.quantity) || verifiedOrder.price !== Number.parseFloat(args.price) || verifiedOrder.ordType !== args.ordType || verifiedOrder.side !== args.side || verifiedOrder.symbol !== args.symbol || verifiedOrder.timeInForce !== args.timeInForce) {
935
824
  return {
936
- contents: [
825
+ content: [
937
826
  {
938
827
  type: "text",
939
828
  text: "Error: Order parameters do not match the verified order. Please use the exact same parameters that were verified."
@@ -963,7 +852,7 @@ To execute this order, call the executeOrder tool with these exact same paramete
963
852
  );
964
853
  if (!this.parser?.connected) {
965
854
  return {
966
- contents: [
855
+ content: [
967
856
  {
968
857
  type: "text",
969
858
  text: "Error: Not connected. Ignoring message."
@@ -976,7 +865,7 @@ To execute this order, call the executeOrder tool with these exact same paramete
976
865
  const fixData = await response;
977
866
  this.verifiedOrders.delete(args.clOrdID);
978
867
  return {
979
- contents: [
868
+ content: [
980
869
  {
981
870
  type: "text",
982
871
  text: fixData.messageType === Messages.Reject ? `Reject message for order ${args.clOrdID}: ${JSON.stringify(fixData.toFIXJSON())}` : `Execution Report for order ${args.clOrdID}: ${JSON.stringify(fixData.toFIXJSON())}`
@@ -985,7 +874,7 @@ To execute this order, call the executeOrder tool with these exact same paramete
985
874
  };
986
875
  } catch (error) {
987
876
  return {
988
- contents: [
877
+ content: [
989
878
  {
990
879
  type: "text",
991
880
  text: `Error: ${error instanceof Error ? error.message : "Failed to execute order"}`
@@ -1029,7 +918,7 @@ To execute this order, call the executeOrder tool with these exact same paramete
1029
918
  const mdr = this.parser?.createMessage(...messageFields);
1030
919
  if (!this.parser?.connected) {
1031
920
  return {
1032
- contents: [
921
+ content: [
1033
922
  {
1034
923
  type: "text",
1035
924
  text: "Error: Not connected. Ignoring message."
@@ -1041,7 +930,7 @@ To execute this order, call the executeOrder tool with these exact same paramete
1041
930
  this.parser?.send(mdr);
1042
931
  const fixData = await response;
1043
932
  return {
1044
- contents: [
933
+ content: [
1045
934
  {
1046
935
  type: "text",
1047
936
  text: `Market data for ${args.symbols.join(", ")}: ${JSON.stringify(fixData.toFIXJSON())}`
@@ -1050,7 +939,7 @@ To execute this order, call the executeOrder tool with these exact same paramete
1050
939
  };
1051
940
  } catch (error) {
1052
941
  return {
1053
- contents: [
942
+ content: [
1054
943
  {
1055
944
  type: "text",
1056
945
  text: `Error: ${error instanceof Error ? error.message : "Failed to request market data"}`
@@ -1061,6 +950,143 @@ To execute this order, call the executeOrder tool with these exact same paramete
1061
950
  }
1062
951
  }
1063
952
  );
953
+ this.server.setRequestHandler(
954
+ z.object({
955
+ method: z.literal("stockGraph"),
956
+ params: symbolSchema
957
+ }),
958
+ async (request, extra) => {
959
+ this.parser?.logger.log({
960
+ level: "info",
961
+ message: "MCP Server Resource called: stockGraph"
962
+ });
963
+ const args = request.params;
964
+ const symbol = args.symbol;
965
+ const priceHistory = this.marketDataPrices.get(symbol) || [];
966
+ if (priceHistory.length === 0) {
967
+ return {
968
+ content: [
969
+ {
970
+ type: "text",
971
+ text: `No price data available for ${symbol}`
972
+ }
973
+ ]
974
+ };
975
+ }
976
+ const width = 600;
977
+ const height = 300;
978
+ const padding = 40;
979
+ const xScale = (width - 2 * padding) / (priceHistory.length - 1);
980
+ const yMin = Math.min(...priceHistory.map((d) => d.price));
981
+ const yMax = Math.max(...priceHistory.map((d) => d.price));
982
+ const yScale = (height - 2 * padding) / (yMax - yMin);
983
+ const points = priceHistory.map((d, i) => {
984
+ const x = padding + i * xScale;
985
+ const y = height - padding - (d.price - yMin) * yScale;
986
+ return `${x},${y}`;
987
+ }).join(" L ");
988
+ const svg = `<?xml version="1.0" encoding="UTF-8"?>
989
+ <svg width="${width}" height="${height}" xmlns="http://www.w3.org/2000/svg">
990
+ <!-- Background -->
991
+ <rect width="100%" height="100%" fill="#f8f9fa"/>
992
+
993
+ <!-- Grid lines -->
994
+ <g stroke="#e9ecef" stroke-width="1">
995
+ ${Array.from({ length: 5 }, (_, i) => {
996
+ const y = padding + (height - 2 * padding) * i / 4;
997
+ return `<line x1="${padding}" y1="${y}" x2="${width - padding}" y2="${y}"/>`;
998
+ }).join("\n")}
999
+ </g>
1000
+
1001
+ <!-- Price line -->
1002
+ <path d="M ${points}"
1003
+ fill="none"
1004
+ stroke="#007bff"
1005
+ stroke-width="2"/>
1006
+
1007
+ <!-- Data points -->
1008
+ ${priceHistory.map((d, i) => {
1009
+ const x = padding + i * xScale;
1010
+ const y = height - padding - (d.price - yMin) * yScale;
1011
+ return `<circle cx="${x}" cy="${y}" r="3" fill="#007bff"/>`;
1012
+ }).join("\n")}
1013
+
1014
+ <!-- Labels -->
1015
+ <g font-family="Arial" font-size="12" fill="#495057">
1016
+ ${Array.from({ length: 5 }, (_, i) => {
1017
+ const x = padding + (width - 2 * padding) * i / 4;
1018
+ const index = Math.floor((priceHistory.length - 1) * i / 4);
1019
+ const timestamp = new Date(priceHistory[index].timestamp).toLocaleTimeString();
1020
+ return `<text x="${x + padding}" y="${height - padding + 20}" text-anchor="middle">${timestamp}</text>`;
1021
+ }).join("\n")}
1022
+ ${Array.from({ length: 5 }, (_, i) => {
1023
+ const y = padding + (height - 2 * padding) * i / 4;
1024
+ const price = yMax - (yMax - yMin) * i / 4;
1025
+ return `<text x="${padding - 5}" y="${y + 4}" text-anchor="end">$${price.toFixed(2)}</text>`;
1026
+ }).join("\n")}
1027
+ </g>
1028
+
1029
+ <!-- Title -->
1030
+ <text x="${width / 2}" y="${padding / 2}"
1031
+ font-family="Arial" font-size="16" font-weight="bold"
1032
+ text-anchor="middle" fill="#212529">
1033
+ ${symbol} - Price Chart (${priceHistory.length} points)
1034
+ </text>
1035
+ </svg>`;
1036
+ return {
1037
+ content: [
1038
+ {
1039
+ type: "text",
1040
+ text: svg
1041
+ }
1042
+ ]
1043
+ };
1044
+ }
1045
+ );
1046
+ this.server.setRequestHandler(
1047
+ z.object({
1048
+ method: z.literal("stockPriceHistory"),
1049
+ params: symbolSchema
1050
+ }),
1051
+ async (request, extra) => {
1052
+ this.parser?.logger.log({
1053
+ level: "info",
1054
+ message: "MCP Server Resource called: stockPriceHistory"
1055
+ });
1056
+ const args = request.params;
1057
+ const symbol = args.symbol;
1058
+ const priceHistory = this.marketDataPrices.get(symbol) || [];
1059
+ if (priceHistory.length === 0) {
1060
+ return {
1061
+ content: [
1062
+ {
1063
+ type: "text",
1064
+ text: `No price data available for ${symbol}`
1065
+ }
1066
+ ]
1067
+ };
1068
+ }
1069
+ return {
1070
+ content: [
1071
+ {
1072
+ type: "text",
1073
+ text: JSON.stringify(
1074
+ {
1075
+ symbol,
1076
+ count: priceHistory.length,
1077
+ prices: priceHistory.map((point) => ({
1078
+ timestamp: new Date(point.timestamp).toISOString(),
1079
+ price: point.price
1080
+ }))
1081
+ },
1082
+ null,
1083
+ 2
1084
+ )
1085
+ }
1086
+ ]
1087
+ };
1088
+ }
1089
+ );
1064
1090
  process.on("SIGINT", async () => {
1065
1091
  await this.server.close();
1066
1092
  process.exit(0);