fixparser-plugin-mcp 9.1.7-75ded9c1 → 9.1.7-81ea0211
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.
- package/build/cjs/MCPLocal.js +442 -374
- package/build/cjs/MCPLocal.js.map +2 -2
- package/build/esm/MCPLocal.mjs +442 -374
- package/build/esm/MCPLocal.mjs.map +2 -2
- package/build-examples/cjs/example_mcp_local.js +22 -22
- package/build-examples/cjs/example_mcp_local.js.map +3 -3
- package/build-examples/esm/example_mcp_local.mjs +23 -23
- package/build-examples/esm/example_mcp_local.mjs.map +3 -3
- package/package.json +2 -2
package/build/cjs/MCPLocal.js
CHANGED
|
@@ -27,6 +27,100 @@ var import_server = require("@modelcontextprotocol/sdk/server/index.js");
|
|
|
27
27
|
var import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
28
28
|
var import_fixparser = require("fixparser");
|
|
29
29
|
var import_zod = require("zod");
|
|
30
|
+
var fixStringSchema = import_zod.z.object({
|
|
31
|
+
fixString: import_zod.z.string()
|
|
32
|
+
});
|
|
33
|
+
var orderSchema = import_zod.z.object({
|
|
34
|
+
clOrdID: import_zod.z.string(),
|
|
35
|
+
handlInst: import_zod.z.enum(["1", "2", "3"]),
|
|
36
|
+
quantity: import_zod.z.string(),
|
|
37
|
+
price: import_zod.z.string(),
|
|
38
|
+
ordType: import_zod.z.enum([
|
|
39
|
+
"1",
|
|
40
|
+
"2",
|
|
41
|
+
"3",
|
|
42
|
+
"4",
|
|
43
|
+
"5",
|
|
44
|
+
"6",
|
|
45
|
+
"7",
|
|
46
|
+
"8",
|
|
47
|
+
"9",
|
|
48
|
+
"A",
|
|
49
|
+
"B",
|
|
50
|
+
"C",
|
|
51
|
+
"D",
|
|
52
|
+
"E",
|
|
53
|
+
"F",
|
|
54
|
+
"G",
|
|
55
|
+
"H",
|
|
56
|
+
"I",
|
|
57
|
+
"J",
|
|
58
|
+
"K",
|
|
59
|
+
"L",
|
|
60
|
+
"M",
|
|
61
|
+
"P",
|
|
62
|
+
"Q",
|
|
63
|
+
"R",
|
|
64
|
+
"S"
|
|
65
|
+
]),
|
|
66
|
+
side: import_zod.z.enum(["1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H"]),
|
|
67
|
+
symbol: import_zod.z.string(),
|
|
68
|
+
timeInForce: import_zod.z.enum(["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C"])
|
|
69
|
+
});
|
|
70
|
+
var marketDataRequestSchema = import_zod.z.object({
|
|
71
|
+
mdUpdateType: import_zod.z.enum(["0", "1"]),
|
|
72
|
+
symbols: import_zod.z.array(import_zod.z.string()),
|
|
73
|
+
mdReqID: import_zod.z.string(),
|
|
74
|
+
subscriptionRequestType: import_zod.z.enum(["0", "1", "2"]),
|
|
75
|
+
mdEntryTypes: import_zod.z.array(
|
|
76
|
+
import_zod.z.enum([
|
|
77
|
+
"0",
|
|
78
|
+
"1",
|
|
79
|
+
"2",
|
|
80
|
+
"3",
|
|
81
|
+
"4",
|
|
82
|
+
"5",
|
|
83
|
+
"6",
|
|
84
|
+
"7",
|
|
85
|
+
"8",
|
|
86
|
+
"9",
|
|
87
|
+
"A",
|
|
88
|
+
"B",
|
|
89
|
+
"C",
|
|
90
|
+
"D",
|
|
91
|
+
"E",
|
|
92
|
+
"F",
|
|
93
|
+
"G",
|
|
94
|
+
"H",
|
|
95
|
+
"J",
|
|
96
|
+
"K",
|
|
97
|
+
"L",
|
|
98
|
+
"M",
|
|
99
|
+
"N",
|
|
100
|
+
"O",
|
|
101
|
+
"P",
|
|
102
|
+
"Q",
|
|
103
|
+
"R",
|
|
104
|
+
"S",
|
|
105
|
+
"T",
|
|
106
|
+
"U",
|
|
107
|
+
"V",
|
|
108
|
+
"W",
|
|
109
|
+
"X",
|
|
110
|
+
"Y",
|
|
111
|
+
"Z",
|
|
112
|
+
"a",
|
|
113
|
+
"b",
|
|
114
|
+
"c",
|
|
115
|
+
"d",
|
|
116
|
+
"e",
|
|
117
|
+
"g",
|
|
118
|
+
"h",
|
|
119
|
+
"i",
|
|
120
|
+
"t"
|
|
121
|
+
])
|
|
122
|
+
)
|
|
123
|
+
});
|
|
30
124
|
var MCPLocal = class {
|
|
31
125
|
parser;
|
|
32
126
|
server = new import_server.Server(
|
|
@@ -240,14 +334,6 @@ var MCPLocal = class {
|
|
|
240
334
|
level: "info",
|
|
241
335
|
message: `MCP Server added ${symbol}: ${priceNum}`
|
|
242
336
|
});
|
|
243
|
-
this.server.notification({
|
|
244
|
-
method: "priceUpdate",
|
|
245
|
-
params: {
|
|
246
|
-
symbol: symbolStr,
|
|
247
|
-
price: priceNum,
|
|
248
|
-
timestamp: Number(timestamp)
|
|
249
|
-
}
|
|
250
|
-
});
|
|
251
337
|
}
|
|
252
338
|
}
|
|
253
339
|
if (msgType === import_fixparser.Messages.MarketDataSnapshotFullRefresh) {
|
|
@@ -300,11 +386,11 @@ var MCPLocal = class {
|
|
|
300
386
|
import_zod.z.object({ method: import_zod.z.literal("resources/templates/list") }),
|
|
301
387
|
async (request, extra) => {
|
|
302
388
|
return {
|
|
303
|
-
|
|
389
|
+
templates: [
|
|
304
390
|
{
|
|
305
391
|
name: "stockGraph",
|
|
306
392
|
description: "Generates a price chart for a given symbol",
|
|
307
|
-
|
|
393
|
+
uri: "stockGraph/{symbol}",
|
|
308
394
|
parameters: {
|
|
309
395
|
type: "object",
|
|
310
396
|
properties: {
|
|
@@ -316,7 +402,7 @@ var MCPLocal = class {
|
|
|
316
402
|
{
|
|
317
403
|
name: "stockPriceHistory",
|
|
318
404
|
description: "Returns price history for a given symbol",
|
|
319
|
-
|
|
405
|
+
uri: "stockPriceHistory/{symbol}",
|
|
320
406
|
parameters: {
|
|
321
407
|
type: "object",
|
|
322
408
|
properties: {
|
|
@@ -489,361 +575,6 @@ var MCPLocal = class {
|
|
|
489
575
|
};
|
|
490
576
|
}
|
|
491
577
|
);
|
|
492
|
-
this.server.setRequestHandler(
|
|
493
|
-
import_zod.z.object({
|
|
494
|
-
method: import_zod.z.literal("tools/call"),
|
|
495
|
-
params: import_zod.z.object({
|
|
496
|
-
name: import_zod.z.string(),
|
|
497
|
-
arguments: import_zod.z.any(),
|
|
498
|
-
_meta: import_zod.z.object({
|
|
499
|
-
progressToken: import_zod.z.number()
|
|
500
|
-
}).optional()
|
|
501
|
-
})
|
|
502
|
-
}),
|
|
503
|
-
async (request, extra) => {
|
|
504
|
-
const { name, arguments: args } = request.params;
|
|
505
|
-
switch (name) {
|
|
506
|
-
case "parse":
|
|
507
|
-
try {
|
|
508
|
-
const parsedMessage = this.parser?.parse(args.fixString);
|
|
509
|
-
if (!parsedMessage || parsedMessage.length === 0) {
|
|
510
|
-
return {
|
|
511
|
-
contents: [
|
|
512
|
-
{
|
|
513
|
-
type: "text",
|
|
514
|
-
text: "Error: Failed to parse FIX string",
|
|
515
|
-
uri: "parse"
|
|
516
|
-
}
|
|
517
|
-
],
|
|
518
|
-
isError: true
|
|
519
|
-
};
|
|
520
|
-
}
|
|
521
|
-
return {
|
|
522
|
-
contents: [
|
|
523
|
-
{
|
|
524
|
-
type: "text",
|
|
525
|
-
text: `${parsedMessage[0].description}
|
|
526
|
-
${parsedMessage[0].messageTypeDescription}`,
|
|
527
|
-
uri: "parse"
|
|
528
|
-
}
|
|
529
|
-
]
|
|
530
|
-
};
|
|
531
|
-
} catch (error) {
|
|
532
|
-
return {
|
|
533
|
-
contents: [
|
|
534
|
-
{
|
|
535
|
-
type: "text",
|
|
536
|
-
text: `Error: ${error instanceof Error ? error.message : "Failed to parse FIX string"}`,
|
|
537
|
-
uri: "parse"
|
|
538
|
-
}
|
|
539
|
-
],
|
|
540
|
-
isError: true
|
|
541
|
-
};
|
|
542
|
-
}
|
|
543
|
-
case "parseToJSON":
|
|
544
|
-
try {
|
|
545
|
-
const parsedMessage = this.parser?.parse(args.fixString);
|
|
546
|
-
if (!parsedMessage || parsedMessage.length === 0) {
|
|
547
|
-
return {
|
|
548
|
-
contents: [
|
|
549
|
-
{
|
|
550
|
-
type: "text",
|
|
551
|
-
text: "Error: Failed to parse FIX string",
|
|
552
|
-
uri: "parseToJSON"
|
|
553
|
-
}
|
|
554
|
-
],
|
|
555
|
-
isError: true
|
|
556
|
-
};
|
|
557
|
-
}
|
|
558
|
-
return {
|
|
559
|
-
contents: [
|
|
560
|
-
{
|
|
561
|
-
type: "text",
|
|
562
|
-
text: `${parsedMessage[0].toFIXJSON()}`,
|
|
563
|
-
uri: "parseToJSON"
|
|
564
|
-
}
|
|
565
|
-
]
|
|
566
|
-
};
|
|
567
|
-
} catch (error) {
|
|
568
|
-
return {
|
|
569
|
-
contents: [
|
|
570
|
-
{
|
|
571
|
-
type: "text",
|
|
572
|
-
text: `Error: ${error instanceof Error ? error.message : "Failed to parse FIX string"}`,
|
|
573
|
-
uri: "parseToJSON"
|
|
574
|
-
}
|
|
575
|
-
],
|
|
576
|
-
isError: true
|
|
577
|
-
};
|
|
578
|
-
}
|
|
579
|
-
case "verifyOrder":
|
|
580
|
-
try {
|
|
581
|
-
this.verifiedOrders.set(args.clOrdID, {
|
|
582
|
-
clOrdID: args.clOrdID,
|
|
583
|
-
handlInst: args.handlInst,
|
|
584
|
-
quantity: Number.parseFloat(args.quantity),
|
|
585
|
-
price: Number.parseFloat(args.price),
|
|
586
|
-
ordType: args.ordType,
|
|
587
|
-
side: args.side,
|
|
588
|
-
symbol: args.symbol,
|
|
589
|
-
timeInForce: args.timeInForce
|
|
590
|
-
});
|
|
591
|
-
const ordTypeNames = {
|
|
592
|
-
"1": "Market",
|
|
593
|
-
"2": "Limit",
|
|
594
|
-
"3": "Stop",
|
|
595
|
-
"4": "StopLimit",
|
|
596
|
-
"5": "MarketOnClose",
|
|
597
|
-
"6": "WithOrWithout",
|
|
598
|
-
"7": "LimitOrBetter",
|
|
599
|
-
"8": "LimitWithOrWithout",
|
|
600
|
-
"9": "OnBasis",
|
|
601
|
-
A: "OnClose",
|
|
602
|
-
B: "LimitOnClose",
|
|
603
|
-
C: "ForexMarket",
|
|
604
|
-
D: "PreviouslyQuoted",
|
|
605
|
-
E: "PreviouslyIndicated",
|
|
606
|
-
F: "ForexLimit",
|
|
607
|
-
G: "ForexSwap",
|
|
608
|
-
H: "ForexPreviouslyQuoted",
|
|
609
|
-
I: "Funari",
|
|
610
|
-
J: "MarketIfTouched",
|
|
611
|
-
K: "MarketWithLeftOverAsLimit",
|
|
612
|
-
L: "PreviousFundValuationPoint",
|
|
613
|
-
M: "NextFundValuationPoint",
|
|
614
|
-
P: "Pegged",
|
|
615
|
-
Q: "CounterOrderSelection",
|
|
616
|
-
R: "StopOnBidOrOffer",
|
|
617
|
-
S: "StopLimitOnBidOrOffer"
|
|
618
|
-
};
|
|
619
|
-
const sideNames = {
|
|
620
|
-
"1": "Buy",
|
|
621
|
-
"2": "Sell",
|
|
622
|
-
"3": "BuyMinus",
|
|
623
|
-
"4": "SellPlus",
|
|
624
|
-
"5": "SellShort",
|
|
625
|
-
"6": "SellShortExempt",
|
|
626
|
-
"7": "Undisclosed",
|
|
627
|
-
"8": "Cross",
|
|
628
|
-
"9": "CrossShort",
|
|
629
|
-
A: "CrossShortExempt",
|
|
630
|
-
B: "AsDefined",
|
|
631
|
-
C: "Opposite",
|
|
632
|
-
D: "Subscribe",
|
|
633
|
-
E: "Redeem",
|
|
634
|
-
F: "Lend",
|
|
635
|
-
G: "Borrow",
|
|
636
|
-
H: "SellUndisclosed"
|
|
637
|
-
};
|
|
638
|
-
const timeInForceNames = {
|
|
639
|
-
"0": "Day",
|
|
640
|
-
"1": "GoodTillCancel",
|
|
641
|
-
"2": "AtTheOpening",
|
|
642
|
-
"3": "ImmediateOrCancel",
|
|
643
|
-
"4": "FillOrKill",
|
|
644
|
-
"5": "GoodTillCrossing",
|
|
645
|
-
"6": "GoodTillDate",
|
|
646
|
-
"7": "AtTheClose",
|
|
647
|
-
"8": "GoodThroughCrossing",
|
|
648
|
-
"9": "AtCrossing",
|
|
649
|
-
A: "GoodForTime",
|
|
650
|
-
B: "GoodForAuction",
|
|
651
|
-
C: "GoodForMonth"
|
|
652
|
-
};
|
|
653
|
-
const handlInstNames = {
|
|
654
|
-
"1": "AutomatedExecutionNoIntervention",
|
|
655
|
-
"2": "AutomatedExecutionInterventionOK",
|
|
656
|
-
"3": "ManualOrder"
|
|
657
|
-
};
|
|
658
|
-
return {
|
|
659
|
-
contents: [
|
|
660
|
-
{
|
|
661
|
-
type: "text",
|
|
662
|
-
text: `VERIFICATION: All parameters valid. Ready to proceed with order execution.
|
|
663
|
-
|
|
664
|
-
Parameters verified:
|
|
665
|
-
- ClOrdID: ${args.clOrdID}
|
|
666
|
-
- HandlInst: ${args.handlInst} (${handlInstNames[args.handlInst]})
|
|
667
|
-
- Quantity: ${args.quantity}
|
|
668
|
-
- Price: ${args.price}
|
|
669
|
-
- OrdType: ${args.ordType} (${ordTypeNames[args.ordType]})
|
|
670
|
-
- Side: ${args.side} (${sideNames[args.side]})
|
|
671
|
-
- Symbol: ${args.symbol}
|
|
672
|
-
- TimeInForce: ${args.timeInForce} (${timeInForceNames[args.timeInForce]})
|
|
673
|
-
|
|
674
|
-
To execute this order, call the executeOrder tool with these exact same parameters.`,
|
|
675
|
-
uri: "verifyOrder"
|
|
676
|
-
}
|
|
677
|
-
]
|
|
678
|
-
};
|
|
679
|
-
} catch (error) {
|
|
680
|
-
return {
|
|
681
|
-
contents: [
|
|
682
|
-
{
|
|
683
|
-
type: "text",
|
|
684
|
-
text: `Error: ${error instanceof Error ? error.message : "Failed to verify order parameters"}`,
|
|
685
|
-
uri: "verifyOrder"
|
|
686
|
-
}
|
|
687
|
-
],
|
|
688
|
-
isError: true
|
|
689
|
-
};
|
|
690
|
-
}
|
|
691
|
-
case "executeOrder":
|
|
692
|
-
try {
|
|
693
|
-
const verifiedOrder = this.verifiedOrders.get(args.clOrdID);
|
|
694
|
-
if (!verifiedOrder) {
|
|
695
|
-
return {
|
|
696
|
-
contents: [
|
|
697
|
-
{
|
|
698
|
-
type: "text",
|
|
699
|
-
text: `Error: Order ${args.clOrdID} has not been verified. Please call verifyOrder first.`,
|
|
700
|
-
uri: "executeOrder"
|
|
701
|
-
}
|
|
702
|
-
],
|
|
703
|
-
isError: true
|
|
704
|
-
};
|
|
705
|
-
}
|
|
706
|
-
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) {
|
|
707
|
-
return {
|
|
708
|
-
contents: [
|
|
709
|
-
{
|
|
710
|
-
type: "text",
|
|
711
|
-
text: "Error: Order parameters do not match the verified order. Please use the exact same parameters that were verified.",
|
|
712
|
-
uri: "executeOrder"
|
|
713
|
-
}
|
|
714
|
-
],
|
|
715
|
-
isError: true
|
|
716
|
-
};
|
|
717
|
-
}
|
|
718
|
-
const response = new Promise((resolve) => {
|
|
719
|
-
this.pendingRequests.set(args.clOrdID, resolve);
|
|
720
|
-
});
|
|
721
|
-
const order = this.parser?.createMessage(
|
|
722
|
-
new import_fixparser.Field(import_fixparser.Fields.MsgType, import_fixparser.Messages.NewOrderSingle),
|
|
723
|
-
new import_fixparser.Field(import_fixparser.Fields.MsgSeqNum, this.parser?.getNextTargetMsgSeqNum()),
|
|
724
|
-
new import_fixparser.Field(import_fixparser.Fields.SenderCompID, this.parser?.sender),
|
|
725
|
-
new import_fixparser.Field(import_fixparser.Fields.TargetCompID, this.parser?.target),
|
|
726
|
-
new import_fixparser.Field(import_fixparser.Fields.SendingTime, this.parser?.getTimestamp()),
|
|
727
|
-
new import_fixparser.Field(import_fixparser.Fields.ClOrdID, args.clOrdID),
|
|
728
|
-
new import_fixparser.Field(import_fixparser.Fields.Side, args.side),
|
|
729
|
-
new import_fixparser.Field(import_fixparser.Fields.Symbol, args.symbol),
|
|
730
|
-
new import_fixparser.Field(import_fixparser.Fields.OrderQty, Number.parseFloat(args.quantity)),
|
|
731
|
-
new import_fixparser.Field(import_fixparser.Fields.Price, Number.parseFloat(args.price)),
|
|
732
|
-
new import_fixparser.Field(import_fixparser.Fields.OrdType, args.ordType),
|
|
733
|
-
new import_fixparser.Field(import_fixparser.Fields.HandlInst, args.handlInst),
|
|
734
|
-
new import_fixparser.Field(import_fixparser.Fields.TimeInForce, args.timeInForce),
|
|
735
|
-
new import_fixparser.Field(import_fixparser.Fields.TransactTime, this.parser?.getTimestamp())
|
|
736
|
-
);
|
|
737
|
-
if (!this.parser?.connected) {
|
|
738
|
-
return {
|
|
739
|
-
contents: [
|
|
740
|
-
{
|
|
741
|
-
type: "text",
|
|
742
|
-
text: "Error: Not connected. Ignoring message.",
|
|
743
|
-
uri: "executeOrder"
|
|
744
|
-
}
|
|
745
|
-
],
|
|
746
|
-
isError: true
|
|
747
|
-
};
|
|
748
|
-
}
|
|
749
|
-
this.parser?.send(order);
|
|
750
|
-
const fixData = await response;
|
|
751
|
-
this.verifiedOrders.delete(args.clOrdID);
|
|
752
|
-
return {
|
|
753
|
-
contents: [
|
|
754
|
-
{
|
|
755
|
-
type: "text",
|
|
756
|
-
text: fixData.messageType === import_fixparser.Messages.Reject ? `Reject message for order ${args.clOrdID}: ${JSON.stringify(fixData.toFIXJSON())}` : `Execution Report for order ${args.clOrdID}: ${JSON.stringify(fixData.toFIXJSON())}`,
|
|
757
|
-
uri: "executeOrder"
|
|
758
|
-
}
|
|
759
|
-
]
|
|
760
|
-
};
|
|
761
|
-
} catch (error) {
|
|
762
|
-
return {
|
|
763
|
-
contents: [
|
|
764
|
-
{
|
|
765
|
-
type: "text",
|
|
766
|
-
text: `Error: ${error instanceof Error ? error.message : "Failed to execute order"}`,
|
|
767
|
-
uri: "executeOrder"
|
|
768
|
-
}
|
|
769
|
-
],
|
|
770
|
-
isError: true
|
|
771
|
-
};
|
|
772
|
-
}
|
|
773
|
-
case "marketDataRequest":
|
|
774
|
-
try {
|
|
775
|
-
const response = new Promise((resolve) => {
|
|
776
|
-
this.pendingRequests.set(args.mdReqID, resolve);
|
|
777
|
-
});
|
|
778
|
-
const messageFields = [
|
|
779
|
-
new import_fixparser.Field(import_fixparser.Fields.MsgType, import_fixparser.Messages.MarketDataRequest),
|
|
780
|
-
new import_fixparser.Field(import_fixparser.Fields.SenderCompID, this.parser?.sender),
|
|
781
|
-
new import_fixparser.Field(import_fixparser.Fields.MsgSeqNum, this.parser?.getNextTargetMsgSeqNum()),
|
|
782
|
-
new import_fixparser.Field(import_fixparser.Fields.TargetCompID, this.parser?.target),
|
|
783
|
-
new import_fixparser.Field(import_fixparser.Fields.SendingTime, this.parser?.getTimestamp()),
|
|
784
|
-
new import_fixparser.Field(import_fixparser.Fields.MDReqID, args.mdReqID),
|
|
785
|
-
new import_fixparser.Field(import_fixparser.Fields.SubscriptionRequestType, args.subscriptionRequestType),
|
|
786
|
-
new import_fixparser.Field(import_fixparser.Fields.MarketDepth, 0),
|
|
787
|
-
new import_fixparser.Field(import_fixparser.Fields.MDUpdateType, args.mdUpdateType)
|
|
788
|
-
];
|
|
789
|
-
messageFields.push(new import_fixparser.Field(import_fixparser.Fields.NoRelatedSym, args.symbols.length));
|
|
790
|
-
args.symbols.forEach((symbol) => {
|
|
791
|
-
messageFields.push(new import_fixparser.Field(import_fixparser.Fields.Symbol, symbol));
|
|
792
|
-
});
|
|
793
|
-
messageFields.push(new import_fixparser.Field(import_fixparser.Fields.NoMDEntryTypes, args.mdEntryTypes.length));
|
|
794
|
-
args.mdEntryTypes.forEach((entryType) => {
|
|
795
|
-
messageFields.push(new import_fixparser.Field(import_fixparser.Fields.MDEntryType, entryType));
|
|
796
|
-
});
|
|
797
|
-
const mdr = this.parser?.createMessage(...messageFields);
|
|
798
|
-
if (!this.parser?.connected) {
|
|
799
|
-
return {
|
|
800
|
-
contents: [
|
|
801
|
-
{
|
|
802
|
-
type: "text",
|
|
803
|
-
text: "Error: Not connected. Ignoring message.",
|
|
804
|
-
uri: "marketDataRequest"
|
|
805
|
-
}
|
|
806
|
-
],
|
|
807
|
-
isError: true
|
|
808
|
-
};
|
|
809
|
-
}
|
|
810
|
-
this.parser?.send(mdr);
|
|
811
|
-
const fixData = await response;
|
|
812
|
-
return {
|
|
813
|
-
contents: [
|
|
814
|
-
{
|
|
815
|
-
type: "text",
|
|
816
|
-
text: `Market data for ${args.symbols.join(", ")}: ${JSON.stringify(fixData.toFIXJSON())}`,
|
|
817
|
-
uri: "marketDataRequest"
|
|
818
|
-
}
|
|
819
|
-
]
|
|
820
|
-
};
|
|
821
|
-
} catch (error) {
|
|
822
|
-
return {
|
|
823
|
-
contents: [
|
|
824
|
-
{
|
|
825
|
-
type: "text",
|
|
826
|
-
text: `Error: ${error instanceof Error ? error.message : "Failed to request market data"}`,
|
|
827
|
-
uri: "marketDataRequest"
|
|
828
|
-
}
|
|
829
|
-
],
|
|
830
|
-
isError: true
|
|
831
|
-
};
|
|
832
|
-
}
|
|
833
|
-
default:
|
|
834
|
-
return {
|
|
835
|
-
contents: [
|
|
836
|
-
{
|
|
837
|
-
type: "text",
|
|
838
|
-
text: `Tool not found: ${name}`,
|
|
839
|
-
uri: name
|
|
840
|
-
}
|
|
841
|
-
],
|
|
842
|
-
isError: true
|
|
843
|
-
};
|
|
844
|
-
}
|
|
845
|
-
}
|
|
846
|
-
);
|
|
847
578
|
this.server.setRequestHandler(
|
|
848
579
|
import_zod.z.object({
|
|
849
580
|
method: import_zod.z.literal("resources/read"),
|
|
@@ -893,8 +624,7 @@ To execute this order, call the executeOrder tool with these exact same paramete
|
|
|
893
624
|
contents: [
|
|
894
625
|
{
|
|
895
626
|
type: "text",
|
|
896
|
-
text: `No price data available for ${symbol}
|
|
897
|
-
uri
|
|
627
|
+
text: `No price data available for ${symbol}`
|
|
898
628
|
}
|
|
899
629
|
]
|
|
900
630
|
};
|
|
@@ -963,8 +693,7 @@ To execute this order, call the executeOrder tool with these exact same paramete
|
|
|
963
693
|
contents: [
|
|
964
694
|
{
|
|
965
695
|
type: "text",
|
|
966
|
-
text: svg
|
|
967
|
-
uri
|
|
696
|
+
text: svg
|
|
968
697
|
}
|
|
969
698
|
]
|
|
970
699
|
};
|
|
@@ -977,8 +706,7 @@ To execute this order, call the executeOrder tool with these exact same paramete
|
|
|
977
706
|
contents: [
|
|
978
707
|
{
|
|
979
708
|
type: "text",
|
|
980
|
-
text: `No price data available for ${symbol}
|
|
981
|
-
uri
|
|
709
|
+
text: `No price data available for ${symbol}`
|
|
982
710
|
}
|
|
983
711
|
]
|
|
984
712
|
};
|
|
@@ -998,8 +726,7 @@ To execute this order, call the executeOrder tool with these exact same paramete
|
|
|
998
726
|
},
|
|
999
727
|
null,
|
|
1000
728
|
2
|
|
1001
|
-
)
|
|
1002
|
-
uri
|
|
729
|
+
)
|
|
1003
730
|
}
|
|
1004
731
|
]
|
|
1005
732
|
};
|
|
@@ -1017,6 +744,347 @@ To execute this order, call the executeOrder tool with these exact same paramete
|
|
|
1017
744
|
}
|
|
1018
745
|
}
|
|
1019
746
|
);
|
|
747
|
+
this.server.setRequestHandler(
|
|
748
|
+
import_zod.z.object({
|
|
749
|
+
method: import_zod.z.literal("parse"),
|
|
750
|
+
params: fixStringSchema
|
|
751
|
+
}),
|
|
752
|
+
async (request, extra) => {
|
|
753
|
+
try {
|
|
754
|
+
const args = request.params;
|
|
755
|
+
const parsedMessage = this.parser?.parse(args.fixString);
|
|
756
|
+
if (!parsedMessage || parsedMessage.length === 0) {
|
|
757
|
+
return {
|
|
758
|
+
contents: [{ type: "text", text: "Error: Failed to parse FIX string" }],
|
|
759
|
+
isError: true
|
|
760
|
+
};
|
|
761
|
+
}
|
|
762
|
+
return {
|
|
763
|
+
contents: [
|
|
764
|
+
{
|
|
765
|
+
type: "text",
|
|
766
|
+
text: `${parsedMessage[0].description}
|
|
767
|
+
${parsedMessage[0].messageTypeDescription}`
|
|
768
|
+
}
|
|
769
|
+
]
|
|
770
|
+
};
|
|
771
|
+
} catch (error) {
|
|
772
|
+
return {
|
|
773
|
+
contents: [
|
|
774
|
+
{
|
|
775
|
+
type: "text",
|
|
776
|
+
text: `Error: ${error instanceof Error ? error.message : "Failed to parse FIX string"}`
|
|
777
|
+
}
|
|
778
|
+
],
|
|
779
|
+
isError: true
|
|
780
|
+
};
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
);
|
|
784
|
+
this.server.setRequestHandler(
|
|
785
|
+
import_zod.z.object({
|
|
786
|
+
method: import_zod.z.literal("parseToJSON"),
|
|
787
|
+
params: fixStringSchema
|
|
788
|
+
}),
|
|
789
|
+
async (request, extra) => {
|
|
790
|
+
try {
|
|
791
|
+
const args = request.params;
|
|
792
|
+
const parsedMessage = this.parser?.parse(args.fixString);
|
|
793
|
+
if (!parsedMessage || parsedMessage.length === 0) {
|
|
794
|
+
return {
|
|
795
|
+
contents: [{ type: "text", text: "Error: Failed to parse FIX string" }],
|
|
796
|
+
isError: true
|
|
797
|
+
};
|
|
798
|
+
}
|
|
799
|
+
return {
|
|
800
|
+
contents: [
|
|
801
|
+
{
|
|
802
|
+
type: "text",
|
|
803
|
+
text: `${parsedMessage[0].toFIXJSON()}`
|
|
804
|
+
}
|
|
805
|
+
]
|
|
806
|
+
};
|
|
807
|
+
} catch (error) {
|
|
808
|
+
return {
|
|
809
|
+
contents: [
|
|
810
|
+
{
|
|
811
|
+
type: "text",
|
|
812
|
+
text: `Error: ${error instanceof Error ? error.message : "Failed to parse FIX string"}`
|
|
813
|
+
}
|
|
814
|
+
],
|
|
815
|
+
isError: true
|
|
816
|
+
};
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
);
|
|
820
|
+
this.server.setRequestHandler(
|
|
821
|
+
import_zod.z.object({
|
|
822
|
+
method: import_zod.z.literal("verifyOrder"),
|
|
823
|
+
params: orderSchema
|
|
824
|
+
}),
|
|
825
|
+
async (request, extra) => {
|
|
826
|
+
try {
|
|
827
|
+
const args = request.params;
|
|
828
|
+
this.verifiedOrders.set(args.clOrdID, {
|
|
829
|
+
clOrdID: args.clOrdID,
|
|
830
|
+
handlInst: args.handlInst,
|
|
831
|
+
quantity: Number.parseFloat(args.quantity),
|
|
832
|
+
price: Number.parseFloat(args.price),
|
|
833
|
+
ordType: args.ordType,
|
|
834
|
+
side: args.side,
|
|
835
|
+
symbol: args.symbol,
|
|
836
|
+
timeInForce: args.timeInForce
|
|
837
|
+
});
|
|
838
|
+
const ordTypeNames = {
|
|
839
|
+
"1": "Market",
|
|
840
|
+
"2": "Limit",
|
|
841
|
+
"3": "Stop",
|
|
842
|
+
"4": "StopLimit",
|
|
843
|
+
"5": "MarketOnClose",
|
|
844
|
+
"6": "WithOrWithout",
|
|
845
|
+
"7": "LimitOrBetter",
|
|
846
|
+
"8": "LimitWithOrWithout",
|
|
847
|
+
"9": "OnBasis",
|
|
848
|
+
A: "OnClose",
|
|
849
|
+
B: "LimitOnClose",
|
|
850
|
+
C: "ForexMarket",
|
|
851
|
+
D: "PreviouslyQuoted",
|
|
852
|
+
E: "PreviouslyIndicated",
|
|
853
|
+
F: "ForexLimit",
|
|
854
|
+
G: "ForexSwap",
|
|
855
|
+
H: "ForexPreviouslyQuoted",
|
|
856
|
+
I: "Funari",
|
|
857
|
+
J: "MarketIfTouched",
|
|
858
|
+
K: "MarketWithLeftOverAsLimit",
|
|
859
|
+
L: "PreviousFundValuationPoint",
|
|
860
|
+
M: "NextFundValuationPoint",
|
|
861
|
+
P: "Pegged",
|
|
862
|
+
Q: "CounterOrderSelection",
|
|
863
|
+
R: "StopOnBidOrOffer",
|
|
864
|
+
S: "StopLimitOnBidOrOffer"
|
|
865
|
+
};
|
|
866
|
+
const sideNames = {
|
|
867
|
+
"1": "Buy",
|
|
868
|
+
"2": "Sell",
|
|
869
|
+
"3": "BuyMinus",
|
|
870
|
+
"4": "SellPlus",
|
|
871
|
+
"5": "SellShort",
|
|
872
|
+
"6": "SellShortExempt",
|
|
873
|
+
"7": "Undisclosed",
|
|
874
|
+
"8": "Cross",
|
|
875
|
+
"9": "CrossShort",
|
|
876
|
+
A: "CrossShortExempt",
|
|
877
|
+
B: "AsDefined",
|
|
878
|
+
C: "Opposite",
|
|
879
|
+
D: "Subscribe",
|
|
880
|
+
E: "Redeem",
|
|
881
|
+
F: "Lend",
|
|
882
|
+
G: "Borrow",
|
|
883
|
+
H: "SellUndisclosed"
|
|
884
|
+
};
|
|
885
|
+
const timeInForceNames = {
|
|
886
|
+
"0": "Day",
|
|
887
|
+
"1": "GoodTillCancel",
|
|
888
|
+
"2": "AtTheOpening",
|
|
889
|
+
"3": "ImmediateOrCancel",
|
|
890
|
+
"4": "FillOrKill",
|
|
891
|
+
"5": "GoodTillCrossing",
|
|
892
|
+
"6": "GoodTillDate",
|
|
893
|
+
"7": "AtTheClose",
|
|
894
|
+
"8": "GoodThroughCrossing",
|
|
895
|
+
"9": "AtCrossing",
|
|
896
|
+
A: "GoodForTime",
|
|
897
|
+
B: "GoodForAuction",
|
|
898
|
+
C: "GoodForMonth"
|
|
899
|
+
};
|
|
900
|
+
const handlInstNames = {
|
|
901
|
+
"1": "AutomatedExecutionNoIntervention",
|
|
902
|
+
"2": "AutomatedExecutionInterventionOK",
|
|
903
|
+
"3": "ManualOrder"
|
|
904
|
+
};
|
|
905
|
+
return {
|
|
906
|
+
contents: [
|
|
907
|
+
{
|
|
908
|
+
type: "text",
|
|
909
|
+
text: `VERIFICATION: All parameters valid. Ready to proceed with order execution.
|
|
910
|
+
|
|
911
|
+
Parameters verified:
|
|
912
|
+
- ClOrdID: ${args.clOrdID}
|
|
913
|
+
- HandlInst: ${args.handlInst} (${handlInstNames[args.handlInst]})
|
|
914
|
+
- Quantity: ${args.quantity}
|
|
915
|
+
- Price: ${args.price}
|
|
916
|
+
- OrdType: ${args.ordType} (${ordTypeNames[args.ordType]})
|
|
917
|
+
- Side: ${args.side} (${sideNames[args.side]})
|
|
918
|
+
- Symbol: ${args.symbol}
|
|
919
|
+
- TimeInForce: ${args.timeInForce} (${timeInForceNames[args.timeInForce]})
|
|
920
|
+
|
|
921
|
+
To execute this order, call the executeOrder tool with these exact same parameters.`
|
|
922
|
+
}
|
|
923
|
+
]
|
|
924
|
+
};
|
|
925
|
+
} catch (error) {
|
|
926
|
+
return {
|
|
927
|
+
contents: [
|
|
928
|
+
{
|
|
929
|
+
type: "text",
|
|
930
|
+
text: `Error: ${error instanceof Error ? error.message : "Failed to verify order parameters"}`
|
|
931
|
+
}
|
|
932
|
+
],
|
|
933
|
+
isError: true
|
|
934
|
+
};
|
|
935
|
+
}
|
|
936
|
+
}
|
|
937
|
+
);
|
|
938
|
+
this.server.setRequestHandler(
|
|
939
|
+
import_zod.z.object({
|
|
940
|
+
method: import_zod.z.literal("executeOrder"),
|
|
941
|
+
params: orderSchema
|
|
942
|
+
}),
|
|
943
|
+
async (request, extra) => {
|
|
944
|
+
try {
|
|
945
|
+
const args = request.params;
|
|
946
|
+
const verifiedOrder = this.verifiedOrders.get(args.clOrdID);
|
|
947
|
+
if (!verifiedOrder) {
|
|
948
|
+
return {
|
|
949
|
+
contents: [
|
|
950
|
+
{
|
|
951
|
+
type: "text",
|
|
952
|
+
text: `Error: Order ${args.clOrdID} has not been verified. Please call verifyOrder first.`
|
|
953
|
+
}
|
|
954
|
+
],
|
|
955
|
+
isError: true
|
|
956
|
+
};
|
|
957
|
+
}
|
|
958
|
+
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) {
|
|
959
|
+
return {
|
|
960
|
+
contents: [
|
|
961
|
+
{
|
|
962
|
+
type: "text",
|
|
963
|
+
text: "Error: Order parameters do not match the verified order. Please use the exact same parameters that were verified."
|
|
964
|
+
}
|
|
965
|
+
],
|
|
966
|
+
isError: true
|
|
967
|
+
};
|
|
968
|
+
}
|
|
969
|
+
const response = new Promise((resolve) => {
|
|
970
|
+
this.pendingRequests.set(args.clOrdID, resolve);
|
|
971
|
+
});
|
|
972
|
+
const order = this.parser?.createMessage(
|
|
973
|
+
new import_fixparser.Field(import_fixparser.Fields.MsgType, import_fixparser.Messages.NewOrderSingle),
|
|
974
|
+
new import_fixparser.Field(import_fixparser.Fields.MsgSeqNum, this.parser?.getNextTargetMsgSeqNum()),
|
|
975
|
+
new import_fixparser.Field(import_fixparser.Fields.SenderCompID, this.parser?.sender),
|
|
976
|
+
new import_fixparser.Field(import_fixparser.Fields.TargetCompID, this.parser?.target),
|
|
977
|
+
new import_fixparser.Field(import_fixparser.Fields.SendingTime, this.parser?.getTimestamp()),
|
|
978
|
+
new import_fixparser.Field(import_fixparser.Fields.ClOrdID, args.clOrdID),
|
|
979
|
+
new import_fixparser.Field(import_fixparser.Fields.Side, args.side),
|
|
980
|
+
new import_fixparser.Field(import_fixparser.Fields.Symbol, args.symbol),
|
|
981
|
+
new import_fixparser.Field(import_fixparser.Fields.OrderQty, Number.parseFloat(args.quantity)),
|
|
982
|
+
new import_fixparser.Field(import_fixparser.Fields.Price, Number.parseFloat(args.price)),
|
|
983
|
+
new import_fixparser.Field(import_fixparser.Fields.OrdType, args.ordType),
|
|
984
|
+
new import_fixparser.Field(import_fixparser.Fields.HandlInst, args.handlInst),
|
|
985
|
+
new import_fixparser.Field(import_fixparser.Fields.TimeInForce, args.timeInForce),
|
|
986
|
+
new import_fixparser.Field(import_fixparser.Fields.TransactTime, this.parser?.getTimestamp())
|
|
987
|
+
);
|
|
988
|
+
if (!this.parser?.connected) {
|
|
989
|
+
return {
|
|
990
|
+
contents: [
|
|
991
|
+
{
|
|
992
|
+
type: "text",
|
|
993
|
+
text: "Error: Not connected. Ignoring message."
|
|
994
|
+
}
|
|
995
|
+
],
|
|
996
|
+
isError: true
|
|
997
|
+
};
|
|
998
|
+
}
|
|
999
|
+
this.parser?.send(order);
|
|
1000
|
+
const fixData = await response;
|
|
1001
|
+
this.verifiedOrders.delete(args.clOrdID);
|
|
1002
|
+
return {
|
|
1003
|
+
contents: [
|
|
1004
|
+
{
|
|
1005
|
+
type: "text",
|
|
1006
|
+
text: fixData.messageType === import_fixparser.Messages.Reject ? `Reject message for order ${args.clOrdID}: ${JSON.stringify(fixData.toFIXJSON())}` : `Execution Report for order ${args.clOrdID}: ${JSON.stringify(fixData.toFIXJSON())}`
|
|
1007
|
+
}
|
|
1008
|
+
]
|
|
1009
|
+
};
|
|
1010
|
+
} catch (error) {
|
|
1011
|
+
return {
|
|
1012
|
+
contents: [
|
|
1013
|
+
{
|
|
1014
|
+
type: "text",
|
|
1015
|
+
text: `Error: ${error instanceof Error ? error.message : "Failed to execute order"}`
|
|
1016
|
+
}
|
|
1017
|
+
],
|
|
1018
|
+
isError: true
|
|
1019
|
+
};
|
|
1020
|
+
}
|
|
1021
|
+
}
|
|
1022
|
+
);
|
|
1023
|
+
this.server.setRequestHandler(
|
|
1024
|
+
import_zod.z.object({
|
|
1025
|
+
method: import_zod.z.literal("marketDataRequest"),
|
|
1026
|
+
params: marketDataRequestSchema
|
|
1027
|
+
}),
|
|
1028
|
+
async (request, extra) => {
|
|
1029
|
+
try {
|
|
1030
|
+
const args = request.params;
|
|
1031
|
+
const response = new Promise((resolve) => {
|
|
1032
|
+
this.pendingRequests.set(args.mdReqID, resolve);
|
|
1033
|
+
});
|
|
1034
|
+
const messageFields = [
|
|
1035
|
+
new import_fixparser.Field(import_fixparser.Fields.MsgType, import_fixparser.Messages.MarketDataRequest),
|
|
1036
|
+
new import_fixparser.Field(import_fixparser.Fields.SenderCompID, this.parser?.sender),
|
|
1037
|
+
new import_fixparser.Field(import_fixparser.Fields.MsgSeqNum, this.parser?.getNextTargetMsgSeqNum()),
|
|
1038
|
+
new import_fixparser.Field(import_fixparser.Fields.TargetCompID, this.parser?.target),
|
|
1039
|
+
new import_fixparser.Field(import_fixparser.Fields.SendingTime, this.parser?.getTimestamp()),
|
|
1040
|
+
new import_fixparser.Field(import_fixparser.Fields.MDReqID, args.mdReqID),
|
|
1041
|
+
new import_fixparser.Field(import_fixparser.Fields.SubscriptionRequestType, args.subscriptionRequestType),
|
|
1042
|
+
new import_fixparser.Field(import_fixparser.Fields.MarketDepth, 0),
|
|
1043
|
+
new import_fixparser.Field(import_fixparser.Fields.MDUpdateType, args.mdUpdateType)
|
|
1044
|
+
];
|
|
1045
|
+
messageFields.push(new import_fixparser.Field(import_fixparser.Fields.NoRelatedSym, args.symbols.length));
|
|
1046
|
+
args.symbols.forEach((symbol) => {
|
|
1047
|
+
messageFields.push(new import_fixparser.Field(import_fixparser.Fields.Symbol, symbol));
|
|
1048
|
+
});
|
|
1049
|
+
messageFields.push(new import_fixparser.Field(import_fixparser.Fields.NoMDEntryTypes, args.mdEntryTypes.length));
|
|
1050
|
+
args.mdEntryTypes.forEach((entryType) => {
|
|
1051
|
+
messageFields.push(new import_fixparser.Field(import_fixparser.Fields.MDEntryType, entryType));
|
|
1052
|
+
});
|
|
1053
|
+
const mdr = this.parser?.createMessage(...messageFields);
|
|
1054
|
+
if (!this.parser?.connected) {
|
|
1055
|
+
return {
|
|
1056
|
+
contents: [
|
|
1057
|
+
{
|
|
1058
|
+
type: "text",
|
|
1059
|
+
text: "Error: Not connected. Ignoring message."
|
|
1060
|
+
}
|
|
1061
|
+
],
|
|
1062
|
+
isError: true
|
|
1063
|
+
};
|
|
1064
|
+
}
|
|
1065
|
+
this.parser?.send(mdr);
|
|
1066
|
+
const fixData = await response;
|
|
1067
|
+
return {
|
|
1068
|
+
contents: [
|
|
1069
|
+
{
|
|
1070
|
+
type: "text",
|
|
1071
|
+
text: `Market data for ${args.symbols.join(", ")}: ${JSON.stringify(fixData.toFIXJSON())}`
|
|
1072
|
+
}
|
|
1073
|
+
]
|
|
1074
|
+
};
|
|
1075
|
+
} catch (error) {
|
|
1076
|
+
return {
|
|
1077
|
+
contents: [
|
|
1078
|
+
{
|
|
1079
|
+
type: "text",
|
|
1080
|
+
text: `Error: ${error instanceof Error ? error.message : "Failed to request market data"}`
|
|
1081
|
+
}
|
|
1082
|
+
],
|
|
1083
|
+
isError: true
|
|
1084
|
+
};
|
|
1085
|
+
}
|
|
1086
|
+
}
|
|
1087
|
+
);
|
|
1020
1088
|
process.on("SIGINT", async () => {
|
|
1021
1089
|
await this.server.close();
|
|
1022
1090
|
process.exit(0);
|