@nqminds/mcp-client 1.0.14 → 1.0.21
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/dist/MCPChat.js +2 -2
- package/dist/api-helpers.d.ts +2 -0
- package/dist/api-helpers.d.ts.map +1 -1
- package/dist/api-helpers.js +2 -1
- package/dist/openai-client.d.ts +6 -0
- package/dist/openai-client.d.ts.map +1 -1
- package/dist/openai-client.js +167 -6
- package/package.json +2 -1
package/dist/MCPChat.js
CHANGED
|
@@ -191,7 +191,7 @@ export function MCPChat({ companyNumber, apiEndpoint = "/api/mcp/chat", customSt
|
|
|
191
191
|
}
|
|
192
192
|
catch (error) {
|
|
193
193
|
if (error instanceof Error && error.name === "AbortError") {
|
|
194
|
-
|
|
194
|
+
// Request cancelled by user — no-op
|
|
195
195
|
return;
|
|
196
196
|
}
|
|
197
197
|
console.error("Error:", error);
|
|
@@ -268,7 +268,7 @@ export function MCPChat({ companyNumber, apiEndpoint = "/api/mcp/chat", customSt
|
|
|
268
268
|
const visibleMessages = messages.filter((m) => !m.hidden);
|
|
269
269
|
const showHome = visibleMessages.length === 0 && !isLoading;
|
|
270
270
|
return (React.createElement("div", { className: `mcp-root ${className}`, style: customStyles, "data-theme": theme },
|
|
271
|
-
!isOpen && (React.createElement("button", { className: "mcp-float-icon", onClick: () => setIsOpen(true), "aria-label": "
|
|
271
|
+
!isOpen && (React.createElement("button", { className: "mcp-float-icon", onClick: () => setIsOpen(true), "aria-label": "Corporata AI assistant", title: "Corporata AI assistant" }, "\uD83E\uDD16")),
|
|
272
272
|
isOpen && (React.createElement("div", { className: "mcp-overlay" },
|
|
273
273
|
React.createElement("div", { className: "mcp-panel" },
|
|
274
274
|
React.createElement("div", { className: "mcp-chat-header" },
|
package/dist/api-helpers.d.ts
CHANGED
|
@@ -5,6 +5,8 @@ export interface CreateMCPHandlerConfig {
|
|
|
5
5
|
openaiApiKey: string;
|
|
6
6
|
mcpServerCommand: string;
|
|
7
7
|
openaiModel?: string;
|
|
8
|
+
/** Override log directory. Falls back to MCP_LOG_DIR env var. */
|
|
9
|
+
logDir?: string;
|
|
8
10
|
}
|
|
9
11
|
/**
|
|
10
12
|
* Creates a streaming MCP chat handler for Next.js API routes
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api-helpers.d.ts","sourceRoot":"","sources":["../src/api-helpers.ts"],"names":[],"mappings":"AAAA;;GAEG;AAOH,MAAM,WAAW,sBAAsB;IACrC,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,EAAE,MAAM,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"api-helpers.d.ts","sourceRoot":"","sources":["../src/api-helpers.ts"],"names":[],"mappings":"AAAA;;GAEG;AAOH,MAAM,WAAW,sBAAsB;IACrC,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,EAAE,MAAM,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iEAAiE;IACjE,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,sBAAsB,IACnD,SAAS,OAAO,uBAoH/B;AAED;;GAEG;AACH,wBAAgB,qBAAqB,KACrB,SAAS,OAAO,uBAU/B;AAED;;GAEG;AACH,wBAAsB,iBAAiB,kBAKtC"}
|
package/dist/api-helpers.js
CHANGED
|
@@ -17,6 +17,7 @@ export function createMCPChatHandler(config) {
|
|
|
17
17
|
openaiApiKey: config.openaiApiKey,
|
|
18
18
|
mcpServerCommand: config.mcpServerCommand,
|
|
19
19
|
openaiModel: config.openaiModel,
|
|
20
|
+
logDir: config.logDir || process.env.MCP_LOG_DIR,
|
|
20
21
|
});
|
|
21
22
|
await client.connect();
|
|
22
23
|
clients.set(sessionId, client);
|
|
@@ -96,7 +97,7 @@ export function createMCPChatHandler(config) {
|
|
|
96
97
|
},
|
|
97
98
|
cancel() {
|
|
98
99
|
// This is called when client disconnects/cancels
|
|
99
|
-
console.
|
|
100
|
+
console.error("Client disconnected, aborting server processing");
|
|
100
101
|
abortController.abort();
|
|
101
102
|
}
|
|
102
103
|
});
|
package/dist/openai-client.d.ts
CHANGED
|
@@ -38,6 +38,11 @@ export interface MCPClientConfig {
|
|
|
38
38
|
* Guardrail for unusually large tool outputs stored in history.
|
|
39
39
|
*/
|
|
40
40
|
maxToolOutputChars?: number;
|
|
41
|
+
/**
|
|
42
|
+
* Directory to write structured JSONL log files.
|
|
43
|
+
* Falls back to the MCP_LOG_DIR env var, then to ./logs relative to CWD.
|
|
44
|
+
*/
|
|
45
|
+
logDir?: string;
|
|
41
46
|
}
|
|
42
47
|
interface UsageStats {
|
|
43
48
|
inputTokens: number;
|
|
@@ -81,6 +86,7 @@ export declare class MCPClientOpenAI {
|
|
|
81
86
|
*/
|
|
82
87
|
private turnStats;
|
|
83
88
|
private config;
|
|
89
|
+
private logger;
|
|
84
90
|
constructor(config: MCPClientConfig);
|
|
85
91
|
connect(): Promise<void>;
|
|
86
92
|
cleanup(): Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"openai-client.d.ts","sourceRoot":"","sources":["../src/openai-client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;
|
|
1
|
+
{"version":3,"file":"openai-client.d.ts","sourceRoot":"","sources":["../src/openai-client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAsEH,MAAM,WAAW,eAAe;IAC9B,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,EAAE,MAAM,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB;;;;OAIG;IACH,yBAAyB,CAAC,EAAE,MAAM,CAAC;IAEnC;;;;OAIG;IACH,2BAA2B,CAAC,EAAE,MAAM,CAAC;IAErC;;OAEG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAE5B;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAID,UAAU,UAAU;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;IACxB,cAAc,EAAE,MAAM,CAAC;CACxB;AAiBD,qBAAa,eAAe;IAC1B,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,SAAS,CAAuB;IAExC;;;OAGG;IACH,OAAO,CAAC,YAAY,CAAuB;IAE3C;;;OAGG;IACH,OAAO,CAAC,mBAAmB,CAA2B;IAEtD;;;OAGG;IACH,OAAO,CAAC,UAAU,CAGhB;IAEF;;OAEG;IACH,OAAO,CAAC,eAAe,CAAK;IAE5B;;OAEG;IACH,OAAO,CAAC,SAAS,CAOf;IAEF;;;;OAIG;IACH,OAAO,CAAC,SAAS,CAKf;IAEF,OAAO,CAAC,MAAM,CAA4B;IAC1C,OAAO,CAAC,MAAM,CAAa;gBAEf,MAAM,EAAE,eAAe;IAuC7B,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAKxB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAK9B,YAAY,IAAI,IAAI;IAmBpB,QAAQ,IAAI,UAAU;IAItB;;;OAGG;YACW,kBAAkB;IA0BhC;;;OAGG;IACH,OAAO,CAAC,UAAU;IAalB;;;OAGG;YACW,gBAAgB;IAuB9B;;;OAGG;IACH,OAAO,CAAC,wBAAwB;IAUhC;;OAEG;IACH,OAAO,CAAC,SAAS;IAIjB;;;;;;;;OAQG;IACH,OAAO,CAAC,YAAY;IAmCpB;;OAEG;IACH,OAAO,CAAC,iBAAiB;IA8EzB,OAAO,CAAC,eAAe;IAQvB,OAAO,CAAC,kBAAkB;IAQ1B;;;;;;OAMG;IACH,OAAO,CAAC,iBAAiB;IA2CzB;;;OAGG;IACH,OAAO,CAAC,sBAAsB;IAsC9B;;OAEG;YACW,kBAAkB;IA4DhC;;;OAGG;YACW,mBAAmB;IAoBjC;;;OAGG;IACH,OAAO,CAAC,8BAA8B;IAatC;;OAEG;YACW,UAAU;IAiBxB;;OAEG;YACW,cAAc;IAqC5B;;OAEG;IACG,YAAY,CAChB,KAAK,EAAE,MAAM,EACb,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,EACtC,WAAW,CAAC,EAAE,WAAW,EACzB,kBAAkB,UAAQ,GACzB,OAAO,CAAC,MAAM,CAAC;IAyRlB;;OAEG;YACW,eAAe;CA8H9B"}
|
package/dist/openai-client.js
CHANGED
|
@@ -19,6 +19,69 @@
|
|
|
19
19
|
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
20
20
|
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
21
21
|
import OpenAI from "openai";
|
|
22
|
+
import fs from "fs";
|
|
23
|
+
import path from "path";
|
|
24
|
+
// ── Privacy-safe input shape descriptor (logs types/lengths, never payload values) ── //
|
|
25
|
+
function describeShape(value, depth = 0) {
|
|
26
|
+
if (depth > 2)
|
|
27
|
+
return "…";
|
|
28
|
+
if (value === null || value === undefined)
|
|
29
|
+
return String(value);
|
|
30
|
+
if (typeof value === "string")
|
|
31
|
+
return `string(len=${value.length})`;
|
|
32
|
+
if (typeof value === "number" || typeof value === "boolean")
|
|
33
|
+
return typeof value;
|
|
34
|
+
if (Array.isArray(value))
|
|
35
|
+
return `array(len=${value.length})`;
|
|
36
|
+
if (typeof value === "object") {
|
|
37
|
+
const out = {};
|
|
38
|
+
for (const [k, v] of Object.entries(value)) {
|
|
39
|
+
out[k] = describeShape(v, depth + 1);
|
|
40
|
+
}
|
|
41
|
+
return out;
|
|
42
|
+
}
|
|
43
|
+
return typeof value;
|
|
44
|
+
}
|
|
45
|
+
// ── JSONL file logger — non-blocking fire-and-forget writes ── //
|
|
46
|
+
// INFO/WARN/ERROR go to mcp-client-YYYY-MM-DD.log (clean operational log)
|
|
47
|
+
// DEBUG goes to mcp-client-debug-YYYY-MM-DD.log (full payloads for reproduction)
|
|
48
|
+
// Log filenames are computed at write-time so files rotate at midnight.
|
|
49
|
+
class McpLogger {
|
|
50
|
+
constructor(logDir) {
|
|
51
|
+
let ready = false;
|
|
52
|
+
try {
|
|
53
|
+
fs.mkdirSync(logDir, { recursive: true });
|
|
54
|
+
ready = true;
|
|
55
|
+
}
|
|
56
|
+
catch (e) {
|
|
57
|
+
console.error("[McpLogger] Failed to open log dir:", logDir, e);
|
|
58
|
+
}
|
|
59
|
+
this.logDir = logDir;
|
|
60
|
+
this.ready = ready;
|
|
61
|
+
}
|
|
62
|
+
today() {
|
|
63
|
+
return new Date().toISOString().slice(0, 10); // YYYY-MM-DD recomputed each call
|
|
64
|
+
}
|
|
65
|
+
info(event, data = {}) {
|
|
66
|
+
this.write("INFO", event, data, path.join(this.logDir, `mcp-client-${this.today()}.log`));
|
|
67
|
+
}
|
|
68
|
+
warn(event, data = {}) {
|
|
69
|
+
this.write("WARN", event, data, path.join(this.logDir, `mcp-client-${this.today()}.log`));
|
|
70
|
+
}
|
|
71
|
+
error(event, data = {}) {
|
|
72
|
+
this.write("ERROR", event, data, path.join(this.logDir, `mcp-client-${this.today()}.log`));
|
|
73
|
+
}
|
|
74
|
+
/** Full-payload debug — written to the separate debug file only. */
|
|
75
|
+
debug(event, data = {}) {
|
|
76
|
+
this.write("DEBUG", event, data, path.join(this.logDir, `mcp-client-debug-${this.today()}.log`));
|
|
77
|
+
}
|
|
78
|
+
write(level, event, data, file) {
|
|
79
|
+
if (!this.ready)
|
|
80
|
+
return;
|
|
81
|
+
const line = JSON.stringify({ ts: new Date().toISOString(), level, event, ...data }) + "\n";
|
|
82
|
+
fs.appendFile(file, line, () => { }); // fire-and-forget
|
|
83
|
+
}
|
|
84
|
+
}
|
|
22
85
|
export class MCPClientOpenAI {
|
|
23
86
|
constructor(config) {
|
|
24
87
|
/**
|
|
@@ -74,7 +137,9 @@ export class MCPClientOpenAI {
|
|
|
74
137
|
compactTriggerInputTokens: config.compactTriggerInputTokens ?? 200000,
|
|
75
138
|
hotContextTargetInputTokens: config.hotContextTargetInputTokens ?? 100000,
|
|
76
139
|
maxToolOutputChars: config.maxToolOutputChars ?? 20000,
|
|
140
|
+
logDir: config.logDir ?? process.env.MCP_LOG_DIR ?? path.resolve(process.cwd(), "logs"),
|
|
77
141
|
};
|
|
142
|
+
this.logger = new McpLogger(this.config.logDir);
|
|
78
143
|
this.openai = new OpenAI({
|
|
79
144
|
apiKey: this.config.openaiApiKey,
|
|
80
145
|
});
|
|
@@ -94,11 +159,14 @@ export class MCPClientOpenAI {
|
|
|
94
159
|
}
|
|
95
160
|
async connect() {
|
|
96
161
|
await this.client.connect(this.transport);
|
|
162
|
+
this.logger.info("CLIENT_CONNECTED", { model: this.config.openaiModel });
|
|
97
163
|
}
|
|
98
164
|
async cleanup() {
|
|
165
|
+
this.logger.info("CLIENT_DISCONNECTED", {});
|
|
99
166
|
await this.client.close();
|
|
100
167
|
}
|
|
101
168
|
clearHistory() {
|
|
169
|
+
this.logger.info("HISTORY_CLEARED", {});
|
|
102
170
|
this.conversationHistory = [];
|
|
103
171
|
this.compaction = {
|
|
104
172
|
item: null,
|
|
@@ -420,6 +488,12 @@ export class MCPClientOpenAI {
|
|
|
420
488
|
if (this.compaction.item)
|
|
421
489
|
compactInput.push(this.compaction.item);
|
|
422
490
|
compactInput.push(...coldItems);
|
|
491
|
+
this.logger.debug("COMPACTION_REQUEST", {
|
|
492
|
+
model: this.config.openaiModel,
|
|
493
|
+
coldItemCount: coldItems.length,
|
|
494
|
+
hasPriorCompactionItem: !!this.compaction.item,
|
|
495
|
+
compactInput,
|
|
496
|
+
});
|
|
423
497
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
424
498
|
const response = await this.openai.responses.compact({
|
|
425
499
|
model: this.config.openaiModel,
|
|
@@ -435,6 +509,11 @@ export class MCPClientOpenAI {
|
|
|
435
509
|
if (newItem) {
|
|
436
510
|
this.compaction.item = newItem;
|
|
437
511
|
this.compaction.compactedTurns += this.getTurnBoundaries(coldItems).length;
|
|
512
|
+
this.logger.debug("COMPACTION_RESPONSE", {
|
|
513
|
+
newCompactionItem: newItem,
|
|
514
|
+
totalCompactedTurns: this.compaction.compactedTurns,
|
|
515
|
+
rawResponse: response,
|
|
516
|
+
});
|
|
438
517
|
}
|
|
439
518
|
else {
|
|
440
519
|
throw new Error("Compaction response did not include a reusable compaction item");
|
|
@@ -444,6 +523,10 @@ export class MCPClientOpenAI {
|
|
|
444
523
|
catch (error) {
|
|
445
524
|
// Fallback: if compaction fails, just drop the cold part rather than
|
|
446
525
|
// keeping everything and risking repeated context overflows.
|
|
526
|
+
this.logger.error("COMPACTION_FAILED", {
|
|
527
|
+
errorMessage: error instanceof Error ? error.message : String(error),
|
|
528
|
+
stack: error instanceof Error ? error.stack : undefined,
|
|
529
|
+
});
|
|
447
530
|
console.error("[MCPClient] Compaction failed, dropping cold history:", error);
|
|
448
531
|
}
|
|
449
532
|
}
|
|
@@ -499,6 +582,15 @@ export class MCPClientOpenAI {
|
|
|
499
582
|
* Create a response against the current full context.
|
|
500
583
|
*/
|
|
501
584
|
async createResponse(params) {
|
|
585
|
+
this.logger.debug("LLM_REQUEST", {
|
|
586
|
+
model: this.config.openaiModel,
|
|
587
|
+
instructionsLength: this.instructions?.length ?? 0,
|
|
588
|
+
instructions: this.instructions,
|
|
589
|
+
inputItems: params.input.length,
|
|
590
|
+
input: params.input,
|
|
591
|
+
toolNames: params.tools.map((t) => t.name ?? t.type),
|
|
592
|
+
previousResponseId: params.previousResponseId ?? null,
|
|
593
|
+
});
|
|
502
594
|
const response = await this.openai.responses.create({
|
|
503
595
|
model: this.config.openaiModel,
|
|
504
596
|
instructions: this.instructions ?? undefined,
|
|
@@ -509,6 +601,12 @@ export class MCPClientOpenAI {
|
|
|
509
601
|
truncation: "disabled",
|
|
510
602
|
prompt_cache_retention: "24h",
|
|
511
603
|
});
|
|
604
|
+
this.logger.debug("LLM_RESPONSE", {
|
|
605
|
+
responseId: response.id,
|
|
606
|
+
outputItems: (response.output ?? []).length,
|
|
607
|
+
output: response.output,
|
|
608
|
+
usage: response.usage,
|
|
609
|
+
});
|
|
512
610
|
this.captureUsage(response);
|
|
513
611
|
return response;
|
|
514
612
|
}
|
|
@@ -523,6 +621,7 @@ export class MCPClientOpenAI {
|
|
|
523
621
|
return this.processRawQuery(query, onThinking, abortSignal);
|
|
524
622
|
}
|
|
525
623
|
this.startTurn();
|
|
624
|
+
this.logger.info("QUERY_START", { queryShape: describeShape(query), bypassSystemPrompt });
|
|
526
625
|
await this.ensureSystemPrompt();
|
|
527
626
|
// Proactive compaction based on last real measured request.
|
|
528
627
|
await this.maybeCompactHistory();
|
|
@@ -568,6 +667,13 @@ export class MCPClientOpenAI {
|
|
|
568
667
|
}
|
|
569
668
|
catch (error) {
|
|
570
669
|
const err = error;
|
|
670
|
+
this.logger.warn("API_ERROR", {
|
|
671
|
+
status: err.status,
|
|
672
|
+
code: err.code,
|
|
673
|
+
message: err.message,
|
|
674
|
+
stack: error instanceof Error ? error.stack : undefined,
|
|
675
|
+
state: "ERROR_STATE",
|
|
676
|
+
});
|
|
571
677
|
const message = err.message?.toLowerCase() || "";
|
|
572
678
|
const contextProblem = err.status === 400 &&
|
|
573
679
|
(err.code === "context_length_exceeded" ||
|
|
@@ -612,6 +718,13 @@ export class MCPClientOpenAI {
|
|
|
612
718
|
}
|
|
613
719
|
}
|
|
614
720
|
else {
|
|
721
|
+
this.logger.error("API_ERROR_UNHANDLED", {
|
|
722
|
+
status: err.status,
|
|
723
|
+
code: err.code,
|
|
724
|
+
message: err.message,
|
|
725
|
+
stack: error instanceof Error ? error.stack : undefined,
|
|
726
|
+
state: "FATAL",
|
|
727
|
+
});
|
|
615
728
|
throw error;
|
|
616
729
|
}
|
|
617
730
|
}
|
|
@@ -648,17 +761,39 @@ export class MCPClientOpenAI {
|
|
|
648
761
|
toolDesc = `web_search → "${functionArgs.query}"`;
|
|
649
762
|
}
|
|
650
763
|
onThinking?.(`🔧 ${toolDesc}`);
|
|
764
|
+
this.logger.info("TOOL_CALL_SENDING", {
|
|
765
|
+
tool: functionName,
|
|
766
|
+
inputShape: describeShape(functionArgs),
|
|
767
|
+
state: "SENDING",
|
|
768
|
+
});
|
|
769
|
+
this.logger.debug("TOOL_CALL_FULL_ARGS", {
|
|
770
|
+
tool: functionName,
|
|
771
|
+
arguments: functionArgs,
|
|
772
|
+
});
|
|
651
773
|
try {
|
|
652
774
|
const result = await this.client.callTool({
|
|
653
775
|
name: functionName,
|
|
654
776
|
arguments: functionArgs,
|
|
655
777
|
});
|
|
656
778
|
const compactOutput = this.compactToolResult(result.content);
|
|
779
|
+
this.logger.info("TOOL_CALL_SUCCESS", { tool: functionName, state: "RECEIVED" });
|
|
780
|
+
this.logger.debug("TOOL_CALL_FULL_RESULT", {
|
|
781
|
+
tool: functionName,
|
|
782
|
+
result: result.content,
|
|
783
|
+
});
|
|
657
784
|
const toolOutputItem = this.makeFunctionOutput(functionCall.call_id, compactOutput);
|
|
658
785
|
toolOutputsForNextStep.push(toolOutputItem);
|
|
659
786
|
this.conversationHistory.push(toolOutputItem);
|
|
660
787
|
}
|
|
661
788
|
catch (error) {
|
|
789
|
+
this.logger.error("TOOL_CALL_ERROR", {
|
|
790
|
+
tool: functionName,
|
|
791
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
792
|
+
errorCode: error?.code ?? error?.name ?? "UNKNOWN",
|
|
793
|
+
errorMessage: error instanceof Error ? error.message : String(error),
|
|
794
|
+
stack: error instanceof Error ? error.stack : undefined,
|
|
795
|
+
state: "ERROR_STATE",
|
|
796
|
+
});
|
|
662
797
|
const toolOutputItem = this.makeFunctionOutput(functionCall.call_id, `Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
663
798
|
toolOutputsForNextStep.push(toolOutputItem);
|
|
664
799
|
this.conversationHistory.push(toolOutputItem);
|
|
@@ -677,7 +812,12 @@ export class MCPClientOpenAI {
|
|
|
677
812
|
}
|
|
678
813
|
}
|
|
679
814
|
}
|
|
815
|
+
this.logger.info("QUERY_COMPLETE", { loops: loopCount, responseLength: finalResponse.length });
|
|
680
816
|
this.conversationHistory.push(...output);
|
|
817
|
+
this.logger.debug("CONVERSATION_HISTORY_SNAPSHOT", {
|
|
818
|
+
itemCount: this.conversationHistory.length,
|
|
819
|
+
history: this.conversationHistory,
|
|
820
|
+
});
|
|
681
821
|
break;
|
|
682
822
|
}
|
|
683
823
|
if (loopCount >= maxLoops && !finalResponse) {
|
|
@@ -730,14 +870,13 @@ export class MCPClientOpenAI {
|
|
|
730
870
|
loopCount++;
|
|
731
871
|
if (abortSignal?.aborted)
|
|
732
872
|
throw new Error("Request was cancelled");
|
|
873
|
+
const rawInput = (!previousResponseId ? isolatedHistory : (pendingRawToolOutputs ?? []));
|
|
874
|
+
this.logger.info("QUERY_START", { queryShape: describeShape(rawInput), bypassSystemPrompt: true });
|
|
733
875
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
734
|
-
const response = await this.
|
|
735
|
-
|
|
736
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
737
|
-
input: (!previousResponseId ? isolatedHistory : (pendingRawToolOutputs ?? [])),
|
|
738
|
-
previous_response_id: previousResponseId,
|
|
876
|
+
const response = await this.createResponse({
|
|
877
|
+
input: rawInput,
|
|
739
878
|
tools,
|
|
740
|
-
|
|
879
|
+
previousResponseId,
|
|
741
880
|
});
|
|
742
881
|
pendingRawToolOutputs = null;
|
|
743
882
|
this.captureUsage(response);
|
|
@@ -771,14 +910,36 @@ export class MCPClientOpenAI {
|
|
|
771
910
|
toolDesc = `web_search → "${functionArgs.query}"`;
|
|
772
911
|
}
|
|
773
912
|
onThinking?.(`🔧 ${toolDesc}`);
|
|
913
|
+
this.logger.info("TOOL_CALL_SENDING", {
|
|
914
|
+
tool: functionName,
|
|
915
|
+
inputShape: describeShape(functionArgs),
|
|
916
|
+
state: "SENDING",
|
|
917
|
+
});
|
|
918
|
+
this.logger.debug("TOOL_CALL_FULL_ARGS", {
|
|
919
|
+
tool: functionName,
|
|
920
|
+
arguments: functionArgs,
|
|
921
|
+
});
|
|
774
922
|
try {
|
|
775
923
|
const result = await this.client.callTool({
|
|
776
924
|
name: functionName,
|
|
777
925
|
arguments: functionArgs,
|
|
778
926
|
});
|
|
927
|
+
this.logger.info("TOOL_CALL_SUCCESS", { tool: functionName, state: "RECEIVED" });
|
|
928
|
+
this.logger.debug("TOOL_CALL_FULL_RESULT", {
|
|
929
|
+
tool: functionName,
|
|
930
|
+
result: result.content,
|
|
931
|
+
});
|
|
779
932
|
newToolOutputs.push(this.makeFunctionOutput(functionCall.call_id, this.compactToolResult(result.content)));
|
|
780
933
|
}
|
|
781
934
|
catch (error) {
|
|
935
|
+
this.logger.error("TOOL_CALL_ERROR", {
|
|
936
|
+
tool: functionName,
|
|
937
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
938
|
+
errorCode: error?.code ?? error?.name ?? "UNKNOWN",
|
|
939
|
+
errorMessage: error instanceof Error ? error.message : String(error),
|
|
940
|
+
stack: error instanceof Error ? error.stack : undefined,
|
|
941
|
+
state: "ERROR_STATE",
|
|
942
|
+
});
|
|
782
943
|
newToolOutputs.push(this.makeFunctionOutput(functionCall.call_id, `Error: ${error instanceof Error ? error.message : String(error)}`));
|
|
783
944
|
}
|
|
784
945
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nqminds/mcp-client",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.21",
|
|
4
4
|
"description": "Reusable MCP client component with AI chat interface",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -47,6 +47,7 @@
|
|
|
47
47
|
},
|
|
48
48
|
"dependencies": {
|
|
49
49
|
"@modelcontextprotocol/sdk": "^1.0.4",
|
|
50
|
+
"@types/node": "^20.0.0",
|
|
50
51
|
"openai": "^6.15.0"
|
|
51
52
|
},
|
|
52
53
|
"devDependencies": {
|