@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 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
- console.log("Request was cancelled");
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": "Open AI assistant", title: "Open AI assistant" }, "\uD83E\uDD16")),
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" },
@@ -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;CACtB;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,sBAAsB,IACnD,SAAS,OAAO,uBAmH/B;AAED;;GAEG;AACH,wBAAgB,qBAAqB,KACrB,SAAS,OAAO,uBAU/B;AAED;;GAEG;AACH,wBAAsB,iBAAiB,kBAKtC"}
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"}
@@ -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.log("Client disconnected, aborting server processing");
100
+ console.error("Client disconnected, aborting server processing");
100
101
  abortController.abort();
101
102
  }
102
103
  });
@@ -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;AAMH,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;CAC7B;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;gBAE9B,MAAM,EAAE,eAAe;IAoC7B,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAIxB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAI9B,YAAY,IAAI,IAAI;IAkBpB,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;IA4ChC;;;OAGG;YACW,mBAAmB;IAoBjC;;;OAGG;IACH,OAAO,CAAC,8BAA8B;IAatC;;OAEG;YACW,UAAU;IAiBxB;;OAEG;YACW,cAAc;IAoB5B;;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;IA8OlB;;OAEG;YACW,eAAe;CAyG9B"}
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"}
@@ -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.openai.responses.create({
735
- model: this.config.openaiModel,
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
- truncation: "disabled",
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.14",
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": {