fixparser-plugin-mcp 9.1.7-3f807208 → 9.1.7-400318ef
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 +402 -660
- package/build/cjs/MCPLocal.js.map +2 -2
- package/build/esm/MCPLocal.mjs +402 -660
- package/build/esm/MCPLocal.mjs.map +2 -2
- package/build-examples/cjs/example_mcp_local.js +21 -21
- package/build-examples/cjs/example_mcp_local.js.map +3 -3
- package/build-examples/esm/example_mcp_local.mjs +20 -20
- package/build-examples/esm/example_mcp_local.mjs.map +3 -3
- package/package.json +2 -2
package/build/esm/MCPLocal.mjs
CHANGED
|
@@ -152,9 +152,16 @@ var MCPLocal = class {
|
|
|
152
152
|
},
|
|
153
153
|
required: ["mdUpdateType", "symbols", "mdReqID", "subscriptionRequestType", "mdEntryTypes"]
|
|
154
154
|
}
|
|
155
|
+
}
|
|
156
|
+
},
|
|
157
|
+
resources: {
|
|
158
|
+
greeting: {
|
|
159
|
+
description: "A simple greeting resource",
|
|
160
|
+
uri: "greeting-resource"
|
|
155
161
|
},
|
|
156
|
-
|
|
162
|
+
stockGraph: {
|
|
157
163
|
description: "Generates a price chart for a given symbol",
|
|
164
|
+
uri: "stockGraph",
|
|
158
165
|
parameters: {
|
|
159
166
|
type: "object",
|
|
160
167
|
properties: {
|
|
@@ -163,8 +170,9 @@ var MCPLocal = class {
|
|
|
163
170
|
required: ["symbol"]
|
|
164
171
|
}
|
|
165
172
|
},
|
|
166
|
-
|
|
173
|
+
stockPriceHistory: {
|
|
167
174
|
description: "Returns price history for a given symbol",
|
|
175
|
+
uri: "stockPriceHistory",
|
|
168
176
|
parameters: {
|
|
169
177
|
type: "object",
|
|
170
178
|
properties: {
|
|
@@ -173,20 +181,6 @@ var MCPLocal = class {
|
|
|
173
181
|
required: ["symbol"]
|
|
174
182
|
}
|
|
175
183
|
}
|
|
176
|
-
},
|
|
177
|
-
resources: {
|
|
178
|
-
greeting: {
|
|
179
|
-
description: "A simple greeting resource",
|
|
180
|
-
uri: "greeting-resource"
|
|
181
|
-
},
|
|
182
|
-
stockGraph: {
|
|
183
|
-
description: "Generates a price chart for a given symbol",
|
|
184
|
-
uri: "stockGraph/{symbol}"
|
|
185
|
-
},
|
|
186
|
-
stockPriceHistory: {
|
|
187
|
-
description: "Returns price history for a given symbol",
|
|
188
|
-
uri: "stockPriceHistory/{symbol}"
|
|
189
|
-
}
|
|
190
184
|
}
|
|
191
185
|
}
|
|
192
186
|
}
|
|
@@ -236,14 +230,6 @@ var MCPLocal = class {
|
|
|
236
230
|
level: "info",
|
|
237
231
|
message: `MCP Server added ${symbol}: ${priceNum}`
|
|
238
232
|
});
|
|
239
|
-
this.server.notification({
|
|
240
|
-
method: "priceUpdate",
|
|
241
|
-
params: {
|
|
242
|
-
symbol: symbolStr,
|
|
243
|
-
price: priceNum,
|
|
244
|
-
timestamp: Number(timestamp)
|
|
245
|
-
}
|
|
246
|
-
});
|
|
247
233
|
}
|
|
248
234
|
}
|
|
249
235
|
if (msgType === Messages.MarketDataSnapshotFullRefresh) {
|
|
@@ -278,385 +264,158 @@ var MCPLocal = class {
|
|
|
278
264
|
if (!this.server) {
|
|
279
265
|
return;
|
|
280
266
|
}
|
|
281
|
-
this.server.setRequestHandler(
|
|
282
|
-
|
|
283
|
-
|
|
267
|
+
this.server.setRequestHandler(z.object({ method: z.literal("parse") }), async (request, extra) => {
|
|
268
|
+
try {
|
|
269
|
+
const args = request.params;
|
|
270
|
+
const parsedMessage = this.parser?.parse(args.fixString);
|
|
271
|
+
if (!parsedMessage || parsedMessage.length === 0) {
|
|
272
|
+
return {
|
|
273
|
+
content: [{ type: "text", text: "Error: Failed to parse FIX string" }],
|
|
274
|
+
isError: true
|
|
275
|
+
};
|
|
276
|
+
}
|
|
284
277
|
return {
|
|
285
|
-
|
|
278
|
+
content: [
|
|
286
279
|
{
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
280
|
+
type: "text",
|
|
281
|
+
text: `${parsedMessage[0].description}
|
|
282
|
+
${parsedMessage[0].messageTypeDescription}`
|
|
290
283
|
}
|
|
291
284
|
]
|
|
292
285
|
};
|
|
293
|
-
}
|
|
294
|
-
);
|
|
295
|
-
this.server.setRequestHandler(
|
|
296
|
-
z.object({ method: z.literal("resources/templates/list") }),
|
|
297
|
-
async (request, extra) => {
|
|
286
|
+
} catch (error) {
|
|
298
287
|
return {
|
|
299
|
-
|
|
300
|
-
{
|
|
301
|
-
name: "stockGraph",
|
|
302
|
-
description: "Generates a price chart for a given symbol",
|
|
303
|
-
uriTemplate: "stockGraph/{symbol}",
|
|
304
|
-
parameters: {
|
|
305
|
-
type: "object",
|
|
306
|
-
properties: {
|
|
307
|
-
symbol: { type: "string" }
|
|
308
|
-
},
|
|
309
|
-
required: ["symbol"]
|
|
310
|
-
}
|
|
311
|
-
},
|
|
288
|
+
content: [
|
|
312
289
|
{
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
uriTemplate: "stockPriceHistory/{symbol}",
|
|
316
|
-
parameters: {
|
|
317
|
-
type: "object",
|
|
318
|
-
properties: {
|
|
319
|
-
symbol: { type: "string" }
|
|
320
|
-
},
|
|
321
|
-
required: ["symbol"]
|
|
322
|
-
}
|
|
290
|
+
type: "text",
|
|
291
|
+
text: `Error: ${error instanceof Error ? error.message : "Failed to parse FIX string"}`
|
|
323
292
|
}
|
|
324
|
-
]
|
|
293
|
+
],
|
|
294
|
+
isError: true
|
|
325
295
|
};
|
|
326
296
|
}
|
|
327
|
-
);
|
|
297
|
+
});
|
|
328
298
|
this.server.setRequestHandler(
|
|
329
|
-
z.object({ method: z.literal("
|
|
299
|
+
z.object({ method: z.literal("parseToJSON") }),
|
|
330
300
|
async (request, extra) => {
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
name: "parseToJSON",
|
|
346
|
-
description: "Parses a FIX message into JSON",
|
|
347
|
-
inputSchema: {
|
|
348
|
-
type: "object",
|
|
349
|
-
properties: {
|
|
350
|
-
fixString: { type: "string" }
|
|
351
|
-
},
|
|
352
|
-
required: ["fixString"]
|
|
353
|
-
}
|
|
354
|
-
},
|
|
355
|
-
{
|
|
356
|
-
name: "verifyOrder",
|
|
357
|
-
description: "Verifies order parameters before execution",
|
|
358
|
-
inputSchema: {
|
|
359
|
-
type: "object",
|
|
360
|
-
properties: {
|
|
361
|
-
clOrdID: { type: "string" },
|
|
362
|
-
handlInst: { type: "string", enum: ["1", "2", "3"] },
|
|
363
|
-
quantity: { type: "string" },
|
|
364
|
-
price: { type: "string" },
|
|
365
|
-
ordType: {
|
|
366
|
-
type: "string",
|
|
367
|
-
enum: [
|
|
368
|
-
"1",
|
|
369
|
-
"2",
|
|
370
|
-
"3",
|
|
371
|
-
"4",
|
|
372
|
-
"5",
|
|
373
|
-
"6",
|
|
374
|
-
"7",
|
|
375
|
-
"8",
|
|
376
|
-
"9",
|
|
377
|
-
"A",
|
|
378
|
-
"B",
|
|
379
|
-
"C",
|
|
380
|
-
"D",
|
|
381
|
-
"E",
|
|
382
|
-
"F",
|
|
383
|
-
"G",
|
|
384
|
-
"H",
|
|
385
|
-
"I",
|
|
386
|
-
"J",
|
|
387
|
-
"K",
|
|
388
|
-
"L",
|
|
389
|
-
"M",
|
|
390
|
-
"P",
|
|
391
|
-
"Q",
|
|
392
|
-
"R",
|
|
393
|
-
"S"
|
|
394
|
-
]
|
|
395
|
-
},
|
|
396
|
-
side: {
|
|
397
|
-
type: "string",
|
|
398
|
-
enum: [
|
|
399
|
-
"1",
|
|
400
|
-
"2",
|
|
401
|
-
"3",
|
|
402
|
-
"4",
|
|
403
|
-
"5",
|
|
404
|
-
"6",
|
|
405
|
-
"7",
|
|
406
|
-
"8",
|
|
407
|
-
"9",
|
|
408
|
-
"A",
|
|
409
|
-
"B",
|
|
410
|
-
"C",
|
|
411
|
-
"D",
|
|
412
|
-
"E",
|
|
413
|
-
"F",
|
|
414
|
-
"G",
|
|
415
|
-
"H"
|
|
416
|
-
]
|
|
417
|
-
},
|
|
418
|
-
symbol: { type: "string" },
|
|
419
|
-
timeInForce: {
|
|
420
|
-
type: "string",
|
|
421
|
-
enum: ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C"]
|
|
422
|
-
}
|
|
423
|
-
},
|
|
424
|
-
required: [
|
|
425
|
-
"clOrdID",
|
|
426
|
-
"handlInst",
|
|
427
|
-
"quantity",
|
|
428
|
-
"price",
|
|
429
|
-
"ordType",
|
|
430
|
-
"side",
|
|
431
|
-
"symbol",
|
|
432
|
-
"timeInForce"
|
|
433
|
-
]
|
|
434
|
-
}
|
|
435
|
-
},
|
|
436
|
-
{
|
|
437
|
-
name: "executeOrder",
|
|
438
|
-
description: "Executes a verified order",
|
|
439
|
-
inputSchema: {
|
|
440
|
-
type: "object",
|
|
441
|
-
properties: {
|
|
442
|
-
clOrdID: { type: "string" },
|
|
443
|
-
handlInst: { type: "string", enum: ["1", "2", "3"] },
|
|
444
|
-
quantity: { type: "string" },
|
|
445
|
-
price: { type: "string" },
|
|
446
|
-
ordType: { type: "string" },
|
|
447
|
-
side: { type: "string" },
|
|
448
|
-
symbol: { type: "string" },
|
|
449
|
-
timeInForce: { type: "string" }
|
|
450
|
-
},
|
|
451
|
-
required: [
|
|
452
|
-
"clOrdID",
|
|
453
|
-
"handlInst",
|
|
454
|
-
"quantity",
|
|
455
|
-
"price",
|
|
456
|
-
"ordType",
|
|
457
|
-
"side",
|
|
458
|
-
"symbol",
|
|
459
|
-
"timeInForce"
|
|
460
|
-
]
|
|
301
|
+
try {
|
|
302
|
+
const args = request.params;
|
|
303
|
+
const parsedMessage = this.parser?.parse(args.fixString);
|
|
304
|
+
if (!parsedMessage || parsedMessage.length === 0) {
|
|
305
|
+
return {
|
|
306
|
+
content: [{ type: "text", text: "Error: Failed to parse FIX string" }],
|
|
307
|
+
isError: true
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
return {
|
|
311
|
+
content: [
|
|
312
|
+
{
|
|
313
|
+
type: "text",
|
|
314
|
+
text: `${parsedMessage[0].toFIXJSON()}`
|
|
461
315
|
}
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
symbols: { type: "array", items: { type: "string" } },
|
|
471
|
-
mdReqID: { type: "string" },
|
|
472
|
-
subscriptionRequestType: { type: "string", enum: ["0", "1", "2"] },
|
|
473
|
-
mdEntryTypes: { type: "array", items: { type: "string" } }
|
|
474
|
-
},
|
|
475
|
-
required: [
|
|
476
|
-
"mdUpdateType",
|
|
477
|
-
"symbols",
|
|
478
|
-
"mdReqID",
|
|
479
|
-
"subscriptionRequestType",
|
|
480
|
-
"mdEntryTypes"
|
|
481
|
-
]
|
|
316
|
+
]
|
|
317
|
+
};
|
|
318
|
+
} catch (error) {
|
|
319
|
+
return {
|
|
320
|
+
content: [
|
|
321
|
+
{
|
|
322
|
+
type: "text",
|
|
323
|
+
text: `Error: ${error instanceof Error ? error.message : "Failed to parse FIX string"}`
|
|
482
324
|
}
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
325
|
+
],
|
|
326
|
+
isError: true
|
|
327
|
+
};
|
|
328
|
+
}
|
|
486
329
|
}
|
|
487
330
|
);
|
|
488
331
|
this.server.setRequestHandler(
|
|
489
|
-
z.object({
|
|
490
|
-
method: z.literal("tools/call"),
|
|
491
|
-
params: z.object({
|
|
492
|
-
name: z.string(),
|
|
493
|
-
arguments: z.any(),
|
|
494
|
-
_meta: z.object({
|
|
495
|
-
progressToken: z.number()
|
|
496
|
-
}).optional()
|
|
497
|
-
})
|
|
498
|
-
}),
|
|
332
|
+
z.object({ method: z.literal("verifyOrder") }),
|
|
499
333
|
async (request, extra) => {
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
timeInForce: args.timeInForce
|
|
586
|
-
});
|
|
587
|
-
const ordTypeNames = {
|
|
588
|
-
"1": "Market",
|
|
589
|
-
"2": "Limit",
|
|
590
|
-
"3": "Stop",
|
|
591
|
-
"4": "StopLimit",
|
|
592
|
-
"5": "MarketOnClose",
|
|
593
|
-
"6": "WithOrWithout",
|
|
594
|
-
"7": "LimitOrBetter",
|
|
595
|
-
"8": "LimitWithOrWithout",
|
|
596
|
-
"9": "OnBasis",
|
|
597
|
-
A: "OnClose",
|
|
598
|
-
B: "LimitOnClose",
|
|
599
|
-
C: "ForexMarket",
|
|
600
|
-
D: "PreviouslyQuoted",
|
|
601
|
-
E: "PreviouslyIndicated",
|
|
602
|
-
F: "ForexLimit",
|
|
603
|
-
G: "ForexSwap",
|
|
604
|
-
H: "ForexPreviouslyQuoted",
|
|
605
|
-
I: "Funari",
|
|
606
|
-
J: "MarketIfTouched",
|
|
607
|
-
K: "MarketWithLeftOverAsLimit",
|
|
608
|
-
L: "PreviousFundValuationPoint",
|
|
609
|
-
M: "NextFundValuationPoint",
|
|
610
|
-
P: "Pegged",
|
|
611
|
-
Q: "CounterOrderSelection",
|
|
612
|
-
R: "StopOnBidOrOffer",
|
|
613
|
-
S: "StopLimitOnBidOrOffer"
|
|
614
|
-
};
|
|
615
|
-
const sideNames = {
|
|
616
|
-
"1": "Buy",
|
|
617
|
-
"2": "Sell",
|
|
618
|
-
"3": "BuyMinus",
|
|
619
|
-
"4": "SellPlus",
|
|
620
|
-
"5": "SellShort",
|
|
621
|
-
"6": "SellShortExempt",
|
|
622
|
-
"7": "Undisclosed",
|
|
623
|
-
"8": "Cross",
|
|
624
|
-
"9": "CrossShort",
|
|
625
|
-
A: "CrossShortExempt",
|
|
626
|
-
B: "AsDefined",
|
|
627
|
-
C: "Opposite",
|
|
628
|
-
D: "Subscribe",
|
|
629
|
-
E: "Redeem",
|
|
630
|
-
F: "Lend",
|
|
631
|
-
G: "Borrow",
|
|
632
|
-
H: "SellUndisclosed"
|
|
633
|
-
};
|
|
634
|
-
const timeInForceNames = {
|
|
635
|
-
"0": "Day",
|
|
636
|
-
"1": "GoodTillCancel",
|
|
637
|
-
"2": "AtTheOpening",
|
|
638
|
-
"3": "ImmediateOrCancel",
|
|
639
|
-
"4": "FillOrKill",
|
|
640
|
-
"5": "GoodTillCrossing",
|
|
641
|
-
"6": "GoodTillDate",
|
|
642
|
-
"7": "AtTheClose",
|
|
643
|
-
"8": "GoodThroughCrossing",
|
|
644
|
-
"9": "AtCrossing",
|
|
645
|
-
A: "GoodForTime",
|
|
646
|
-
B: "GoodForAuction",
|
|
647
|
-
C: "GoodForMonth"
|
|
648
|
-
};
|
|
649
|
-
const handlInstNames = {
|
|
650
|
-
"1": "AutomatedExecutionNoIntervention",
|
|
651
|
-
"2": "AutomatedExecutionInterventionOK",
|
|
652
|
-
"3": "ManualOrder"
|
|
653
|
-
};
|
|
654
|
-
return {
|
|
655
|
-
contents: [
|
|
656
|
-
{
|
|
657
|
-
type: "text",
|
|
658
|
-
text: `VERIFICATION: All parameters valid. Ready to proceed with order execution.
|
|
659
|
-
|
|
334
|
+
try {
|
|
335
|
+
const args = request.params;
|
|
336
|
+
this.verifiedOrders.set(args.clOrdID, {
|
|
337
|
+
clOrdID: args.clOrdID,
|
|
338
|
+
handlInst: args.handlInst,
|
|
339
|
+
quantity: Number.parseFloat(args.quantity),
|
|
340
|
+
price: Number.parseFloat(args.price),
|
|
341
|
+
ordType: args.ordType,
|
|
342
|
+
side: args.side,
|
|
343
|
+
symbol: args.symbol,
|
|
344
|
+
timeInForce: args.timeInForce
|
|
345
|
+
});
|
|
346
|
+
const ordTypeNames = {
|
|
347
|
+
"1": "Market",
|
|
348
|
+
"2": "Limit",
|
|
349
|
+
"3": "Stop",
|
|
350
|
+
"4": "StopLimit",
|
|
351
|
+
"5": "MarketOnClose",
|
|
352
|
+
"6": "WithOrWithout",
|
|
353
|
+
"7": "LimitOrBetter",
|
|
354
|
+
"8": "LimitWithOrWithout",
|
|
355
|
+
"9": "OnBasis",
|
|
356
|
+
A: "OnClose",
|
|
357
|
+
B: "LimitOnClose",
|
|
358
|
+
C: "ForexMarket",
|
|
359
|
+
D: "PreviouslyQuoted",
|
|
360
|
+
E: "PreviouslyIndicated",
|
|
361
|
+
F: "ForexLimit",
|
|
362
|
+
G: "ForexSwap",
|
|
363
|
+
H: "ForexPreviouslyQuoted",
|
|
364
|
+
I: "Funari",
|
|
365
|
+
J: "MarketIfTouched",
|
|
366
|
+
K: "MarketWithLeftOverAsLimit",
|
|
367
|
+
L: "PreviousFundValuationPoint",
|
|
368
|
+
M: "NextFundValuationPoint",
|
|
369
|
+
P: "Pegged",
|
|
370
|
+
Q: "CounterOrderSelection",
|
|
371
|
+
R: "StopOnBidOrOffer",
|
|
372
|
+
S: "StopLimitOnBidOrOffer"
|
|
373
|
+
};
|
|
374
|
+
const sideNames = {
|
|
375
|
+
"1": "Buy",
|
|
376
|
+
"2": "Sell",
|
|
377
|
+
"3": "BuyMinus",
|
|
378
|
+
"4": "SellPlus",
|
|
379
|
+
"5": "SellShort",
|
|
380
|
+
"6": "SellShortExempt",
|
|
381
|
+
"7": "Undisclosed",
|
|
382
|
+
"8": "Cross",
|
|
383
|
+
"9": "CrossShort",
|
|
384
|
+
A: "CrossShortExempt",
|
|
385
|
+
B: "AsDefined",
|
|
386
|
+
C: "Opposite",
|
|
387
|
+
D: "Subscribe",
|
|
388
|
+
E: "Redeem",
|
|
389
|
+
F: "Lend",
|
|
390
|
+
G: "Borrow",
|
|
391
|
+
H: "SellUndisclosed"
|
|
392
|
+
};
|
|
393
|
+
const timeInForceNames = {
|
|
394
|
+
"0": "Day",
|
|
395
|
+
"1": "GoodTillCancel",
|
|
396
|
+
"2": "AtTheOpening",
|
|
397
|
+
"3": "ImmediateOrCancel",
|
|
398
|
+
"4": "FillOrKill",
|
|
399
|
+
"5": "GoodTillCrossing",
|
|
400
|
+
"6": "GoodTillDate",
|
|
401
|
+
"7": "AtTheClose",
|
|
402
|
+
"8": "GoodThroughCrossing",
|
|
403
|
+
"9": "AtCrossing",
|
|
404
|
+
A: "GoodForTime",
|
|
405
|
+
B: "GoodForAuction",
|
|
406
|
+
C: "GoodForMonth"
|
|
407
|
+
};
|
|
408
|
+
const handlInstNames = {
|
|
409
|
+
"1": "AutomatedExecutionNoIntervention",
|
|
410
|
+
"2": "AutomatedExecutionInterventionOK",
|
|
411
|
+
"3": "ManualOrder"
|
|
412
|
+
};
|
|
413
|
+
return {
|
|
414
|
+
content: [
|
|
415
|
+
{
|
|
416
|
+
type: "text",
|
|
417
|
+
text: `VERIFICATION: All parameters valid. Ready to proceed with order execution.
|
|
418
|
+
|
|
660
419
|
Parameters verified:
|
|
661
420
|
- ClOrdID: ${args.clOrdID}
|
|
662
421
|
- HandlInst: ${args.handlInst} (${handlInstNames[args.handlInst]})
|
|
@@ -667,193 +426,217 @@ Parameters verified:
|
|
|
667
426
|
- Symbol: ${args.symbol}
|
|
668
427
|
- TimeInForce: ${args.timeInForce} (${timeInForceNames[args.timeInForce]})
|
|
669
428
|
|
|
670
|
-
To execute this order, call the executeOrder tool with these exact same parameters
|
|
671
|
-
uri: "verifyOrder"
|
|
672
|
-
}
|
|
673
|
-
]
|
|
674
|
-
};
|
|
675
|
-
} catch (error) {
|
|
676
|
-
return {
|
|
677
|
-
contents: [
|
|
678
|
-
{
|
|
679
|
-
type: "text",
|
|
680
|
-
text: `Error: ${error instanceof Error ? error.message : "Failed to verify order parameters"}`,
|
|
681
|
-
uri: "verifyOrder"
|
|
682
|
-
}
|
|
683
|
-
],
|
|
684
|
-
isError: true
|
|
685
|
-
};
|
|
686
|
-
}
|
|
687
|
-
case "executeOrder":
|
|
688
|
-
try {
|
|
689
|
-
const verifiedOrder = this.verifiedOrders.get(args.clOrdID);
|
|
690
|
-
if (!verifiedOrder) {
|
|
691
|
-
return {
|
|
692
|
-
contents: [
|
|
693
|
-
{
|
|
694
|
-
type: "text",
|
|
695
|
-
text: `Error: Order ${args.clOrdID} has not been verified. Please call verifyOrder first.`,
|
|
696
|
-
uri: "executeOrder"
|
|
697
|
-
}
|
|
698
|
-
],
|
|
699
|
-
isError: true
|
|
700
|
-
};
|
|
429
|
+
To execute this order, call the executeOrder tool with these exact same parameters.`
|
|
701
430
|
}
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
],
|
|
711
|
-
isError: true
|
|
712
|
-
};
|
|
431
|
+
]
|
|
432
|
+
};
|
|
433
|
+
} catch (error) {
|
|
434
|
+
return {
|
|
435
|
+
content: [
|
|
436
|
+
{
|
|
437
|
+
type: "text",
|
|
438
|
+
text: `Error: ${error instanceof Error ? error.message : "Failed to verify order parameters"}`
|
|
713
439
|
}
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
}
|
|
440
|
+
],
|
|
441
|
+
isError: true
|
|
442
|
+
};
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
);
|
|
446
|
+
this.server.setRequestHandler(
|
|
447
|
+
z.object({ method: z.literal("executeOrder") }),
|
|
448
|
+
async (request, extra) => {
|
|
449
|
+
try {
|
|
450
|
+
const args = request.params;
|
|
451
|
+
const verifiedOrder = this.verifiedOrders.get(args.clOrdID);
|
|
452
|
+
if (!verifiedOrder) {
|
|
453
|
+
return {
|
|
454
|
+
content: [
|
|
455
|
+
{
|
|
456
|
+
type: "text",
|
|
457
|
+
text: `Error: Order ${args.clOrdID} has not been verified. Please call verifyOrder first.`
|
|
458
|
+
}
|
|
459
|
+
],
|
|
460
|
+
isError: true
|
|
461
|
+
};
|
|
462
|
+
}
|
|
463
|
+
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) {
|
|
464
|
+
return {
|
|
465
|
+
content: [
|
|
466
|
+
{
|
|
467
|
+
type: "text",
|
|
468
|
+
text: "Error: Order parameters do not match the verified order. Please use the exact same parameters that were verified."
|
|
469
|
+
}
|
|
470
|
+
],
|
|
471
|
+
isError: true
|
|
472
|
+
};
|
|
473
|
+
}
|
|
474
|
+
const response = new Promise((resolve) => {
|
|
475
|
+
this.pendingRequests.set(args.clOrdID, resolve);
|
|
476
|
+
});
|
|
477
|
+
const order = this.parser?.createMessage(
|
|
478
|
+
new Field(Fields.MsgType, Messages.NewOrderSingle),
|
|
479
|
+
new Field(Fields.MsgSeqNum, this.parser?.getNextTargetMsgSeqNum()),
|
|
480
|
+
new Field(Fields.SenderCompID, this.parser?.sender),
|
|
481
|
+
new Field(Fields.TargetCompID, this.parser?.target),
|
|
482
|
+
new Field(Fields.SendingTime, this.parser?.getTimestamp()),
|
|
483
|
+
new Field(Fields.ClOrdID, args.clOrdID),
|
|
484
|
+
new Field(Fields.Side, args.side),
|
|
485
|
+
new Field(Fields.Symbol, args.symbol),
|
|
486
|
+
new Field(Fields.OrderQty, Number.parseFloat(args.quantity)),
|
|
487
|
+
new Field(Fields.Price, Number.parseFloat(args.price)),
|
|
488
|
+
new Field(Fields.OrdType, args.ordType),
|
|
489
|
+
new Field(Fields.HandlInst, args.handlInst),
|
|
490
|
+
new Field(Fields.TimeInForce, args.timeInForce),
|
|
491
|
+
new Field(Fields.TransactTime, this.parser?.getTimestamp())
|
|
492
|
+
);
|
|
493
|
+
if (!this.parser?.connected) {
|
|
494
|
+
return {
|
|
495
|
+
content: [
|
|
496
|
+
{
|
|
497
|
+
type: "text",
|
|
498
|
+
text: "Error: Not connected. Ignoring message."
|
|
499
|
+
}
|
|
500
|
+
],
|
|
501
|
+
isError: true
|
|
502
|
+
};
|
|
503
|
+
}
|
|
504
|
+
this.parser?.send(order);
|
|
505
|
+
const fixData = await response;
|
|
506
|
+
this.verifiedOrders.delete(args.clOrdID);
|
|
507
|
+
return {
|
|
508
|
+
content: [
|
|
509
|
+
{
|
|
510
|
+
type: "text",
|
|
511
|
+
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())}`
|
|
744
512
|
}
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
uri: "executeOrder"
|
|
754
|
-
}
|
|
755
|
-
]
|
|
756
|
-
};
|
|
757
|
-
} catch (error) {
|
|
758
|
-
return {
|
|
759
|
-
contents: [
|
|
760
|
-
{
|
|
761
|
-
type: "text",
|
|
762
|
-
text: `Error: ${error instanceof Error ? error.message : "Failed to execute order"}`,
|
|
763
|
-
uri: "executeOrder"
|
|
764
|
-
}
|
|
765
|
-
],
|
|
766
|
-
isError: true
|
|
767
|
-
};
|
|
768
|
-
}
|
|
769
|
-
case "marketDataRequest":
|
|
770
|
-
try {
|
|
771
|
-
const response = new Promise((resolve) => {
|
|
772
|
-
this.pendingRequests.set(args.mdReqID, resolve);
|
|
773
|
-
});
|
|
774
|
-
const messageFields = [
|
|
775
|
-
new Field(Fields.MsgType, Messages.MarketDataRequest),
|
|
776
|
-
new Field(Fields.SenderCompID, this.parser?.sender),
|
|
777
|
-
new Field(Fields.MsgSeqNum, this.parser?.getNextTargetMsgSeqNum()),
|
|
778
|
-
new Field(Fields.TargetCompID, this.parser?.target),
|
|
779
|
-
new Field(Fields.SendingTime, this.parser?.getTimestamp()),
|
|
780
|
-
new Field(Fields.MDReqID, args.mdReqID),
|
|
781
|
-
new Field(Fields.SubscriptionRequestType, args.subscriptionRequestType),
|
|
782
|
-
new Field(Fields.MarketDepth, 0),
|
|
783
|
-
new Field(Fields.MDUpdateType, args.mdUpdateType)
|
|
784
|
-
];
|
|
785
|
-
messageFields.push(new Field(Fields.NoRelatedSym, args.symbols.length));
|
|
786
|
-
args.symbols.forEach((symbol) => {
|
|
787
|
-
messageFields.push(new Field(Fields.Symbol, symbol));
|
|
788
|
-
});
|
|
789
|
-
messageFields.push(new Field(Fields.NoMDEntryTypes, args.mdEntryTypes.length));
|
|
790
|
-
args.mdEntryTypes.forEach((entryType) => {
|
|
791
|
-
messageFields.push(new Field(Fields.MDEntryType, entryType));
|
|
792
|
-
});
|
|
793
|
-
const mdr = this.parser?.createMessage(...messageFields);
|
|
794
|
-
if (!this.parser?.connected) {
|
|
795
|
-
return {
|
|
796
|
-
contents: [
|
|
797
|
-
{
|
|
798
|
-
type: "text",
|
|
799
|
-
text: "Error: Not connected. Ignoring message.",
|
|
800
|
-
uri: "marketDataRequest"
|
|
801
|
-
}
|
|
802
|
-
],
|
|
803
|
-
isError: true
|
|
804
|
-
};
|
|
513
|
+
]
|
|
514
|
+
};
|
|
515
|
+
} catch (error) {
|
|
516
|
+
return {
|
|
517
|
+
content: [
|
|
518
|
+
{
|
|
519
|
+
type: "text",
|
|
520
|
+
text: `Error: ${error instanceof Error ? error.message : "Failed to execute order"}`
|
|
805
521
|
}
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
522
|
+
],
|
|
523
|
+
isError: true
|
|
524
|
+
};
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
);
|
|
528
|
+
this.server.setRequestHandler(
|
|
529
|
+
z.object({ method: z.literal("marketDataRequest") }),
|
|
530
|
+
async (request, extra) => {
|
|
531
|
+
try {
|
|
532
|
+
const args = request.params;
|
|
533
|
+
const response = new Promise((resolve) => {
|
|
534
|
+
this.pendingRequests.set(args.mdReqID, resolve);
|
|
535
|
+
});
|
|
536
|
+
const messageFields = [
|
|
537
|
+
new Field(Fields.MsgType, Messages.MarketDataRequest),
|
|
538
|
+
new Field(Fields.SenderCompID, this.parser?.sender),
|
|
539
|
+
new Field(Fields.MsgSeqNum, this.parser?.getNextTargetMsgSeqNum()),
|
|
540
|
+
new Field(Fields.TargetCompID, this.parser?.target),
|
|
541
|
+
new Field(Fields.SendingTime, this.parser?.getTimestamp()),
|
|
542
|
+
new Field(Fields.MDReqID, args.mdReqID),
|
|
543
|
+
new Field(Fields.SubscriptionRequestType, args.subscriptionRequestType),
|
|
544
|
+
new Field(Fields.MarketDepth, 0),
|
|
545
|
+
new Field(Fields.MDUpdateType, args.mdUpdateType)
|
|
546
|
+
];
|
|
547
|
+
messageFields.push(new Field(Fields.NoRelatedSym, args.symbols.length));
|
|
548
|
+
args.symbols.forEach((symbol) => {
|
|
549
|
+
messageFields.push(new Field(Fields.Symbol, symbol));
|
|
550
|
+
});
|
|
551
|
+
messageFields.push(new Field(Fields.NoMDEntryTypes, args.mdEntryTypes.length));
|
|
552
|
+
args.mdEntryTypes.forEach((entryType) => {
|
|
553
|
+
messageFields.push(new Field(Fields.MDEntryType, entryType));
|
|
554
|
+
});
|
|
555
|
+
const mdr = this.parser?.createMessage(...messageFields);
|
|
556
|
+
if (!this.parser?.connected) {
|
|
557
|
+
return {
|
|
558
|
+
content: [
|
|
559
|
+
{
|
|
560
|
+
type: "text",
|
|
561
|
+
text: "Error: Not connected. Ignoring message."
|
|
562
|
+
}
|
|
563
|
+
],
|
|
564
|
+
isError: true
|
|
565
|
+
};
|
|
566
|
+
}
|
|
567
|
+
this.parser?.send(mdr);
|
|
568
|
+
const fixData = await response;
|
|
569
|
+
return {
|
|
570
|
+
content: [
|
|
571
|
+
{
|
|
572
|
+
type: "text",
|
|
573
|
+
text: `Market data for ${args.symbols.join(", ")}: ${JSON.stringify(fixData.toFIXJSON())}`
|
|
574
|
+
}
|
|
575
|
+
]
|
|
576
|
+
};
|
|
577
|
+
} catch (error) {
|
|
578
|
+
return {
|
|
579
|
+
content: [
|
|
580
|
+
{
|
|
581
|
+
type: "text",
|
|
582
|
+
text: `Error: ${error instanceof Error ? error.message : "Failed to request market data"}`
|
|
583
|
+
}
|
|
584
|
+
],
|
|
585
|
+
isError: true
|
|
586
|
+
};
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
);
|
|
590
|
+
this.server.setRequestHandler(
|
|
591
|
+
z.object({ method: z.literal("greeting-resource") }),
|
|
592
|
+
async (request, extra) => {
|
|
593
|
+
this.parser?.logger.log({
|
|
594
|
+
level: "info",
|
|
595
|
+
message: "MCP Server Resource called: greeting-resource"
|
|
596
|
+
});
|
|
597
|
+
return {
|
|
598
|
+
content: [
|
|
599
|
+
{
|
|
600
|
+
type: "text",
|
|
601
|
+
text: "Hello, world!"
|
|
828
602
|
}
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
603
|
+
]
|
|
604
|
+
};
|
|
605
|
+
}
|
|
606
|
+
);
|
|
607
|
+
this.server.setRequestHandler(
|
|
608
|
+
z.object({ method: z.literal("stockGraph") }),
|
|
609
|
+
async (request, extra) => {
|
|
610
|
+
this.parser?.logger.log({
|
|
611
|
+
level: "info",
|
|
612
|
+
message: "MCP Server Resource called: stockGraph"
|
|
613
|
+
});
|
|
614
|
+
const args = request.params;
|
|
615
|
+
const symbol = args.symbol;
|
|
616
|
+
const priceHistory = this.marketDataPrices.get(symbol) || [];
|
|
617
|
+
if (priceHistory.length === 0) {
|
|
618
|
+
return {
|
|
619
|
+
content: [
|
|
620
|
+
{
|
|
621
|
+
type: "text",
|
|
622
|
+
text: `No price data available for ${symbol}`
|
|
843
623
|
}
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
624
|
+
]
|
|
625
|
+
};
|
|
626
|
+
}
|
|
627
|
+
const width = 600;
|
|
628
|
+
const height = 300;
|
|
629
|
+
const padding = 40;
|
|
630
|
+
const xScale = (width - 2 * padding) / (priceHistory.length - 1);
|
|
631
|
+
const yMin = Math.min(...priceHistory.map((d) => d.price));
|
|
632
|
+
const yMax = Math.max(...priceHistory.map((d) => d.price));
|
|
633
|
+
const yScale = (height - 2 * padding) / (yMax - yMin);
|
|
634
|
+
const points = priceHistory.map((d, i) => {
|
|
635
|
+
const x = padding + i * xScale;
|
|
636
|
+
const y = height - padding - (d.price - yMin) * yScale;
|
|
637
|
+
return `${x},${y}`;
|
|
638
|
+
}).join(" L ");
|
|
639
|
+
const svg = `<?xml version="1.0" encoding="UTF-8"?>
|
|
857
640
|
<svg width="${width}" height="${height}" xmlns="http://www.w3.org/2000/svg">
|
|
858
641
|
<!-- Background -->
|
|
859
642
|
<rect width="100%" height="100%" fill="#f8f9fa"/>
|
|
@@ -861,9 +644,9 @@ To execute this order, call the executeOrder tool with these exact same paramete
|
|
|
861
644
|
<!-- Grid lines -->
|
|
862
645
|
<g stroke="#e9ecef" stroke-width="1">
|
|
863
646
|
${Array.from({ length: 5 }, (_, i) => {
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
647
|
+
const y = padding + (height - 2 * padding) * i / 4;
|
|
648
|
+
return `<line x1="${padding}" y1="${y}" x2="${width - padding}" y2="${y}"/>`;
|
|
649
|
+
}).join("\n")}
|
|
867
650
|
</g>
|
|
868
651
|
|
|
869
652
|
<!-- Price line -->
|
|
@@ -874,24 +657,24 @@ To execute this order, call the executeOrder tool with these exact same paramete
|
|
|
874
657
|
|
|
875
658
|
<!-- Data points -->
|
|
876
659
|
${priceHistory.map((d, i) => {
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
660
|
+
const x = padding + i * xScale;
|
|
661
|
+
const y = height - padding - (d.price - yMin) * yScale;
|
|
662
|
+
return `<circle cx="${x}" cy="${y}" r="3" fill="#007bff"/>`;
|
|
663
|
+
}).join("\n")}
|
|
881
664
|
|
|
882
665
|
<!-- Labels -->
|
|
883
666
|
<g font-family="Arial" font-size="12" fill="#495057">
|
|
884
667
|
${Array.from({ length: 5 }, (_, i) => {
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
668
|
+
const x = padding + (width - 2 * padding) * i / 4;
|
|
669
|
+
const index = Math.floor((priceHistory.length - 1) * i / 4);
|
|
670
|
+
const timestamp = new Date(priceHistory[index].timestamp).toLocaleTimeString();
|
|
671
|
+
return `<text x="${x + padding}" y="${height - padding + 20}" text-anchor="middle">${timestamp}</text>`;
|
|
672
|
+
}).join("\n")}
|
|
890
673
|
${Array.from({ length: 5 }, (_, i) => {
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
674
|
+
const y = padding + (height - 2 * padding) * i / 4;
|
|
675
|
+
const price = yMax - (yMax - yMin) * i / 4;
|
|
676
|
+
return `<text x="${padding - 5}" y="${y + 4}" text-anchor="end">$${price.toFixed(2)}</text>`;
|
|
677
|
+
}).join("\n")}
|
|
895
678
|
</g>
|
|
896
679
|
|
|
897
680
|
<!-- Title -->
|
|
@@ -901,86 +684,45 @@ To execute this order, call the executeOrder tool with these exact same paramete
|
|
|
901
684
|
${symbol} - Price Chart (${priceHistory.length} points)
|
|
902
685
|
</text>
|
|
903
686
|
</svg>`;
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
uri: "getStockGraph"
|
|
910
|
-
}
|
|
911
|
-
]
|
|
912
|
-
};
|
|
913
|
-
} catch (error) {
|
|
914
|
-
return {
|
|
915
|
-
contents: [
|
|
916
|
-
{
|
|
917
|
-
type: "text",
|
|
918
|
-
text: `Error: ${error instanceof Error ? error.message : "Failed to generate stock graph"}`,
|
|
919
|
-
uri: "getStockGraph"
|
|
920
|
-
}
|
|
921
|
-
],
|
|
922
|
-
isError: true
|
|
923
|
-
};
|
|
924
|
-
}
|
|
925
|
-
case "getStockPriceHistory":
|
|
926
|
-
try {
|
|
927
|
-
const symbol = args.symbol;
|
|
928
|
-
const priceHistory = this.marketDataPrices.get(symbol) || [];
|
|
929
|
-
if (priceHistory.length === 0) {
|
|
930
|
-
return {
|
|
931
|
-
contents: [
|
|
932
|
-
{
|
|
933
|
-
type: "text",
|
|
934
|
-
text: `No price data available for ${symbol}`,
|
|
935
|
-
uri: "getStockPriceHistory"
|
|
936
|
-
}
|
|
937
|
-
]
|
|
938
|
-
};
|
|
939
|
-
}
|
|
940
|
-
return {
|
|
941
|
-
contents: [
|
|
942
|
-
{
|
|
943
|
-
type: "text",
|
|
944
|
-
text: JSON.stringify(
|
|
945
|
-
{
|
|
946
|
-
symbol,
|
|
947
|
-
count: priceHistory.length,
|
|
948
|
-
prices: priceHistory.map((point) => ({
|
|
949
|
-
timestamp: new Date(point.timestamp).toISOString(),
|
|
950
|
-
price: point.price
|
|
951
|
-
}))
|
|
952
|
-
},
|
|
953
|
-
null,
|
|
954
|
-
2
|
|
955
|
-
),
|
|
956
|
-
uri: "getStockPriceHistory"
|
|
957
|
-
}
|
|
958
|
-
]
|
|
959
|
-
};
|
|
960
|
-
} catch (error) {
|
|
961
|
-
return {
|
|
962
|
-
contents: [
|
|
963
|
-
{
|
|
964
|
-
type: "text",
|
|
965
|
-
text: `Error: ${error instanceof Error ? error.message : "Failed to get stock price history"}`,
|
|
966
|
-
uri: "getStockPriceHistory"
|
|
967
|
-
}
|
|
968
|
-
],
|
|
969
|
-
isError: true
|
|
970
|
-
};
|
|
687
|
+
return {
|
|
688
|
+
content: [
|
|
689
|
+
{
|
|
690
|
+
type: "text",
|
|
691
|
+
text: svg
|
|
971
692
|
}
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
693
|
+
]
|
|
694
|
+
};
|
|
695
|
+
}
|
|
696
|
+
);
|
|
697
|
+
this.server.setRequestHandler(
|
|
698
|
+
z.object({ method: z.literal("stockPriceHistory") }),
|
|
699
|
+
async (request, extra) => {
|
|
700
|
+
this.parser?.logger.log({
|
|
701
|
+
level: "info",
|
|
702
|
+
message: "MCP Server Resource called: stockPriceHistory"
|
|
703
|
+
});
|
|
704
|
+
const args = request.params;
|
|
705
|
+
const symbol = args.symbol;
|
|
706
|
+
const priceHistory = this.marketDataPrices.get(symbol) || [];
|
|
707
|
+
return {
|
|
708
|
+
content: [
|
|
709
|
+
{
|
|
710
|
+
type: "text",
|
|
711
|
+
text: JSON.stringify(
|
|
975
712
|
{
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
713
|
+
symbol,
|
|
714
|
+
count: priceHistory.length,
|
|
715
|
+
prices: priceHistory.map((point) => ({
|
|
716
|
+
timestamp: new Date(point.timestamp).toISOString(),
|
|
717
|
+
price: point.price
|
|
718
|
+
}))
|
|
719
|
+
},
|
|
720
|
+
null,
|
|
721
|
+
2
|
|
722
|
+
)
|
|
723
|
+
}
|
|
724
|
+
]
|
|
725
|
+
};
|
|
984
726
|
}
|
|
985
727
|
);
|
|
986
728
|
process.on("SIGINT", async () => {
|