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.
- package/build/cjs/MCPLocal.js +353 -159
- package/build/cjs/MCPLocal.js.map +2 -2
- package/build/esm/MCPLocal.mjs +360 -160
- package/build/esm/MCPLocal.mjs.map +2 -2
- package/build-examples/cjs/example_mcp_local.js +4 -1
- package/build-examples/cjs/example_mcp_local.js.map +3 -3
- package/build-examples/esm/example_mcp_local.mjs +4 -1
- package/build-examples/esm/example_mcp_local.mjs.map +3 -3
- package/package.json +6 -5
package/build/esm/MCPLocal.mjs
CHANGED
|
@@ -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 {
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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: {
|
|
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
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
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: "
|
|
392
|
-
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:
|
|
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
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
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: "
|
|
467
|
-
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:
|
|
490
|
+
text: `Error: ${error instanceof Error ? error.message : "Failed to request market data"}`
|
|
475
491
|
}
|
|
476
492
|
]
|
|
477
493
|
};
|
|
478
494
|
}
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
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
|
-
|
|
625
|
+
messages: [
|
|
487
626
|
{
|
|
488
|
-
|
|
489
|
-
|
|
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
|
|
695
|
+
throw new Error(`Unknown prompt: ${name}`);
|
|
496
696
|
}
|
|
497
697
|
});
|
|
498
698
|
process.on("SIGINT", async () => {
|