@wisewandtools/mcp-server 2.1.2 → 2.2.0

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.d.ts CHANGED
@@ -311,14 +311,6 @@ declare class WisewandMCPServer {
311
311
  getPromptCount(): number;
312
312
  getHealth(): HealthStatus | null;
313
313
  getMetrics(): Promise<string>;
314
- /**
315
- * Test API connection during startup
316
- * Returns {ok: boolean, error?: string}
317
- */
318
- testAPIConnection(): Promise<{
319
- ok: boolean;
320
- error?: string;
321
- }>;
322
314
  }
323
315
 
324
316
  export { WisewandMCPServer };
package/dist/index.js CHANGED
@@ -134,11 +134,12 @@ var parseConfig = /* @__PURE__ */ __name(() => {
134
134
  strategy: process.env.CACHE_STRATEGY
135
135
  },
136
136
  monitoring: {
137
- enableMetrics: process.env.ENABLE_METRICS !== "false",
137
+ // Default metrics and health check to false in MCP stdio mode (no port binding needed)
138
+ enableMetrics: process.env.ENABLE_METRICS === "true" ? true : process.env.ENABLE_METRICS === "false" ? false : process.env.MCP_MODE !== "stdio",
138
139
  metricsPort: process.env.METRICS_PORT ? parseInt(process.env.METRICS_PORT) : void 0,
139
140
  enableTracing: process.env.ENABLE_TRACING === "true",
140
141
  tracingEndpoint: process.env.TRACING_ENDPOINT,
141
- enableHealthCheck: process.env.ENABLE_HEALTH_CHECK !== "false",
142
+ enableHealthCheck: process.env.ENABLE_HEALTH_CHECK === "true" ? true : process.env.ENABLE_HEALTH_CHECK === "false" ? false : process.env.MCP_MODE !== "stdio",
142
143
  healthCheckInterval: process.env.HEALTH_CHECK_INTERVAL ? parseInt(process.env.HEALTH_CHECK_INTERVAL) : void 0
143
144
  },
144
145
  features: {
@@ -264,13 +265,11 @@ var WisewandAPIClient = class {
264
265
  "User-Agent": "Wisewand-MCP/1.0.0",
265
266
  "Accept": "application/json"
266
267
  };
267
- this.abortController = new AbortController();
268
268
  }
269
269
  static {
270
270
  __name(this, "WisewandAPIClient");
271
271
  }
272
272
  headers;
273
- abortController;
274
273
  /**
275
274
  * Make HTTP request with retry logic
276
275
  */
@@ -278,25 +277,18 @@ var WisewandAPIClient = class {
278
277
  const url = `${this.config.apiUrl}${endpoint}`;
279
278
  return pRetry(
280
279
  async () => {
280
+ const abortController = new AbortController();
281
281
  const timeoutId = setTimeout(() => {
282
- this.abortController.abort();
282
+ abortController.abort();
283
283
  }, this.config.timeout);
284
284
  try {
285
285
  const bodyJSON = body ? JSON.stringify(body) : void 0;
286
- logger.info("API HTTP REQUEST - EXACT JSON", {
287
- method,
288
- endpoint,
289
- url,
290
- bodyJSON,
291
- // The EXACT string being sent over HTTP
292
- body_includes_apply_project_brief_config: bodyJSON?.includes("apply_project_brief_config"),
293
- body_apply_project_brief_config_value: bodyJSON?.match(/"apply_project_brief_config":(true|false)/)?.[1]
294
- });
286
+ logger.debug("API request", { method, endpoint, url });
295
287
  const response = await fetch(url, {
296
288
  method,
297
289
  headers: this.headers,
298
290
  body: bodyJSON,
299
- signal: this.abortController.signal,
291
+ signal: abortController.signal,
300
292
  ...options
301
293
  });
302
294
  clearTimeout(timeoutId);
@@ -310,7 +302,6 @@ var WisewandAPIClient = class {
310
302
  } catch (error) {
311
303
  clearTimeout(timeoutId);
312
304
  if (error instanceof Error && error.name === "AbortError") {
313
- this.abortController = new AbortController();
314
305
  throw new Error(`Request timeout after ${this.config.timeout}ms`);
315
306
  }
316
307
  throw error;
@@ -617,7 +608,6 @@ var APIError = class extends Error {
617
608
 
618
609
  // src/services/CacheManager.ts
619
610
  import NodeCache from "node-cache";
620
- import Redis from "ioredis";
621
611
  var CacheManager = class {
622
612
  constructor(config2, redisConfig) {
623
613
  this.config = config2;
@@ -644,6 +634,20 @@ var CacheManager = class {
644
634
  });
645
635
  }
646
636
  if ((this.strategy === "redis" || this.strategy === "hybrid") && this.redisConfig) {
637
+ this.initRedis();
638
+ }
639
+ }
640
+ static {
641
+ __name(this, "CacheManager");
642
+ }
643
+ memoryCache;
644
+ redisClient;
645
+ enabled;
646
+ strategy;
647
+ defaultTTL;
648
+ async initRedis() {
649
+ try {
650
+ const { default: Redis } = await import("ioredis");
647
651
  this.redisClient = new Redis({
648
652
  host: this.redisConfig.host,
649
653
  port: this.redisConfig.port,
@@ -664,16 +668,20 @@ var CacheManager = class {
664
668
  this.redisClient.on("error", (error) => {
665
669
  logger.error("Redis cache error", error);
666
670
  });
671
+ } catch (error) {
672
+ logger.warn("Failed to load ioredis, falling back to memory-only cache", { error });
673
+ this.strategy = "memory";
674
+ if (!this.memoryCache) {
675
+ this.memoryCache = new NodeCache({
676
+ stdTTL: this.defaultTTL,
677
+ checkperiod: 120,
678
+ useClones: false,
679
+ deleteOnExpire: true,
680
+ maxKeys: Math.floor(this.config.maxSizeMB * 1e3)
681
+ });
682
+ }
667
683
  }
668
684
  }
669
- static {
670
- __name(this, "CacheManager");
671
- }
672
- memoryCache;
673
- redisClient;
674
- enabled;
675
- strategy;
676
- defaultTTL;
677
685
  async get(key) {
678
686
  if (!this.enabled) return null;
679
687
  try {
@@ -869,8 +877,6 @@ var RateLimiter = class {
869
877
  };
870
878
 
871
879
  // src/monitoring/MetricsCollector.ts
872
- import { Counter, Histogram, Gauge, Registry, collectDefaultMetrics } from "prom-client";
873
- import express from "express";
874
880
  var MetricsCollector = class {
875
881
  static {
876
882
  __name(this, "MetricsCollector");
@@ -878,7 +884,8 @@ var MetricsCollector = class {
878
884
  registry;
879
885
  app;
880
886
  server;
881
- // Metrics
887
+ enabled;
888
+ // Metrics (only initialized when enabled)
882
889
  toolCallCounter;
883
890
  toolCallDuration;
884
891
  apiCallCounter;
@@ -887,116 +894,156 @@ var MetricsCollector = class {
887
894
  cacheMissCounter;
888
895
  activeConnections;
889
896
  errorCounter;
890
- constructor() {
891
- this.registry = new Registry();
892
- collectDefaultMetrics({ register: this.registry });
893
- this.toolCallCounter = new Counter({
894
- name: "mcp_tool_calls_total",
895
- help: "Total number of tool calls",
896
- labelNames: ["tool", "status"],
897
- registers: [this.registry]
898
- });
899
- this.toolCallDuration = new Histogram({
900
- name: "mcp_tool_call_duration_ms",
901
- help: "Tool call duration in milliseconds",
902
- labelNames: ["tool"],
903
- buckets: [10, 50, 100, 500, 1e3, 5e3, 1e4],
904
- registers: [this.registry]
905
- });
906
- this.apiCallCounter = new Counter({
907
- name: "wisewand_api_calls_total",
908
- help: "Total number of Wisewand API calls",
909
- labelNames: ["endpoint", "status"],
910
- registers: [this.registry]
911
- });
912
- this.apiCallDuration = new Histogram({
913
- name: "wisewand_api_call_duration_ms",
914
- help: "Wisewand API call duration in milliseconds",
915
- labelNames: ["endpoint"],
916
- buckets: [100, 500, 1e3, 2e3, 5e3, 1e4, 3e4],
917
- registers: [this.registry]
918
- });
919
- this.cacheHitCounter = new Counter({
920
- name: "cache_hits_total",
921
- help: "Total number of cache hits",
922
- labelNames: ["cache_type"],
923
- registers: [this.registry]
924
- });
925
- this.cacheMissCounter = new Counter({
926
- name: "cache_misses_total",
927
- help: "Total number of cache misses",
928
- labelNames: ["cache_type"],
929
- registers: [this.registry]
930
- });
931
- this.activeConnections = new Gauge({
932
- name: "mcp_active_connections",
933
- help: "Number of active MCP connections",
934
- registers: [this.registry]
935
- });
936
- this.errorCounter = new Counter({
937
- name: "mcp_errors_total",
938
- help: "Total number of errors",
939
- labelNames: ["type", "source"],
940
- registers: [this.registry]
941
- });
942
- logger.info("Metrics collector initialized");
897
+ constructor(enabled = true) {
898
+ this.enabled = enabled;
899
+ if (!this.enabled) {
900
+ logger.info("Metrics collector disabled");
901
+ return;
902
+ }
903
+ }
904
+ async init() {
905
+ if (!this.enabled) return;
906
+ try {
907
+ const { Counter, Histogram, Gauge, Registry, collectDefaultMetrics } = await import("prom-client");
908
+ this.registry = new Registry();
909
+ collectDefaultMetrics({ register: this.registry });
910
+ this.toolCallCounter = new Counter({
911
+ name: "mcp_tool_calls_total",
912
+ help: "Total number of tool calls",
913
+ labelNames: ["tool", "status"],
914
+ registers: [this.registry]
915
+ });
916
+ this.toolCallDuration = new Histogram({
917
+ name: "mcp_tool_call_duration_ms",
918
+ help: "Tool call duration in milliseconds",
919
+ labelNames: ["tool"],
920
+ buckets: [10, 50, 100, 500, 1e3, 5e3, 1e4],
921
+ registers: [this.registry]
922
+ });
923
+ this.apiCallCounter = new Counter({
924
+ name: "wisewand_api_calls_total",
925
+ help: "Total number of Wisewand API calls",
926
+ labelNames: ["endpoint", "status"],
927
+ registers: [this.registry]
928
+ });
929
+ this.apiCallDuration = new Histogram({
930
+ name: "wisewand_api_call_duration_ms",
931
+ help: "Wisewand API call duration in milliseconds",
932
+ labelNames: ["endpoint"],
933
+ buckets: [100, 500, 1e3, 2e3, 5e3, 1e4, 3e4],
934
+ registers: [this.registry]
935
+ });
936
+ this.cacheHitCounter = new Counter({
937
+ name: "cache_hits_total",
938
+ help: "Total number of cache hits",
939
+ labelNames: ["cache_type"],
940
+ registers: [this.registry]
941
+ });
942
+ this.cacheMissCounter = new Counter({
943
+ name: "cache_misses_total",
944
+ help: "Total number of cache misses",
945
+ labelNames: ["cache_type"],
946
+ registers: [this.registry]
947
+ });
948
+ this.activeConnections = new Gauge({
949
+ name: "mcp_active_connections",
950
+ help: "Number of active MCP connections",
951
+ registers: [this.registry]
952
+ });
953
+ this.errorCounter = new Counter({
954
+ name: "mcp_errors_total",
955
+ help: "Total number of errors",
956
+ labelNames: ["type", "source"],
957
+ registers: [this.registry]
958
+ });
959
+ logger.info("Metrics collector initialized");
960
+ } catch (error) {
961
+ logger.warn("Failed to initialize metrics collector, disabling", { error });
962
+ this.enabled = false;
963
+ }
943
964
  }
944
965
  recordToolCall(tool, status, durationMs) {
945
- this.toolCallCounter.inc({ tool, status });
946
- this.toolCallDuration.observe({ tool }, durationMs);
966
+ if (!this.enabled) return;
967
+ this.toolCallCounter?.inc({ tool, status });
968
+ this.toolCallDuration?.observe({ tool }, durationMs);
947
969
  }
948
970
  recordAPICall(endpoint, status, durationMs) {
949
- this.apiCallCounter.inc({ endpoint, status });
971
+ if (!this.enabled) return;
972
+ this.apiCallCounter?.inc({ endpoint, status });
950
973
  if (durationMs) {
951
- this.apiCallDuration.observe({ endpoint }, durationMs);
974
+ this.apiCallDuration?.observe({ endpoint }, durationMs);
952
975
  }
953
976
  }
954
977
  recordCacheHit(cacheType = "memory") {
955
- this.cacheHitCounter.inc({ cache_type: cacheType });
978
+ if (!this.enabled) return;
979
+ this.cacheHitCounter?.inc({ cache_type: cacheType });
956
980
  }
957
981
  recordCacheMiss(cacheType = "memory") {
958
- this.cacheMissCounter.inc({ cache_type: cacheType });
982
+ if (!this.enabled) return;
983
+ this.cacheMissCounter?.inc({ cache_type: cacheType });
959
984
  }
960
985
  setActiveConnections(count) {
961
- this.activeConnections.set(count);
986
+ if (!this.enabled) return;
987
+ this.activeConnections?.set(count);
962
988
  }
963
989
  incrementActiveConnections() {
964
- this.activeConnections.inc();
990
+ if (!this.enabled) return;
991
+ this.activeConnections?.inc();
965
992
  }
966
993
  decrementActiveConnections() {
967
- this.activeConnections.dec();
994
+ if (!this.enabled) return;
995
+ this.activeConnections?.dec();
968
996
  }
969
997
  recordError(type, source) {
970
- this.errorCounter.inc({ type, source });
998
+ if (!this.enabled) return;
999
+ this.errorCounter?.inc({ type, source });
971
1000
  }
972
1001
  async getMetrics() {
1002
+ if (!this.enabled || !this.registry) return "";
973
1003
  return await this.registry.metrics();
974
1004
  }
975
1005
  getMetricsContentType() {
1006
+ if (!this.enabled || !this.registry) return "text/plain";
976
1007
  return this.registry.contentType;
977
1008
  }
978
- startServer(port) {
1009
+ async startServer(port) {
1010
+ if (!this.enabled) return;
979
1011
  if (this.server) {
980
1012
  logger.warn("Metrics server already running");
981
1013
  return;
982
1014
  }
983
- this.app = express();
984
- this.app.get("/health", (_req, res) => {
985
- res.status(200).json({ status: "healthy" });
986
- });
987
- this.app.get("/metrics", async (_req, res) => {
988
- try {
989
- res.set("Content-Type", this.getMetricsContentType());
990
- const metrics = await this.getMetrics();
991
- res.end(metrics);
992
- } catch (error) {
993
- logger.error("Error collecting metrics", error);
994
- res.status(500).end();
1015
+ try {
1016
+ if (!this.registry) {
1017
+ await this.init();
995
1018
  }
996
- });
997
- this.server = this.app.listen(port, () => {
998
- logger.info(`Metrics server started on port ${port}`);
999
- });
1019
+ if (!this.enabled) return;
1020
+ const express = (await import("express")).default;
1021
+ this.app = express();
1022
+ this.app.get("/health", (_req, res) => {
1023
+ res.status(200).json({ status: "healthy" });
1024
+ });
1025
+ this.app.get("/metrics", async (_req, res) => {
1026
+ try {
1027
+ res.set("Content-Type", this.getMetricsContentType());
1028
+ const metrics = await this.getMetrics();
1029
+ res.end(metrics);
1030
+ } catch (error) {
1031
+ logger.error("Error collecting metrics", error);
1032
+ res.status(500).end();
1033
+ }
1034
+ });
1035
+ this.server = this.app.listen(port, () => {
1036
+ logger.info(`Metrics server started on port ${port}`);
1037
+ });
1038
+ this.server.on("error", (error) => {
1039
+ logger.error(`Metrics server failed to bind port ${port}`, { error: error.message, code: error.code });
1040
+ this.server = void 0;
1041
+ this.enabled = false;
1042
+ });
1043
+ } catch (error) {
1044
+ logger.error("Failed to start metrics server", { error });
1045
+ this.enabled = false;
1046
+ }
1000
1047
  }
1001
1048
  async stopServer() {
1002
1049
  if (this.server) {
@@ -1009,6 +1056,7 @@ var MetricsCollector = class {
1009
1056
  }
1010
1057
  }
1011
1058
  reset() {
1059
+ if (!this.enabled || !this.registry) return;
1012
1060
  this.registry.clear();
1013
1061
  }
1014
1062
  };
@@ -6097,7 +6145,7 @@ var WisewandMCPServer = class {
6097
6145
  this.apiClient = new WisewandAPIClient(config2.wisewand);
6098
6146
  this.cacheManager = new CacheManager(config2.cache);
6099
6147
  this.rateLimiter = new RateLimiter(config2.security);
6100
- this.metrics = new MetricsCollector();
6148
+ this.metrics = new MetricsCollector(config2.monitoring.enableMetrics);
6101
6149
  this.healthChecker = new HealthChecker(this.apiClient, this.cacheManager);
6102
6150
  this.articleHandler = new ArticleToolHandler(this.apiClient, this.cacheManager, this.metrics);
6103
6151
  this.projectHandler = new ProjectToolHandler(this.apiClient, this.cacheManager, this.metrics);
@@ -6289,32 +6337,9 @@ var WisewandMCPServer = class {
6289
6337
  getMetrics() {
6290
6338
  return this.metrics.getMetrics();
6291
6339
  }
6292
- /**
6293
- * Test API connection during startup
6294
- * Returns {ok: boolean, error?: string}
6295
- */
6296
- async testAPIConnection() {
6297
- try {
6298
- const health = await this.healthChecker.checkHealth();
6299
- if (health.checks.api) {
6300
- return { ok: true };
6301
- } else {
6302
- return {
6303
- ok: false,
6304
- error: "API health check failed - check API key and network connection"
6305
- };
6306
- }
6307
- } catch (error) {
6308
- return {
6309
- ok: false,
6310
- error: error.message || "Unknown error"
6311
- };
6312
- }
6313
- }
6314
6340
  };
6315
6341
 
6316
6342
  // src/utils/shutdown.ts
6317
- import * as readline from "readline";
6318
6343
  function gracefulShutdown(server) {
6319
6344
  let isShuttingDown = false;
6320
6345
  const shutdown = /* @__PURE__ */ __name(async (signal) => {
@@ -6342,13 +6367,15 @@ function gracefulShutdown(server) {
6342
6367
  process.on("SIGTERM", () => shutdown("SIGTERM"));
6343
6368
  process.on("SIGINT", () => shutdown("SIGINT"));
6344
6369
  process.on("SIGHUP", () => shutdown("SIGHUP"));
6345
- if (process.platform === "win32") {
6346
- const rl = readline.createInterface({
6347
- input: process.stdin,
6348
- output: process.stdout
6349
- });
6350
- rl.on("SIGINT", () => {
6351
- process.emit("SIGINT");
6370
+ if (process.platform === "win32" && process.env.MCP_MODE !== "stdio") {
6371
+ import("readline").then((readline) => {
6372
+ const rl = readline.createInterface({
6373
+ input: process.stdin,
6374
+ output: process.stderr
6375
+ });
6376
+ rl.on("SIGINT", () => {
6377
+ process.emit("SIGINT");
6378
+ });
6352
6379
  });
6353
6380
  }
6354
6381
  }
@@ -6363,23 +6390,6 @@ async function main() {
6363
6390
  nodeVersion: process.version
6364
6391
  });
6365
6392
  const server = new WisewandMCPServer(config);
6366
- logger.info("Testing API connectivity...");
6367
- try {
6368
- const apiHealth = await server.testAPIConnection();
6369
- if (!apiHealth.ok) {
6370
- console.error("\u274C FATAL: Cannot connect to Wisewand API");
6371
- console.error(` Reason: ${apiHealth.error}`);
6372
- console.error(" Check your WISEWAND_API_KEY and network connection");
6373
- console.error(" Get your API key from: https://app.wisewand.ai/api");
6374
- process.exit(1);
6375
- }
6376
- logger.info("\u2713 API connectivity verified");
6377
- } catch (error) {
6378
- console.error("\u274C FATAL: Failed to validate API connection");
6379
- console.error(` Error: ${error.message}`);
6380
- console.error(" Check your WISEWAND_API_KEY and network connection");
6381
- process.exit(1);
6382
- }
6383
6393
  const transport = new StdioServerTransport();
6384
6394
  await server.connect(transport);
6385
6395
  logger.info("Wisewand MCP Server started successfully", {
@@ -6396,11 +6406,9 @@ async function main() {
6396
6406
  __name(main, "main");
6397
6407
  process.on("uncaughtException", (error) => {
6398
6408
  logCriticalError("Uncaught Exception", error);
6399
- process.exit(1);
6400
6409
  });
6401
6410
  process.on("unhandledRejection", (reason) => {
6402
6411
  logCriticalError("Unhandled Rejection", reason);
6403
- process.exit(1);
6404
6412
  });
6405
6413
  main();
6406
6414
  export {