fixparser-plugin-mcp 9.1.7-4423352c → 9.1.7-525accda

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,7 +1,13 @@
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 { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
4
+ import {
5
+ CallToolRequestSchema,
6
+ GetPromptRequestSchema,
7
+ ListPromptsRequestSchema,
8
+ ListResourcesRequestSchema,
9
+ ListToolsRequestSchema
10
+ } from "@modelcontextprotocol/sdk/types.js";
5
11
  import {
6
12
  Field,
7
13
  Fields,
@@ -22,6 +28,16 @@ var parseInputSchema = {
22
28
  },
23
29
  required: ["fixString"]
24
30
  };
31
+ var parseToJSONInputSchema = {
32
+ type: "object",
33
+ properties: {
34
+ fixString: {
35
+ type: "string",
36
+ description: "FIX message string to parse"
37
+ }
38
+ },
39
+ required: ["fixString"]
40
+ };
25
41
  var newOrderSingleInputSchema = {
26
42
  type: "object",
27
43
  properties: {
@@ -33,7 +49,7 @@ var newOrderSingleInputSchema = {
33
49
  type: "string",
34
50
  enum: ["1", "2", "3"],
35
51
  default: HandlInst.AutomatedExecutionNoIntervention,
36
- description: "Handling instruction"
52
+ description: 'Handling instruction (IMPORTANT: Use the numeric/alphabetic value, not the descriptive name. For example, use "1" for Manual, "2" for Automated, "3" for AutomatedNoIntervention)'
37
53
  },
38
54
  quantity: {
39
55
  type: "number",
@@ -74,12 +90,12 @@ var newOrderSingleInputSchema = {
74
90
  "S"
75
91
  ],
76
92
  default: OrdType.Market,
77
- description: "Order type"
93
+ description: 'Order type (IMPORTANT: Use the numeric/alphabetic value, not the descriptive name. For example, use "1" for Market, "2" for Limit, "3" for Stop)'
78
94
  },
79
95
  side: {
80
96
  type: "string",
81
97
  enum: ["1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H"],
82
- description: "Order side (1=Buy, 2=Sell)"
98
+ description: 'Order side (IMPORTANT: Use the numeric/alphabetic value, not the descriptive name. For example, use "1" for Buy, "2" for Sell, "3" for BuyMinus, "4" for SellPlus, "5" for SellShort, "6" for SellShortExempt, "7" for Undisclosed, "8" for Cross, "9" for CrossShort, "A" for CrossShortExempt, "B" for AsDefined, "C" for Opposite, "D" for Subscribe, "E" for Redeem, "F" for Lend, "G" for Borrow, "H" for SellUndisclosed)'
83
99
  },
84
100
  symbol: {
85
101
  type: "string",
@@ -89,7 +105,7 @@ var newOrderSingleInputSchema = {
89
105
  type: "string",
90
106
  enum: ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C"],
91
107
  default: TimeInForce.Day,
92
- description: "Time in force"
108
+ description: 'Time in force (IMPORTANT: Use the numeric/alphabetic value, not the descriptive name. For example, use "0" for Day, "1" for Good Till Cancel, "2" for At Opening, "3" for Immediate or Cancel, "4" for Fill or Kill, "5" for Good Till Crossing, "6" for Good Till Date)'
93
109
  }
94
110
  },
95
111
  required: ["clOrdID", "quantity", "price", "side", "symbol"]
@@ -101,7 +117,7 @@ var marketDataRequestInputSchema = {
101
117
  type: "string",
102
118
  enum: ["0", "1"],
103
119
  default: "0",
104
- description: "Market data update type"
120
+ description: 'Market data update type (IMPORTANT: Use the numeric/alphabetic value, not the descriptive name. For example, use "0" for FullRefresh, "1" for IncrementalRefresh)'
105
121
  },
106
122
  symbol: {
107
123
  type: "string",
@@ -115,7 +131,7 @@ var marketDataRequestInputSchema = {
115
131
  type: "string",
116
132
  enum: ["0", "1", "2"],
117
133
  default: SubscriptionRequestType.SnapshotAndUpdates,
118
- description: "Subscription request type"
134
+ description: 'Subscription request type (IMPORTANT: Use the numeric/alphabetic value, not the descriptive name. For example, use "0" for Snapshot + Updates, "1" for Snapshot, "2" for Unsubscribe)'
119
135
  },
120
136
  mdEntryType: {
121
137
  type: "string",
@@ -166,7 +182,7 @@ var marketDataRequestInputSchema = {
166
182
  "t"
167
183
  ],
168
184
  default: MDEntryType.Bid,
169
- description: "Market data entry type"
185
+ description: 'Market data entry type (IMPORTANT: Use the numeric/alphabetic value, not the descriptive name. For example, use "0" for Bid, "1" for Offer, "2" for Trade, "3" for Index Value, "4" for Opening Price)'
170
186
  }
171
187
  },
172
188
  required: ["symbol", "mdReqID"]
@@ -180,23 +196,28 @@ var MCPLocal = class {
180
196
  version: "1.0.0"
181
197
  },
182
198
  {
183
- capabilities: { tools: {} }
199
+ capabilities: {
200
+ tools: {},
201
+ prompts: {},
202
+ resources: {}
203
+ }
184
204
  }
185
205
  );
186
206
  transport = new StdioServerTransport();
187
207
  onReady = void 0;
188
208
  pendingRequests = /* @__PURE__ */ new Map();
189
209
  constructor({ logger, onReady }) {
190
- if (logger) this.logger = logger;
210
+ if (logger && !logger.silent) {
211
+ this.logger = logger;
212
+ }
191
213
  if (onReady) this.onReady = onReady;
192
214
  }
193
215
  async register(parser) {
194
216
  this.parser = parser;
217
+ if (parser.logger && !parser.logger.silent) {
218
+ this.logger = parser.logger;
219
+ }
195
220
  this.parser.addOnMessageCallback((message) => {
196
- this.logger?.log({
197
- level: "info",
198
- message: `FIXParser (MCP): (${parser.protocol?.toUpperCase()}): << received ${message.description}`
199
- });
200
221
  const msgType = message.messageType;
201
222
  if (msgType === Messages.MarketDataSnapshotFullRefresh || msgType === Messages.ExecutionReport) {
202
223
  const idField = msgType === Messages.MarketDataSnapshotFullRefresh ? message.getField(Fields.MDReqID) : message.getField(Fields.ClOrdID);
@@ -212,7 +233,6 @@ var MCPLocal = class {
212
233
  }
213
234
  }
214
235
  });
215
- this.logger = parser.logger;
216
236
  this.addWorkflows();
217
237
  await this.server.connect(this.transport);
218
238
  if (this.onReady) {
@@ -234,6 +254,27 @@ var MCPLocal = class {
234
254
  });
235
255
  return;
236
256
  }
257
+ const validateArgs = (args, schema) => {
258
+ const result = {};
259
+ for (const [key, propSchema] of Object.entries(schema.properties || {})) {
260
+ const prop = propSchema;
261
+ const value = args?.[key];
262
+ if (prop.required && (value === void 0 || value === null)) {
263
+ throw new Error(`Required property '${key}' is missing`);
264
+ }
265
+ if (value !== void 0) {
266
+ result[key] = value;
267
+ } else if (prop.default !== void 0) {
268
+ result[key] = prop.default;
269
+ }
270
+ }
271
+ return result;
272
+ };
273
+ this.server.setRequestHandler(ListResourcesRequestSchema, async () => {
274
+ return {
275
+ resources: []
276
+ };
277
+ });
237
278
  this.server.setRequestHandler(ListToolsRequestSchema, async () => {
238
279
  return {
239
280
  tools: [
@@ -245,7 +286,7 @@ var MCPLocal = class {
245
286
  {
246
287
  name: "parseToJSON",
247
288
  description: "Parses a FIX message into JSON",
248
- inputSchema: parseInputSchema
289
+ inputSchema: parseToJSONInputSchema
249
290
  },
250
291
  {
251
292
  name: "newOrderSingle",
@@ -264,11 +305,8 @@ var MCPLocal = class {
264
305
  const { name, arguments: args } = request.params;
265
306
  switch (name) {
266
307
  case "parse": {
267
- const { fixString } = args || {};
268
- if (!fixString || typeof fixString !== "string") {
269
- throw new Error("Invalid arguments: fixString is required and must be a string");
270
- }
271
308
  try {
309
+ const { fixString } = validateArgs(args, parseInputSchema);
272
310
  const parsedMessage = this.parser?.parse(fixString);
273
311
  if (!parsedMessage || parsedMessage.length === 0) {
274
312
  return {
@@ -280,7 +318,8 @@ var MCPLocal = class {
280
318
  content: [
281
319
  {
282
320
  type: "text",
283
- text: `Parsed FIX message: ${fixString} (placeholder implementation)`
321
+ text: `${parsedMessage[0].description}
322
+ ${parsedMessage[0].messageTypeDescription}`
284
323
  }
285
324
  ]
286
325
  };
@@ -290,18 +329,15 @@ var MCPLocal = class {
290
329
  content: [
291
330
  {
292
331
  type: "text",
293
- text: "Error: Failed to parse FIX string"
332
+ text: `Error: ${error instanceof Error ? error.message : "Failed to parse FIX string"}`
294
333
  }
295
334
  ]
296
335
  };
297
336
  }
298
337
  }
299
338
  case "parseToJSON": {
300
- const { fixString } = args || {};
301
- if (!fixString || typeof fixString !== "string") {
302
- throw new Error("Invalid arguments: fixString is required and must be a string");
303
- }
304
339
  try {
340
+ const { fixString } = validateArgs(args, parseToJSONInputSchema);
305
341
  const parsedMessage = this.parser?.parse(fixString);
306
342
  if (!parsedMessage || parsedMessage.length === 0) {
307
343
  return {
@@ -313,7 +349,7 @@ var MCPLocal = class {
313
349
  content: [
314
350
  {
315
351
  type: "text",
316
- text: JSON.stringify({ fixString, parsed: "placeholder" })
352
+ text: `${parsedMessage[0].toFIXJSON()}`
317
353
  }
318
354
  ]
319
355
  };
@@ -323,176 +359,340 @@ var MCPLocal = class {
323
359
  content: [
324
360
  {
325
361
  type: "text",
326
- text: "Error: Failed to parse FIX string"
362
+ text: `Error: ${error instanceof Error ? error.message : "Failed to parse FIX string"}`
327
363
  }
328
364
  ]
329
365
  };
330
366
  }
331
367
  }
332
368
  case "newOrderSingle": {
333
- const { clOrdID, handlInst, quantity, price, ordType, side, symbol, timeInForce } = args || {};
334
- if (!clOrdID || typeof clOrdID !== "string") {
335
- throw new Error("Invalid arguments: clOrdID is required and must be a string");
336
- }
337
- if (ordType && typeof ordType !== "string") {
338
- throw new Error("Invalid arguments: ordType is required and must be a string");
339
- }
340
- if (handlInst && typeof handlInst !== "string") {
341
- throw new Error("Invalid arguments: handlInst is required and must be a string");
342
- }
343
- if (timeInForce && typeof timeInForce !== "string") {
344
- throw new Error("Invalid arguments: timeInForce is required and must be a string");
345
- }
346
- if (typeof quantity !== "number") {
347
- throw new Error("Invalid arguments: quantity is required and must be a number");
348
- }
349
- if (typeof price !== "number") {
350
- throw new Error("Invalid arguments: price is required and must be a number");
351
- }
352
- if (!side || typeof side !== "string" || !["1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H"].includes(
353
- side
354
- )) {
355
- throw new Error("Invalid arguments: side is required and must be a valid order side");
356
- }
357
- if (!symbol || typeof symbol !== "string") {
358
- throw new Error("Invalid arguments: symbol is required and must be a string");
359
- }
360
- const response = new Promise((resolve) => {
361
- this.pendingRequests.set(clOrdID, resolve);
362
- });
363
- const msgSeqNum = this.parser?.getNextTargetMsgSeqNum();
364
- const sender = this.parser?.sender;
365
- const target = this.parser?.target;
366
- const timestamp = this.parser?.getTimestamp();
367
- if (!msgSeqNum || !sender || !target || !timestamp) {
368
- throw new Error("Parser not properly initialized");
369
- }
370
- const order = this.parser?.createMessage(
371
- new Field(Fields.MsgType, Messages.NewOrderSingle),
372
- new Field(Fields.MsgSeqNum, msgSeqNum),
373
- new Field(Fields.SenderCompID, sender),
374
- new Field(Fields.TargetCompID, target),
375
- new Field(Fields.SendingTime, timestamp),
376
- new Field(Fields.ClOrdID, clOrdID),
377
- new Field(Fields.Side, side),
378
- new Field(Fields.Symbol, symbol),
379
- new Field(Fields.OrderQty, quantity),
380
- new Field(Fields.Price, price),
381
- new Field(Fields.OrdType, ordType || OrdType.Market),
382
- new Field(
383
- Fields.HandlInst,
384
- handlInst || HandlInst.AutomatedExecutionNoIntervention
385
- ),
386
- new Field(Fields.TimeInForce, timeInForce || TimeInForce.Day),
387
- new Field(Fields.TransactTime, timestamp)
388
- );
389
- if (!this.parser?.connected) {
369
+ try {
370
+ const { clOrdID, handlInst, quantity, price, ordType, side, symbol, timeInForce } = validateArgs(args, newOrderSingleInputSchema);
371
+ const response = new Promise((resolve) => {
372
+ this.pendingRequests.set(clOrdID, resolve);
373
+ });
374
+ const order = this.parser?.createMessage(
375
+ new Field(Fields.MsgType, Messages.NewOrderSingle),
376
+ new Field(Fields.MsgSeqNum, this.parser?.getNextTargetMsgSeqNum()),
377
+ new Field(Fields.SenderCompID, this.parser?.sender),
378
+ new Field(Fields.TargetCompID, this.parser?.target),
379
+ new Field(Fields.SendingTime, this.parser?.getTimestamp()),
380
+ new Field(Fields.ClOrdID, clOrdID),
381
+ new Field(Fields.Side, side),
382
+ new Field(Fields.Symbol, symbol),
383
+ new Field(Fields.OrderQty, quantity),
384
+ new Field(Fields.Price, price),
385
+ new Field(Fields.OrdType, ordType),
386
+ new Field(Fields.HandlInst, handlInst),
387
+ new Field(Fields.TimeInForce, timeInForce),
388
+ new Field(Fields.TransactTime, this.parser?.getTimestamp())
389
+ );
390
+ if (!this.parser?.connected) {
391
+ this.logger?.log({
392
+ level: "error",
393
+ message: "FIXParser (MCP): -- Not connected. Ignoring message."
394
+ });
395
+ return {
396
+ isError: true,
397
+ content: [
398
+ {
399
+ type: "text",
400
+ text: "Error: Not connected. Ignoring message."
401
+ }
402
+ ]
403
+ };
404
+ }
405
+ this.parser?.send(order);
390
406
  this.logger?.log({
391
- level: "error",
392
- message: "FIXParser (MCP): -- Not connected. Ignoring message."
407
+ level: "info",
408
+ message: `FIXParser (MCP): (${this.parser?.protocol?.toUpperCase()}): >> sent ${order?.description}`
393
409
  });
410
+ const fixData = await response;
411
+ return {
412
+ content: [
413
+ {
414
+ type: "text",
415
+ text: `Execution Report for order ${clOrdID}: ${JSON.stringify(fixData.toFIXJSON())}`
416
+ }
417
+ ]
418
+ };
419
+ } catch (error) {
394
420
  return {
395
421
  isError: true,
396
422
  content: [
397
423
  {
398
424
  type: "text",
399
- text: "Error: Not connected. Ignoring message."
425
+ text: `Error: ${error instanceof Error ? error.message : "Failed to create order"}`
400
426
  }
401
427
  ]
402
428
  };
403
429
  }
404
- this.parser?.send(order);
405
- this.logger?.log({
406
- level: "info",
407
- message: `FIXParser (MCP): (${this.parser?.protocol?.toUpperCase()}): >> sent ${order?.description}`
408
- });
409
- const fixData = await response;
410
- return {
411
- content: [
412
- {
413
- type: "text",
414
- text: `Execution Report for order ${clOrdID}: ${JSON.stringify(fixData.toFIXJSON())}`
415
- }
416
- ]
417
- };
418
430
  }
419
431
  case "marketDataRequest": {
420
- const { mdUpdateType, symbol, mdReqID, subscriptionRequestType, mdEntryType } = args || {};
421
- if (!symbol || typeof symbol !== "string") {
422
- throw new Error("Invalid arguments: symbol is required and must be a string");
423
- }
424
- if (!mdReqID || typeof mdReqID !== "string") {
425
- throw new Error("Invalid arguments: mdReqID is required and must be a string");
426
- }
427
- if (mdUpdateType && typeof mdUpdateType !== "string") {
428
- throw new Error("Invalid arguments: mdUpdateType is required and must be a string");
429
- }
430
- if (subscriptionRequestType && typeof subscriptionRequestType !== "string") {
431
- throw new Error("Invalid arguments: subscriptionRequestType is required and must be a string");
432
- }
433
- if (mdEntryType && typeof mdEntryType !== "string") {
434
- throw new Error("Invalid arguments: mdEntryType is required and must be a string");
435
- }
436
- const response = new Promise((resolve) => {
437
- this.pendingRequests.set(mdReqID, resolve);
438
- });
439
- const msgSeqNum = this.parser?.getNextTargetMsgSeqNum();
440
- const sender = this.parser?.sender;
441
- const target = this.parser?.target;
442
- const timestamp = this.parser?.getTimestamp();
443
- if (!msgSeqNum || !sender || !target || !timestamp) {
444
- throw new Error("Parser not properly initialized");
445
- }
446
- const marketDataRequest = this.parser?.createMessage(
447
- new Field(Fields.MsgType, Messages.MarketDataRequest),
448
- new Field(Fields.SenderCompID, sender),
449
- new Field(Fields.MsgSeqNum, msgSeqNum),
450
- new Field(Fields.TargetCompID, target),
451
- new Field(Fields.SendingTime, timestamp),
452
- new Field(Fields.MarketDepth, 0),
453
- new Field(Fields.MDUpdateType, mdUpdateType || "0"),
454
- new Field(Fields.NoRelatedSym, 1),
455
- new Field(Fields.Symbol, symbol),
456
- new Field(Fields.MDReqID, mdReqID),
457
- new Field(
458
- Fields.SubscriptionRequestType,
459
- subscriptionRequestType || SubscriptionRequestType.SnapshotAndUpdates
460
- ),
461
- new Field(Fields.NoMDEntryTypes, 1),
462
- new Field(Fields.MDEntryType, mdEntryType || MDEntryType.Bid)
463
- );
464
- if (!this.parser?.connected) {
432
+ try {
433
+ const { mdUpdateType, symbol, mdReqID, subscriptionRequestType, mdEntryType } = validateArgs(
434
+ args,
435
+ marketDataRequestInputSchema
436
+ );
437
+ const response = new Promise((resolve) => {
438
+ this.pendingRequests.set(mdReqID, resolve);
439
+ });
440
+ const marketDataRequest = this.parser?.createMessage(
441
+ new Field(Fields.MsgType, Messages.MarketDataRequest),
442
+ new Field(Fields.SenderCompID, this.parser?.sender),
443
+ new Field(Fields.MsgSeqNum, this.parser?.getNextTargetMsgSeqNum()),
444
+ new Field(Fields.TargetCompID, this.parser?.target),
445
+ new Field(Fields.SendingTime, this.parser?.getTimestamp()),
446
+ new Field(Fields.MarketDepth, 0),
447
+ new Field(Fields.MDUpdateType, mdUpdateType),
448
+ new Field(Fields.NoRelatedSym, 1),
449
+ new Field(Fields.Symbol, symbol),
450
+ new Field(Fields.MDReqID, mdReqID),
451
+ new Field(Fields.SubscriptionRequestType, subscriptionRequestType),
452
+ new Field(Fields.NoMDEntryTypes, 1),
453
+ new Field(Fields.MDEntryType, mdEntryType)
454
+ );
455
+ if (!this.parser?.connected) {
456
+ this.logger?.log({
457
+ level: "error",
458
+ message: "FIXParser (MCP): -- Not connected. Ignoring message."
459
+ });
460
+ return {
461
+ isError: true,
462
+ content: [
463
+ {
464
+ type: "text",
465
+ text: "Error: Not connected. Ignoring message."
466
+ }
467
+ ]
468
+ };
469
+ }
470
+ this.parser?.send(marketDataRequest);
465
471
  this.logger?.log({
466
- level: "error",
467
- message: "FIXParser (MCP): -- Not connected. Ignoring message."
472
+ level: "info",
473
+ message: `FIXParser (MCP): (${this.parser?.protocol?.toUpperCase()}): >> sent ${marketDataRequest?.description}`
468
474
  });
475
+ const fixData = await response;
476
+ return {
477
+ content: [
478
+ {
479
+ type: "text",
480
+ text: `Market data for ${symbol}: ${JSON.stringify(fixData.toFIXJSON())}`
481
+ }
482
+ ]
483
+ };
484
+ } catch (error) {
469
485
  return {
470
486
  isError: true,
471
487
  content: [
472
488
  {
473
489
  type: "text",
474
- text: "Error: Not connected. Ignoring message."
490
+ text: `Error: ${error instanceof Error ? error.message : "Failed to request market data"}`
475
491
  }
476
492
  ]
477
493
  };
478
494
  }
479
- this.parser?.send(marketDataRequest);
480
- this.logger?.log({
481
- level: "info",
482
- message: `FIXParser (MCP): (${this.parser?.protocol?.toUpperCase()}): >> sent ${marketDataRequest?.description}`
483
- });
484
- const fixData = await response;
495
+ }
496
+ default:
497
+ throw new Error(`Unknown tool: ${name}`);
498
+ }
499
+ });
500
+ this.server.setRequestHandler(ListPromptsRequestSchema, async () => {
501
+ return {
502
+ prompts: [
503
+ {
504
+ name: "parse",
505
+ description: "Parses a FIX message and describes it in plain language",
506
+ arguments: [
507
+ {
508
+ name: "fixString",
509
+ description: "FIX message string to parse",
510
+ required: true
511
+ }
512
+ ]
513
+ },
514
+ {
515
+ name: "parseToJSON",
516
+ description: "Parses a FIX message into JSON",
517
+ arguments: [
518
+ {
519
+ name: "fixString",
520
+ description: "FIX message string to parse",
521
+ required: true
522
+ }
523
+ ]
524
+ },
525
+ {
526
+ name: "newOrderSingle",
527
+ description: "Creates and sends a New Order Single",
528
+ arguments: [
529
+ {
530
+ name: "clOrdID",
531
+ description: "Client Order ID",
532
+ required: true
533
+ },
534
+ {
535
+ name: "handlInst",
536
+ description: "Handling instruction",
537
+ required: false
538
+ },
539
+ {
540
+ name: "quantity",
541
+ description: "Order quantity",
542
+ required: true
543
+ },
544
+ {
545
+ name: "price",
546
+ description: "Order price",
547
+ required: true
548
+ },
549
+ {
550
+ name: "ordType",
551
+ description: "Order type",
552
+ required: false
553
+ },
554
+ {
555
+ name: "side",
556
+ description: "Order side (1=Buy, 2=Sell, 3=BuyMinus, 4=SellPlus, 5=SellShort, 6=SellShortExempt, 7=Undisclosed, 8=Cross, 9=CrossShort, A=CrossShortExempt, B=AsDefined, C=Opposite, D=Subscribe, E=Redeem, F=Lend, G=Borrow, H=SellUndisclosed)",
557
+ required: true
558
+ },
559
+ {
560
+ name: "symbol",
561
+ description: "Trading symbol",
562
+ required: true
563
+ },
564
+ {
565
+ name: "timeInForce",
566
+ description: "Time in force",
567
+ required: false
568
+ }
569
+ ]
570
+ },
571
+ {
572
+ name: "marketDataRequest",
573
+ description: "Sends a request for Market Data with the given symbol",
574
+ arguments: [
575
+ {
576
+ name: "mdUpdateType",
577
+ description: "Market data update type",
578
+ required: false
579
+ },
580
+ {
581
+ name: "symbol",
582
+ description: "Trading symbol",
583
+ required: true
584
+ },
585
+ {
586
+ name: "mdReqID",
587
+ description: "Market data request ID",
588
+ required: true
589
+ },
590
+ {
591
+ name: "subscriptionRequestType",
592
+ description: "Subscription request type",
593
+ required: false
594
+ },
595
+ {
596
+ name: "mdEntryType",
597
+ description: "Market data entry type",
598
+ required: false
599
+ }
600
+ ]
601
+ }
602
+ ]
603
+ };
604
+ });
605
+ this.server.setRequestHandler(GetPromptRequestSchema, async (request) => {
606
+ const { name, arguments: args } = request.params;
607
+ switch (name) {
608
+ case "parse": {
609
+ const fixString = args?.fixString || "";
610
+ return {
611
+ messages: [
612
+ {
613
+ role: "user",
614
+ content: {
615
+ type: "text",
616
+ text: `Please parse and explain this FIX message: ${fixString}`
617
+ }
618
+ }
619
+ ]
620
+ };
621
+ }
622
+ case "parseToJSON": {
623
+ const fixString = args?.fixString || "";
485
624
  return {
486
- content: [
625
+ messages: [
487
626
  {
488
- type: "text",
489
- text: `Market data for ${symbol}: ${JSON.stringify(fixData.toFIXJSON())}`
627
+ role: "user",
628
+ content: {
629
+ type: "text",
630
+ text: `Please parse the FIX message to JSON: ${fixString}`
631
+ }
632
+ }
633
+ ]
634
+ };
635
+ }
636
+ case "newOrderSingle": {
637
+ const { clOrdID, handlInst, quantity, price, ordType, side, symbol, timeInForce } = args || {};
638
+ return {
639
+ messages: [
640
+ {
641
+ role: "user",
642
+ content: {
643
+ type: "text",
644
+ text: [
645
+ "Create a New Order Single FIX message with the following parameters:",
646
+ `- ClOrdID: ${clOrdID}`,
647
+ `- HandlInst: ${handlInst ?? "3"} (IMPORTANT: Use the numeric/alphabetic value, not the descriptive name. For example, use '1' for Manual, '2' for Automated, '3' for AutomatedNoIntervention)`,
648
+ `- Quantity: ${quantity}`,
649
+ `- Price: ${price}`,
650
+ `- OrdType: ${ordType ?? "1"} (IMPORTANT: Use the numeric/alphabetic value, not the descriptive name. For example, use '1' for Market, '2' for Limit, '3' for Stop)`,
651
+ `- Side: ${side} (IMPORTANT: Use the numeric/alphabetic value, not the descriptive name. For example, use '1' for Buy, '2' for Sell)`,
652
+ `- Symbol: ${symbol}`,
653
+ `- TimeInForce: ${timeInForce ?? "0"} (IMPORTANT: Use the numeric/alphabetic value, not the descriptive name. For example, use '0' for Day, '1' for Good Till Cancel, '2' for At Opening, '3' for Immediate or Cancel, '4' for Fill or Kill, '5' for Good Till Crossing, '6' for Good Till Date)`,
654
+ "",
655
+ "Format the response as a JSON object with FIX tag numbers as keys and their corresponding values.",
656
+ "",
657
+ 'Note: For the Side parameter, always use the numeric/alphabetic value (e.g., "1" for Buy, "2" for Sell) as defined in the FIX protocol, not the descriptive name.',
658
+ 'Note: For the HandlInst parameter, always use the numeric/alphabetic value (e.g., "1" for Manual, "2" for Automated, "3" for AutomatedNoIntervention) as defined in the FIX protocol, not the descriptive name.',
659
+ 'Note: For the OrdType parameter, always use the numeric/alphabetic value (e.g., "1" for Market, "2" for Limit, "3" for Stop) as defined in the FIX protocol, not the descriptive name.',
660
+ 'Note: For the TimeInForce parameter, always use the numeric/alphabetic value (e.g., "0" for Day, "1" for Good Till Cancel, "2" for At Opening) as defined in the FIX protocol, not the descriptive name.'
661
+ ].join("\n")
662
+ }
663
+ }
664
+ ]
665
+ };
666
+ }
667
+ case "marketDataRequest": {
668
+ const { mdUpdateType, symbol, mdReqID, subscriptionRequestType, mdEntryType } = args || {};
669
+ return {
670
+ messages: [
671
+ {
672
+ role: "user",
673
+ content: {
674
+ type: "text",
675
+ text: [
676
+ "Create a Market Data Request FIX message with the following parameters:",
677
+ `- MDUpdateType: ${mdUpdateType ?? "0"} (IMPORTANT: Use the numeric/alphabetic value, not the descriptive name. For example, use '0' for FullRefresh, '1' for IncrementalRefresh)`,
678
+ `- Symbol: ${symbol}`,
679
+ `- MDReqID: ${mdReqID}`,
680
+ `- SubscriptionRequestType: ${subscriptionRequestType ?? "0"} (IMPORTANT: Use the numeric/alphabetic value, not the descriptive name. For example, use '0' for Snapshot + Updates, '1' for Snapshot, '2' for Unsubscribe)`,
681
+ `- MDEntryType: ${mdEntryType ?? "0"} (IMPORTANT: Use the numeric/alphabetic value, not the descriptive name. For example, use '0' for Bid, '1' for Offer, '2' for Trade, '3' for Index Value, '4' for Opening Price)`,
682
+ "",
683
+ "Format the response as a JSON object with FIX tag numbers as keys and their corresponding values.",
684
+ "",
685
+ 'Note: For the MDUpdateType parameter, always use the numeric/alphabetic value (e.g., "0" for FullRefresh, "1" for IncrementalRefresh) as defined in the FIX protocol, not the descriptive name.',
686
+ 'Note: For the SubscriptionRequestType parameter, always use the numeric/alphabetic value (e.g., "0" for Snapshot + Updates, "1" for Snapshot, "2" for Unsubscribe) as defined in the FIX protocol, not the descriptive name.',
687
+ 'Note: For the MDEntryType parameter, always use the numeric/alphabetic value (e.g., "0" for Bid, "1" for Offer, "2" for Trade, "3" for Index Value, "4" for Opening Price) as defined in the FIX protocol, not the descriptive name.'
688
+ ].join("\n")
689
+ }
490
690
  }
491
691
  ]
492
692
  };
493
693
  }
494
694
  default:
495
- throw new Error(`Unknown tool: ${name}`);
695
+ throw new Error(`Unknown prompt: ${name}`);
496
696
  }
497
697
  });
498
698
  process.on("SIGINT", async () => {