fix(SEC-API-28): Replace MCP console.error with NestJS Logger
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful

Replace all console.error calls in MCP services with NestJS Logger
instances for consistent structured logging in production.

- mcp-hub.service.ts: Add Logger instance, replace console.error in
  onModuleDestroy cleanup
- stdio-transport.ts: Add Logger instance, replace console.error for
  stderr output (as warn) and JSON parse failures (as error)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Jason Woltje
2026-02-06 15:11:41 -06:00
parent 2e11931ded
commit 08d077605a
2 changed files with 7 additions and 4 deletions

View File

@@ -1,4 +1,4 @@
import { Injectable, OnModuleDestroy } from "@nestjs/common"; import { Injectable, Logger, OnModuleDestroy } from "@nestjs/common";
import { StdioTransport } from "./stdio-transport"; import { StdioTransport } from "./stdio-transport";
import { ToolRegistryService } from "./tool-registry.service"; import { ToolRegistryService } from "./tool-registry.service";
import type { McpServer, McpServerConfig, McpRequest, McpResponse } from "./interfaces"; import type { McpServer, McpServerConfig, McpRequest, McpResponse } from "./interfaces";
@@ -16,6 +16,7 @@ interface McpServerWithTransport extends McpServer {
*/ */
@Injectable() @Injectable()
export class McpHubService implements OnModuleDestroy { export class McpHubService implements OnModuleDestroy {
private readonly logger = new Logger(McpHubService.name);
private servers = new Map<string, McpServerWithTransport>(); private servers = new Map<string, McpServerWithTransport>();
constructor(private readonly toolRegistry: ToolRegistryService) {} constructor(private readonly toolRegistry: ToolRegistryService) {}
@@ -161,7 +162,7 @@ export class McpHubService implements OnModuleDestroy {
async onModuleDestroy(): Promise<void> { async onModuleDestroy(): Promise<void> {
const stopPromises = Array.from(this.servers.keys()).map((serverId) => const stopPromises = Array.from(this.servers.keys()).map((serverId) =>
this.stopServer(serverId).catch((error: unknown) => { this.stopServer(serverId).catch((error: unknown) => {
console.error(`Failed to stop server ${serverId}:`, error); this.logger.error(`Failed to stop server ${serverId}:`, error);
}) })
); );

View File

@@ -1,4 +1,5 @@
import { spawn, type ChildProcess } from "node:child_process"; import { spawn, type ChildProcess } from "node:child_process";
import { Logger } from "@nestjs/common";
import type { McpRequest, McpResponse } from "./interfaces"; import type { McpRequest, McpResponse } from "./interfaces";
/** /**
@@ -6,6 +7,7 @@ import type { McpRequest, McpResponse } from "./interfaces";
* Spawns a child process and communicates via stdin/stdout using JSON-RPC 2.0 * Spawns a child process and communicates via stdin/stdout using JSON-RPC 2.0
*/ */
export class StdioTransport { export class StdioTransport {
private readonly logger = new Logger(StdioTransport.name);
private process?: ChildProcess; private process?: ChildProcess;
private pendingRequests = new Map< private pendingRequests = new Map<
string | number, string | number,
@@ -39,7 +41,7 @@ export class StdioTransport {
}); });
this.process.stderr?.on("data", (data: Buffer) => { this.process.stderr?.on("data", (data: Buffer) => {
console.error(`MCP stderr: ${data.toString()}`); this.logger.warn(`MCP stderr: ${data.toString()}`);
}); });
this.process.on("error", (error) => { this.process.on("error", (error) => {
@@ -130,7 +132,7 @@ export class StdioTransport {
const response = JSON.parse(message) as McpResponse; const response = JSON.parse(message) as McpResponse;
this.handleResponse(response); this.handleResponse(response);
} catch (error) { } catch (error) {
console.error("Failed to parse MCP response:", error); this.logger.error("Failed to parse MCP response:", error);
} }
} }
} }