fdic-mcp-server 1.7.0 → 1.7.1

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/index.js CHANGED
@@ -32,7 +32,7 @@ var import_types = require("@modelcontextprotocol/sdk/types.js");
32
32
  var import_express2 = __toESM(require("express"));
33
33
 
34
34
  // src/constants.ts
35
- var VERSION = true ? "1.7.0" : process.env.npm_package_version ?? "0.0.0-dev";
35
+ var VERSION = true ? "1.7.1" : process.env.npm_package_version ?? "0.0.0-dev";
36
36
  var FDIC_API_BASE_URL = "https://banks.data.fdic.gov/api";
37
37
  var CHARACTER_LIMIT = 5e4;
38
38
  var DEFAULT_FDIC_MAX_RESPONSE_BYTES = 5 * 1024 * 1024;
@@ -95,6 +95,7 @@ var DEFAULT_CHAT_RATE_LIMIT_WINDOW_MS = 6e4;
95
95
  var DEFAULT_CHAT_MAX_MESSAGES = 20;
96
96
  var DEFAULT_CHAT_MAX_MESSAGE_LENGTH = 500;
97
97
  var DEFAULT_CHAT_MAX_TOOL_ROUNDS = 5;
98
+ var DEFAULT_CHAT_GENERATE_RETRIES = 2;
98
99
  var genAIModulePromise;
99
100
  function loadGenAIModule() {
100
101
  genAIModulePromise ??= import("@google/genai");
@@ -202,6 +203,62 @@ function getResponseParts(response) {
202
203
  function getResponseText(response) {
203
204
  return response.text?.trim() || void 0;
204
205
  }
206
+ function wait(ms) {
207
+ return new Promise((resolve) => {
208
+ setTimeout(resolve, ms);
209
+ });
210
+ }
211
+ function getErrorCode(error) {
212
+ if (!error || typeof error !== "object") {
213
+ return void 0;
214
+ }
215
+ const record = error;
216
+ const candidate = record.status ?? record.statusCode ?? record.code;
217
+ return typeof candidate === "number" || typeof candidate === "string" ? candidate : void 0;
218
+ }
219
+ function isTransientChatError(error) {
220
+ const code = getErrorCode(error);
221
+ if (code === 408 || code === 409 || code === 425 || code === 429 || code === 500 || code === 502 || code === 503 || code === 504) {
222
+ return true;
223
+ }
224
+ if (code === "ABORTED" || code === "DEADLINE_EXCEEDED" || code === "INTERNAL" || code === "RESOURCE_EXHAUSTED" || code === "UNAVAILABLE") {
225
+ return true;
226
+ }
227
+ const message = error instanceof Error ? error.message : String(error ?? "");
228
+ return /timeout|temporar|unavailable|overloaded|internal|deadline/i.test(
229
+ message
230
+ );
231
+ }
232
+ function logChatFailure(context) {
233
+ const { error } = context;
234
+ console.error(
235
+ JSON.stringify({
236
+ event: "chat_request_failed",
237
+ sessionId: context.sessionId,
238
+ requestIp: context.requestIp,
239
+ messageCount: context.messageCount,
240
+ model: context.model,
241
+ errorName: error instanceof Error ? error.name : void 0,
242
+ errorMessage: error instanceof Error ? error.message : String(error ?? "unknown"),
243
+ errorCode: getErrorCode(error),
244
+ stack: error instanceof Error ? error.stack : void 0
245
+ })
246
+ );
247
+ }
248
+ async function generateContentWithRetry(ai, request) {
249
+ let attempt = 0;
250
+ while (true) {
251
+ try {
252
+ return await ai.models.generateContent(request);
253
+ } catch (error) {
254
+ if (attempt >= DEFAULT_CHAT_GENERATE_RETRIES || !isTransientChatError(error)) {
255
+ throw error;
256
+ }
257
+ attempt += 1;
258
+ await wait(150 * attempt);
259
+ }
260
+ }
261
+ }
205
262
  async function executeToolCall(server, name, args) {
206
263
  const callTool = getToolCallHandler(server);
207
264
  const result = await callTool(
@@ -235,7 +292,7 @@ async function runConversation(ai, model, functionDeclarations, server, history)
235
292
  } = await loadGenAIModule();
236
293
  const contents = [...history];
237
294
  for (let round = 0; round < DEFAULT_CHAT_MAX_TOOL_ROUNDS; round += 1) {
238
- const response = await ai.models.generateContent({
295
+ const response = await generateContentWithRetry(ai, {
239
296
  model,
240
297
  contents,
241
298
  config: {
@@ -361,6 +418,13 @@ function createChatRouter(options) {
361
418
  reply: conversation.reply
362
419
  });
363
420
  } catch (error) {
421
+ logChatFailure({
422
+ sessionId,
423
+ requestIp,
424
+ messageCount: validationResult.length,
425
+ model,
426
+ error
427
+ });
364
428
  const message = error instanceof Error ? error.message : "Failed to process chat request";
365
429
  const status = message === "Chat tool-call limit exceeded" ? 502 : 500;
366
430
  res.status(status).json({ error: message });
package/dist/server.js CHANGED
@@ -46,7 +46,7 @@ var import_types = require("@modelcontextprotocol/sdk/types.js");
46
46
  var import_express2 = __toESM(require("express"));
47
47
 
48
48
  // src/constants.ts
49
- var VERSION = true ? "1.7.0" : process.env.npm_package_version ?? "0.0.0-dev";
49
+ var VERSION = true ? "1.7.1" : process.env.npm_package_version ?? "0.0.0-dev";
50
50
  var FDIC_API_BASE_URL = "https://banks.data.fdic.gov/api";
51
51
  var CHARACTER_LIMIT = 5e4;
52
52
  var DEFAULT_FDIC_MAX_RESPONSE_BYTES = 5 * 1024 * 1024;
@@ -109,6 +109,7 @@ var DEFAULT_CHAT_RATE_LIMIT_WINDOW_MS = 6e4;
109
109
  var DEFAULT_CHAT_MAX_MESSAGES = 20;
110
110
  var DEFAULT_CHAT_MAX_MESSAGE_LENGTH = 500;
111
111
  var DEFAULT_CHAT_MAX_TOOL_ROUNDS = 5;
112
+ var DEFAULT_CHAT_GENERATE_RETRIES = 2;
112
113
  var genAIModulePromise;
113
114
  function loadGenAIModule() {
114
115
  genAIModulePromise ??= import("@google/genai");
@@ -216,6 +217,62 @@ function getResponseParts(response) {
216
217
  function getResponseText(response) {
217
218
  return response.text?.trim() || void 0;
218
219
  }
220
+ function wait(ms) {
221
+ return new Promise((resolve) => {
222
+ setTimeout(resolve, ms);
223
+ });
224
+ }
225
+ function getErrorCode(error) {
226
+ if (!error || typeof error !== "object") {
227
+ return void 0;
228
+ }
229
+ const record = error;
230
+ const candidate = record.status ?? record.statusCode ?? record.code;
231
+ return typeof candidate === "number" || typeof candidate === "string" ? candidate : void 0;
232
+ }
233
+ function isTransientChatError(error) {
234
+ const code = getErrorCode(error);
235
+ if (code === 408 || code === 409 || code === 425 || code === 429 || code === 500 || code === 502 || code === 503 || code === 504) {
236
+ return true;
237
+ }
238
+ if (code === "ABORTED" || code === "DEADLINE_EXCEEDED" || code === "INTERNAL" || code === "RESOURCE_EXHAUSTED" || code === "UNAVAILABLE") {
239
+ return true;
240
+ }
241
+ const message = error instanceof Error ? error.message : String(error ?? "");
242
+ return /timeout|temporar|unavailable|overloaded|internal|deadline/i.test(
243
+ message
244
+ );
245
+ }
246
+ function logChatFailure(context) {
247
+ const { error } = context;
248
+ console.error(
249
+ JSON.stringify({
250
+ event: "chat_request_failed",
251
+ sessionId: context.sessionId,
252
+ requestIp: context.requestIp,
253
+ messageCount: context.messageCount,
254
+ model: context.model,
255
+ errorName: error instanceof Error ? error.name : void 0,
256
+ errorMessage: error instanceof Error ? error.message : String(error ?? "unknown"),
257
+ errorCode: getErrorCode(error),
258
+ stack: error instanceof Error ? error.stack : void 0
259
+ })
260
+ );
261
+ }
262
+ async function generateContentWithRetry(ai, request) {
263
+ let attempt = 0;
264
+ while (true) {
265
+ try {
266
+ return await ai.models.generateContent(request);
267
+ } catch (error) {
268
+ if (attempt >= DEFAULT_CHAT_GENERATE_RETRIES || !isTransientChatError(error)) {
269
+ throw error;
270
+ }
271
+ attempt += 1;
272
+ await wait(150 * attempt);
273
+ }
274
+ }
275
+ }
219
276
  async function executeToolCall(server, name, args) {
220
277
  const callTool = getToolCallHandler(server);
221
278
  const result = await callTool(
@@ -249,7 +306,7 @@ async function runConversation(ai, model, functionDeclarations, server, history)
249
306
  } = await loadGenAIModule();
250
307
  const contents = [...history];
251
308
  for (let round = 0; round < DEFAULT_CHAT_MAX_TOOL_ROUNDS; round += 1) {
252
- const response = await ai.models.generateContent({
309
+ const response = await generateContentWithRetry(ai, {
253
310
  model,
254
311
  contents,
255
312
  config: {
@@ -375,6 +432,13 @@ function createChatRouter(options) {
375
432
  reply: conversation.reply
376
433
  });
377
434
  } catch (error) {
435
+ logChatFailure({
436
+ sessionId,
437
+ requestIp,
438
+ messageCount: validationResult.length,
439
+ model,
440
+ error
441
+ });
378
442
  const message = error instanceof Error ? error.message : "Failed to process chat request";
379
443
  const status = message === "Chat tool-call limit exceeded" ? 502 : 500;
380
444
  res.status(status).json({ error: message });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fdic-mcp-server",
3
- "version": "1.7.0",
3
+ "version": "1.7.1",
4
4
  "description": "MCP server for the FDIC BankFind Suite API",
5
5
  "mcpName": "io.github.jflamb/fdic-mcp-server",
6
6
  "main": "dist/server.js",